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

Refactor: [Regions] virtualize DOM elements #3712

Merged
merged 3 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 19 additions & 17 deletions cypress/e2e/regions.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,26 @@ describe('WaveSurfer Regions plugin tests', () => {

expect(region.start).to.equal(3)

// Drag the region
const pointerDownEvent = new PointerEvent('pointerdown', {
clientX: 90,
clientY: 1,
})
const pointerMoveEvent = new PointerEvent('pointermove', {
clientX: 200,
clientY: 10,
})
const pointerUpEvent = new PointerEvent('pointerup', {
clientX: 200,
clientY: 10,
})
region.element.dispatchEvent(pointerDownEvent)
win.document.dispatchEvent(pointerMoveEvent)
win.document.dispatchEvent(pointerUpEvent)
return cy.wait(10).then(() => {
// Drag the region
const pointerDownEvent = new PointerEvent('pointerdown', {
clientX: 90,
clientY: 1,
})
const pointerMoveEvent = new PointerEvent('pointermove', {
clientX: 200,
clientY: 10,
})
const pointerUpEvent = new PointerEvent('pointerup', {
clientX: 200,
clientY: 10,
})
region.element.dispatchEvent(pointerDownEvent)
win.document.dispatchEvent(pointerMoveEvent)
win.document.dispatchEvent(pointerUpEvent)

expect(region.start).to.be.greaterThan(3)
expect(region.start).to.be.greaterThan(3)
})
})
})

Expand Down
31 changes: 30 additions & 1 deletion src/plugins/regions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,37 @@ class RegionsPlugin extends BasePlugin<RegionsPluginEvents, RegionsPluginOptions
}
}

private virtualAppend(region: Region, container: HTMLElement, element: HTMLElement) {
const renderIfVisible = () => {
if (!this.wavesurfer) return
const clientWidth = this.wavesurfer.getWidth()
const scrollLeft = this.wavesurfer.getScroll()
const scrollWidth = container.clientWidth
const duration = this.wavesurfer.getDuration()
const start = Math.round((region.start / duration) * scrollWidth)
const width = Math.round(((region.end - region.start) / duration) * scrollWidth) || 1

// Check if the region is between the scrollLeft and scrollLeft + clientWidth
const isVisible = start + width > scrollLeft && start < scrollLeft + clientWidth

if (isVisible) {
container.appendChild(element)
} else {
element.remove()
}
}

setTimeout(() => {
if (!this.wavesurfer) return
renderIfVisible()

const unsubscribe = this.wavesurfer.on('scroll', renderIfVisible)
this.subscriptions.push(region.once('remove', unsubscribe), unsubscribe)
}, 0)
}

private saveRegion(region: Region) {
this.regionsContainer.appendChild(region.element)
this.virtualAppend(region, this.regionsContainer, region.element)
this.avoidOverlapping(region)
this.regions.push(region)

Expand Down
27 changes: 25 additions & 2 deletions src/plugins/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,28 @@ class TimelinePlugin extends BasePlugin<TimelinePluginEvents, TimelinePluginOpti
return 2
}

private virtualAppend(start: number, container: HTMLElement, element: HTMLElement) {
const renderIfVisible = () => {
if (!this.wavesurfer) return
const clientWidth = this.wavesurfer.getWidth()
const scrollLeft = this.wavesurfer.getScroll()
const width = element.clientWidth
const isVisible = start + width > scrollLeft && start < scrollLeft + clientWidth

if (isVisible) {
container.appendChild(element)
} else {
element.remove()
}
}

setTimeout(() => {
if (!this.wavesurfer) return
renderIfVisible()
this.subscriptions.push(this.wavesurfer.on('scroll', renderIfVisible))
}, 0)
}

private initTimeline() {
const duration = this.wavesurfer?.getDuration() ?? this.options.duration ?? 0
const pxPerSec = this.timelineWrapper.scrollWidth / duration
Expand Down Expand Up @@ -217,8 +239,9 @@ class TimelinePlugin extends BasePlugin<TimelinePluginEvents, TimelinePluginOpti
const mode = isPrimary ? 'primary' : isSecondary ? 'secondary' : 'tick'
notch.setAttribute('part', `timeline-notch timeline-notch-${mode}`)

notch.style.left = `${i * pxPerSec}px`
timeline.appendChild(notch)
const offset = i * pxPerSec
notch.style.left = `${offset}px`
this.virtualAppend(offset, timeline, notch)
}

this.timelineWrapper.innerHTML = ''
Expand Down
4 changes: 4 additions & 0 deletions src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ class Renderer extends EventEmitter<RendererEvents> {
return this.wrapper
}

getWidth(): number {
return this.scrollContainer.clientWidth
}

getScroll(): number {
return this.scrollContainer.scrollLeft
}
Expand Down
5 changes: 5 additions & 0 deletions src/wavesurfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,11 @@ class WaveSurfer extends Player<WaveSurferEvents> {
return this.renderer.getWrapper()
}

/** For plugins only: get the scroll container client width */
public getWidth(): number {
return this.renderer.getWidth()
}

/** Get the current scroll position in pixels */
public getScroll(): number {
return this.renderer.getScroll()
Expand Down
Loading