Skip to content
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
56 changes: 56 additions & 0 deletions src/__tests__/renderer-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe('renderer-utils', () => {
barRadius: 3,
barIndexScale: 100 / ((4 + 2) * 10),
barSpacing: 6,
barMinHeight: 0,
})
})
})
Expand All @@ -80,6 +81,29 @@ describe('renderer-utils', () => {
}),
).toEqual({ topHeight: 0, totalHeight: 1 })
})

it('ensures total height is at least barMinHeight', () => {
expect(
calculateBarHeights({
maxTop: 0,
maxBottom: 0,
halfHeight: 20,
vScale: 1,
barMinHeight: 10,
}),
).toEqual({ topHeight: 5, totalHeight: 10 })

expect(
calculateBarHeights({
maxTop: 0,
maxBottom: 0,
halfHeight: 20,
vScale: 1,
barMinHeight: 10,
barAlign: 'top',
}),
).toEqual({ topHeight: 0, totalHeight: 10 })
})
})

describe('resolveBarYPosition', () => {
Expand Down Expand Up @@ -139,6 +163,7 @@ describe('renderer-utils', () => {
vScale: 1,
canvasHeight: 40,
barAlign: undefined,
barMinHeight: 0,
})

expect(segments).toEqual([
Expand All @@ -150,6 +175,37 @@ describe('renderer-utils', () => {
{ x: 5, y: 0, width: 1, height: 16 },
])
})

it('ensures bars are at least barMinHeight tall', () => {
const height = 40
const length = 10

const { barIndexScale, barSpacing, barWidth, halfHeight } = calculateBarRenderConfig({
width: 100,
height,
length,
options,
pixelRatio: 1,
})

const segments = calculateBarSegments({
channelData: [
new Float32Array(length).fill(0.001), // Very small values
],
barIndexScale,
barSpacing,
barWidth,
halfHeight,
vScale: 1,
canvasHeight: height / 2,
barAlign: undefined,
barMinHeight: 10,
})

expect(segments.length).toBeGreaterThan(0)
expect(segments[0].height).toBe(10)
expect(segments[0].y).toBe(15) // Centered: 20 - 10/2
})
})

describe('getRelativePointerPosition', () => {
Expand Down
21 changes: 19 additions & 2 deletions src/renderer-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function calculateBarRenderConfig({
const barWidth = options.barWidth ? options.barWidth * pixelRatio : 1
const barGap = options.barGap ? options.barGap * pixelRatio : options.barWidth ? barWidth / 2 : 0
const barRadius = options.barRadius || 0
const barMinHeight = options.barMinHeight ? options.barMinHeight * pixelRatio : 0
const spacing = barWidth + barGap || 1
const barIndexScale = length > 0 ? width / spacing / length : 0

Expand All @@ -48,6 +49,7 @@ export function calculateBarRenderConfig({
barWidth,
barGap,
barRadius,
barMinHeight,
barIndexScale,
barSpacing: spacing,
}
Expand All @@ -58,15 +60,26 @@ export function calculateBarHeights({
maxBottom,
halfHeight,
vScale,
barMinHeight = 0,
barAlign,
}: {
maxTop: number
maxBottom: number
halfHeight: number
vScale: number
barMinHeight?: number
barAlign?: WaveSurferOptions['barAlign']
}): { topHeight: number; totalHeight: number } {
const topHeight = Math.round(maxTop * halfHeight * vScale)
let topHeight = Math.round(maxTop * halfHeight * vScale)
const bottomHeight = Math.round(maxBottom * halfHeight * vScale)
const totalHeight = topHeight + bottomHeight || 1
let totalHeight = topHeight + bottomHeight || 1

if (totalHeight < barMinHeight) {
totalHeight = barMinHeight
if (!barAlign) {
topHeight = totalHeight / 2
}
}

return { topHeight, totalHeight }
}
Expand Down Expand Up @@ -98,6 +111,7 @@ export function calculateBarSegments({
vScale,
canvasHeight,
barAlign,
barMinHeight,
}: {
channelData: ChannelData
barIndexScale: number
Expand All @@ -107,6 +121,7 @@ export function calculateBarSegments({
vScale: number
canvasHeight: number
barAlign: WaveSurferOptions['barAlign']
barMinHeight: number
}): BarSegment[] {
const topChannel = channelData[0] || []
const bottomChannel = channelData[1] || topChannel
Expand All @@ -127,6 +142,8 @@ export function calculateBarSegments({
maxBottom,
halfHeight,
vScale,
barMinHeight,
barAlign,
})

const y = resolveBarYPosition({
Expand Down
3 changes: 2 additions & 1 deletion src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ class Renderer extends EventEmitter<RendererEvents> {
vScale: number,
) {
const { width, height } = ctx.canvas
const { halfHeight, barWidth, barRadius, barIndexScale, barSpacing } = utils.calculateBarRenderConfig({
const { halfHeight, barWidth, barRadius, barIndexScale, barSpacing, barMinHeight } = utils.calculateBarRenderConfig({
width,
height,
length: (channelData[0] || []).length,
Expand All @@ -371,6 +371,7 @@ class Renderer extends EventEmitter<RendererEvents> {
vScale,
canvasHeight: height,
barAlign: options.barAlign,
barMinHeight,
})

ctx.beginPath()
Expand Down
2 changes: 2 additions & 0 deletions src/wavesurfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export type WaveSurferOptions = {
barHeight?: number
/** Vertical bar alignment */
barAlign?: 'top' | 'bottom'
/** Minimum height of bars in pixels */
barMinHeight?: number
/** Minimum pixels per second of audio (i.e. the zoom level) */
minPxPerSec?: number
/** Stretch the waveform to fill the container, true by default */
Expand Down
Loading