From 35d4956d2142917d22e2db23c2234df0c57a6093 Mon Sep 17 00:00:00 2001 From: Simon Oberhammer Date: Mon, 13 Nov 2023 08:25:18 +0100 Subject: [PATCH 1/5] new seekbar option to prevent label overlap; if the label is corrected by this option the arrow below the label is hidden --- .../skin-modern/components/_seekbarlabel.scss | 9 +++++++ src/ts/components/seekbar.ts | 26 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/scss/skin-modern/components/_seekbarlabel.scss b/src/scss/skin-modern/components/_seekbarlabel.scss index f76c8f1d7..7067771bb 100644 --- a/src/scss/skin-modern/components/_seekbarlabel.scss +++ b/src/scss/skin-modern/components/_seekbarlabel.scss @@ -71,4 +71,13 @@ } } } + // disable position arrow if seekbar label was + // moved due to overflow + &[style*="transform"] { + .#{$prefix}-seekbar-label-inner { + &::after { + content: unset; + } + } + } } diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index e6494691f..ef7271179 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -52,6 +52,11 @@ export interface SeekBarConfig extends ComponentConfig { * Used to enable/disable seek preview */ enableSeekPreview?: boolean; + + /** + * Prevent overflow of seekpreview + */ + preventSeekPreviewOverflow?: boolean; } /** @@ -134,6 +139,8 @@ export class SeekBar extends Component { onSeeked: new EventDispatcher(), }; + private uimanager: UIInstanceManager; + constructor(config: SeekBarConfig = {}) { super(config); @@ -151,6 +158,7 @@ export class SeekBar extends Component { tabIndex: 0, snappingRange: 1, enableSeekPreview: true, + preventSeekPreviewOverflow: false }, this.config); this.label = this.config.label; @@ -204,7 +212,7 @@ export class SeekBar extends Component { configure(player: PlayerAPI, uimanager: UIInstanceManager, configureSeek: boolean = true): void { super.configure(player, uimanager); - + this.uimanager = uimanager; this.player = player; // Apply scaling transform to the backdrop bar to have all bars rendered similarly @@ -1016,7 +1024,23 @@ export class SeekBar extends Component { if (this.label) { this.label.getDomElement().css({ 'left': seekPositionPercentage + '%', + 'transform': null }); + if (this.config.preventSeekPreviewOverflow) { + const uiBounding = this.uimanager.getUI().getDomElement().get(0).getBoundingClientRect(); + const labelBounding = this.label.getDomElement().get(0).getBoundingClientRect(); + let preventOverflowOffset = 0; + if ((labelBounding.right - labelBounding.width/2 ) > uiBounding.right) { + preventOverflowOffset = -(labelBounding.width/2); + } else if ((labelBounding.left - labelBounding.width/2) < uiBounding.left) { + preventOverflowOffset = +(labelBounding.width/2); + } + if (preventOverflowOffset) { + this.label.getDomElement().css({ + transform: `translateX(${preventOverflowOffset}px)` + }) + } + } } this.seekBarEvents.onSeekPreview.dispatch(this, { From ecb8ce50774308ce02c17c85592bf36dba25688a Mon Sep 17 00:00:00 2001 From: Simon Oberhammer Date: Mon, 13 Nov 2023 08:31:25 +0100 Subject: [PATCH 2/5] fix lint-ts complaints --- src/ts/components/seekbar.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index ef7271179..0c7d86245 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -158,7 +158,7 @@ export class SeekBar extends Component { tabIndex: 0, snappingRange: 1, enableSeekPreview: true, - preventSeekPreviewOverflow: false + preventSeekPreviewOverflow: false, }, this.config); this.label = this.config.label; @@ -1024,21 +1024,21 @@ export class SeekBar extends Component { if (this.label) { this.label.getDomElement().css({ 'left': seekPositionPercentage + '%', - 'transform': null + 'transform': null, }); if (this.config.preventSeekPreviewOverflow) { const uiBounding = this.uimanager.getUI().getDomElement().get(0).getBoundingClientRect(); const labelBounding = this.label.getDomElement().get(0).getBoundingClientRect(); let preventOverflowOffset = 0; - if ((labelBounding.right - labelBounding.width/2 ) > uiBounding.right) { - preventOverflowOffset = -(labelBounding.width/2); - } else if ((labelBounding.left - labelBounding.width/2) < uiBounding.left) { - preventOverflowOffset = +(labelBounding.width/2); + if ((labelBounding.right - labelBounding.width / 2 ) > uiBounding.right) { + preventOverflowOffset = -(labelBounding.width / 2); + } else if ((labelBounding.left - labelBounding.width / 2) < uiBounding.left) { + preventOverflowOffset = +(labelBounding.width / 2); } if (preventOverflowOffset) { this.label.getDomElement().css({ - transform: `translateX(${preventOverflowOffset}px)` - }) + transform: `translateX(${preventOverflowOffset}px)`, + }); } } } From 913d3f05a88516c300b4542a7c286b60f03f1faa Mon Sep 17 00:00:00 2001 From: Simon Oberhammer Date: Wed, 28 Feb 2024 13:07:32 +0100 Subject: [PATCH 3/5] keep thumbnail at edge of container (with a bit of margin) for less jumpy behavior; move the arrow too --- .../skin-modern/components/_seekbarlabel.scss | 2 +- src/ts/components/seekbar.ts | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/scss/skin-modern/components/_seekbarlabel.scss b/src/scss/skin-modern/components/_seekbarlabel.scss index 7067771bb..716cd5118 100644 --- a/src/scss/skin-modern/components/_seekbarlabel.scss +++ b/src/scss/skin-modern/components/_seekbarlabel.scss @@ -76,7 +76,7 @@ &[style*="transform"] { .#{$prefix}-seekbar-label-inner { &::after { - content: unset; + transform: translateX(calc(1px * var(--bmpui-seekbar-label-overflow-offset))); } } } diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index 0c7d86245..e17ef81e2 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -1022,23 +1022,28 @@ export class SeekBar extends Component { } if (this.label) { - this.label.getDomElement().css({ + const labelDomElement = this.label.getDomElement(); + labelDomElement.css({ 'left': seekPositionPercentage + '%', 'transform': null, }); if (this.config.preventSeekPreviewOverflow) { + const overflowMargin = 5; const uiBounding = this.uimanager.getUI().getDomElement().get(0).getBoundingClientRect(); - const labelBounding = this.label.getDomElement().get(0).getBoundingClientRect(); + const labelBounding = labelDomElement.get(0).getBoundingClientRect(); + const labelRight = (labelBounding.right - labelBounding.width / 2 ); + const labelLeft = (labelBounding.left - labelBounding.width / 2); let preventOverflowOffset = 0; - if ((labelBounding.right - labelBounding.width / 2 ) > uiBounding.right) { - preventOverflowOffset = -(labelBounding.width / 2); - } else if ((labelBounding.left - labelBounding.width / 2) < uiBounding.left) { - preventOverflowOffset = +(labelBounding.width / 2); + if (labelRight + overflowMargin > uiBounding.right) { + preventOverflowOffset = labelRight - uiBounding.right + overflowMargin; + } else if (labelLeft - overflowMargin < uiBounding.left) { + preventOverflowOffset = labelLeft - uiBounding.left - overflowMargin; } if (preventOverflowOffset) { - this.label.getDomElement().css({ - transform: `translateX(${preventOverflowOffset}px)`, + labelDomElement.css({ + transform: `translateX(${-preventOverflowOffset}px)` }); + labelDomElement.get(0).style.setProperty(`--${this.prefixCss('seekbar-label-overflow-offset')}`, String(preventOverflowOffset)); } } } From e7f1467fbf80042f1eefb74f55398528e200a3b5 Mon Sep 17 00:00:00 2001 From: Simon Oberhammer Date: Wed, 28 Feb 2024 13:08:04 +0100 Subject: [PATCH 4/5] lint complaints; doc --- src/scss/skin-modern/components/_seekbarlabel.scss | 6 +++--- src/ts/components/seekbar.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scss/skin-modern/components/_seekbarlabel.scss b/src/scss/skin-modern/components/_seekbarlabel.scss index 716cd5118..a8d54690e 100644 --- a/src/scss/skin-modern/components/_seekbarlabel.scss +++ b/src/scss/skin-modern/components/_seekbarlabel.scss @@ -71,9 +71,9 @@ } } } - // disable position arrow if seekbar label was - // moved due to overflow - &[style*="transform"] { + + // move arrow if the seekbar label was offset too + &[style*='transform'] { .#{$prefix}-seekbar-label-inner { &::after { transform: translateX(calc(1px * var(--bmpui-seekbar-label-overflow-offset))); diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index e17ef81e2..5d6e7183c 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -1041,7 +1041,7 @@ export class SeekBar extends Component { } if (preventOverflowOffset) { labelDomElement.css({ - transform: `translateX(${-preventOverflowOffset}px)` + transform: `translateX(${-preventOverflowOffset}px)`, }); labelDomElement.get(0).style.setProperty(`--${this.prefixCss('seekbar-label-overflow-offset')}`, String(preventOverflowOffset)); } From e193cbe026ddc5bd7498c65b728c805162e2903e Mon Sep 17 00:00:00 2001 From: Simon Oberhammer Date: Mon, 9 Sep 2024 10:06:33 +0200 Subject: [PATCH 5/5] throttle updates of seekbar label --- src/ts/components/seekbar.ts | 53 ++++++++++++++++++++---------------- src/ts/throttle.ts | 17 ++++++++++++ 2 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 src/ts/throttle.ts diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index 5d6e7183c..2c97cd29a 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -16,6 +16,7 @@ import { i18n } from '../localization/i18n'; import { BrowserUtils } from '../browserutils'; import { TimelineMarkersHandler } from './timelinemarkershandler'; import { getMinBufferLevel } from './seekbarbufferlevel'; +import {throttle} from '../throttle'; /** * Configuration interface for the {@link SeekBar} component. @@ -999,6 +1000,33 @@ export class SeekBar extends Component { this.seekBarEvents.onSeek.dispatch(this); } + protected updateLabelPosition = throttle((seekPositionPercentage: number) => { + const labelDomElement = this.label.getDomElement(); + labelDomElement.css({ + 'left': seekPositionPercentage + '%', + 'transform': null, + }); + if (this.config.preventSeekPreviewOverflow) { + const overflowMargin = 5; + const uiBounding = this.uimanager.getUI().getDomElement().get(0).getBoundingClientRect(); + const labelBounding = labelDomElement.get(0).getBoundingClientRect(); + const labelRight = (labelBounding.right - labelBounding.width / 2 ); + const labelLeft = (labelBounding.left - labelBounding.width / 2); + let preventOverflowOffset = 0; + if (labelRight + overflowMargin > uiBounding.right) { + preventOverflowOffset = labelRight - uiBounding.right + overflowMargin; + } else if (labelLeft - overflowMargin < uiBounding.left) { + preventOverflowOffset = labelLeft - uiBounding.left - overflowMargin; + } + if (preventOverflowOffset) { + labelDomElement.css({ + transform: `translateX(${-preventOverflowOffset}px)`, + }); + labelDomElement.get(0).style.setProperty(`--${this.prefixCss('seekbar-label-overflow-offset')}`, String(preventOverflowOffset)); + } + } + }, 50) + protected onSeekPreviewEvent(percentage: number, scrubbing: boolean) { let snappedMarker = this.timelineMarkersHandler && this.timelineMarkersHandler.getMarkerAtPosition(percentage); @@ -1022,30 +1050,7 @@ export class SeekBar extends Component { } if (this.label) { - const labelDomElement = this.label.getDomElement(); - labelDomElement.css({ - 'left': seekPositionPercentage + '%', - 'transform': null, - }); - if (this.config.preventSeekPreviewOverflow) { - const overflowMargin = 5; - const uiBounding = this.uimanager.getUI().getDomElement().get(0).getBoundingClientRect(); - const labelBounding = labelDomElement.get(0).getBoundingClientRect(); - const labelRight = (labelBounding.right - labelBounding.width / 2 ); - const labelLeft = (labelBounding.left - labelBounding.width / 2); - let preventOverflowOffset = 0; - if (labelRight + overflowMargin > uiBounding.right) { - preventOverflowOffset = labelRight - uiBounding.right + overflowMargin; - } else if (labelLeft - overflowMargin < uiBounding.left) { - preventOverflowOffset = labelLeft - uiBounding.left - overflowMargin; - } - if (preventOverflowOffset) { - labelDomElement.css({ - transform: `translateX(${-preventOverflowOffset}px)`, - }); - labelDomElement.get(0).style.setProperty(`--${this.prefixCss('seekbar-label-overflow-offset')}`, String(preventOverflowOffset)); - } - } + this.updateLabelPosition(seekPositionPercentage); } this.seekBarEvents.onSeekPreview.dispatch(this, { diff --git a/src/ts/throttle.ts b/src/ts/throttle.ts new file mode 100644 index 000000000..9c80702d1 --- /dev/null +++ b/src/ts/throttle.ts @@ -0,0 +1,17 @@ +/** + * Returns a new function which will invocate the original no faster + * then every rateMs milliseconds. + */ +export function throttle(fn: Function, rateMs: number) { + let timerFlag : null | ReturnType = null; + + return (...args: unknown[]) => { + if (timerFlag === null) { + fn(...args); + timerFlag = setTimeout(() => { + timerFlag = null; + }, rateMs); + } + }; +} +