Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show interval value on click #7064

Merged
merged 12 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions panel/dist/css/player.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.faster {
font-size: 11px;
}

.slower {
font-size: 11px;
}
29 changes: 27 additions & 2 deletions panel/models/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export class PlayerView extends WidgetView {
protected _toogle_pause: CallableFunction
protected _toggle_play: CallableFunction
protected _changing: boolean = false
protected slowerButton: HTMLButtonElement
protected fasterButton: HTMLButtonElement

override connect_signals(): void {
super.connect_signals()
Expand Down Expand Up @@ -148,61 +150,72 @@ export class PlayerView extends WidgetView {
this.buttonEl = button_div
button_div.style.cssText = "margin: 0 auto; display: flex; padding: 5px; align-items: stretch; width: 100%;"

const button_style_small = "text-align: center; min-width: 20px; flex-grow: 1; margin: 2px"
const button_style = "text-align: center; min-width: 40px; flex-grow: 2; margin: 2px"
const button_style_small = "text-align: center; min-width: 50px; flex-grow: 1; margin: 2px"
const button_style = "text-align: center; min-width: 50px; flex-grow: 2; margin: 2px"

const slower = document.createElement("button")
slower.classList.add("slower")
slower.style.cssText = button_style_small
slower.innerHTML = SVG_STRINGS.slower
slower.onclick = () => this.slower()
this.slowerButton = slower
button_div.appendChild(slower)

const first = document.createElement("button")
first.classList.add("first")
first.style.cssText = button_style
first.innerHTML = SVG_STRINGS.first
first.onclick = () => this.first_frame()
button_div.appendChild(first)

const previous = document.createElement("button")
previous.classList.add("previous")
previous.style.cssText = button_style
previous.innerHTML = SVG_STRINGS.previous
previous.onclick = () => this.previous_frame()
button_div.appendChild(previous)

const reverse = document.createElement("button")
reverse.classList.add("reverse")
reverse.style.cssText = button_style
reverse.innerHTML = SVG_STRINGS.reverse
reverse.onclick = () => this.reverse_animation()
button_div.appendChild(reverse)

const pause = document.createElement("button")
pause.classList.add("pause")
pause.style.cssText = button_style
pause.innerHTML = SVG_STRINGS.pause
pause.onclick = () => this.pause_animation()
button_div.appendChild(pause)

const play = document.createElement("button")
play.classList.add("play")
play.style.cssText = button_style
play.innerHTML = SVG_STRINGS.play
play.onclick = () => this.play_animation()
button_div.appendChild(play)

const next = document.createElement("button")
next.classList.add("next")
next.style.cssText = button_style
next.innerHTML = SVG_STRINGS.next
next.onclick = () => this.next_frame()
button_div.appendChild(next)

const last = document.createElement("button")
last.classList.add("last")
last.style.cssText = button_style
last.innerHTML = SVG_STRINGS.last
last.onclick = () => this.last_frame()
button_div.appendChild(last)

const faster = document.createElement("button")
faster.classList.add("faster")
faster.style.cssText = button_style_small
faster.innerHTML = SVG_STRINGS.faster
faster.onclick = () => this.faster()
this.fasterButton = faster
button_div.appendChild(faster)

// toggle
Expand Down Expand Up @@ -320,8 +333,17 @@ export class PlayerView extends WidgetView {
this.set_frame(this.model.end)
}

updateSpeedButton(button: HTMLButtonElement, interval: number, originalSVG: string): void {
const fps = 1000 / interval
button.innerHTML = `${fps.toFixed(1)}<br>fps`
setTimeout(() => {
button.innerHTML = originalSVG
}, this.model.preview_duration) // Show for 1.5 seconds
philippjfr marked this conversation as resolved.
Show resolved Hide resolved
}

slower(): void {
this.model.interval = Math.round(this.model.interval / 0.7)
this.updateSpeedButton(this.slowerButton, this.model.interval, SVG_STRINGS.slower)
if (this.model.direction > 0) {
this.play_animation()
} else if (this.model.direction < 0) {
Expand All @@ -331,6 +353,7 @@ export class PlayerView extends WidgetView {

faster(): void {
this.model.interval = Math.round(this.model.interval * 0.7)
this.updateSpeedButton(this.fasterButton, this.model.interval, SVG_STRINGS.faster)
if (this.model.direction > 0) {
this.play_animation()
} else if (this.model.direction < 0) {
Expand Down Expand Up @@ -431,6 +454,7 @@ export namespace Player {
loop_policy: p.Property<typeof LoopPolicy["__type__"]>
value: p.Property<any>
value_throttled: p.Property<any>
preview_duration: p.Property<number>
show_loop_controls: p.Property<boolean>
}
}
Expand Down Expand Up @@ -459,6 +483,7 @@ export class Player extends Widget {
loop_policy: [LoopPolicy, "once"],
value: [Int, 0],
value_throttled: [Int, 0],
preview_duration: [Int, 1500],
show_loop_controls: [Bool, true],
}))

Expand Down
4 changes: 4 additions & 0 deletions panel/models/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class Player(Widget):
show_loop_controls = Bool(True, help="""Whether the loop controls
radio buttons are shown""")

preview_duration = Int(1500, help="""
Duration (in milliseconds) for showing the current FPS when clicking
the slower/faster buttons, before reverting to the icon.""")

width = Override(default=400)

height = Override(default=250)
Expand Down
35 changes: 35 additions & 0 deletions panel/tests/ui/widgets/test_player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import pytest

pytest.importorskip("playwright")


from panel.tests.util import serve_component, wait_until
from panel.widgets import Player

pytestmark = pytest.mark.ui


def test_player_faster_click_shows_ms(page):
player = Player()
serve_component(page, player)

faster_element = page.locator(".faster")
faster_element.click()

wait_until(lambda: player.interval == 350)
assert faster_element.inner_text() == "2.9\nfps"

wait_until(lambda: faster_element.inner_text() == "")


def test_player_slower_click_shows_ms(page):
player = Player()
serve_component(page, player)

slower_element = page.locator(".slower")
slower_element.click()

wait_until(lambda: player.interval == 714)
assert slower_element.inner_text() == "1.4\nfps"

wait_until(lambda: slower_element.inner_text() == "")
8 changes: 8 additions & 0 deletions panel/widgets/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import param

from panel.io.resources import CDN_DIST

from ..config import config
from ..models.widgets import Player as _BkPlayer
from ..util import indexOf, isIn
Expand All @@ -31,6 +33,10 @@ class PlayerBase(Widget):
default='once', objects=['once', 'loop', 'reflect'], doc="""
Policy used when player hits last frame""")

preview_duration = param.Integer(default=1500, doc="""
ahuang11 marked this conversation as resolved.
Show resolved Hide resolved
Duration (in milliseconds) for showing the current FPS when clicking
the slower/faster buttons, before reverting to the icon.""")

show_loop_controls = param.Boolean(default=True, doc="""
Whether the loop controls radio buttons are shown""")

Expand All @@ -47,6 +53,8 @@ class PlayerBase(Widget):

_widget_type: ClassVar[type[Model]] = _BkPlayer

_stylesheets: ClassVar[list[str]] = [f"{CDN_DIST}css/player.css"]

__abstract = True

def __init__(self, **params):
Expand Down
Loading