diff --git a/CHANGES.md b/CHANGES.md index b264f8e2e..a3c512a63 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,11 @@ wavesurfer.js changelog ======================= +3.2.0 (unreleased) +------------------ + +- New `barRadius` option to create waveforms with rounded bars (#953) + 3.1.0 (26.09.2019) ------------------ diff --git a/example/rounded-bars/index.html b/example/rounded-bars/index.html new file mode 100644 index 000000000..0b1453ca4 --- /dev/null +++ b/example/rounded-bars/index.html @@ -0,0 +1,118 @@ + + + + + + wavesurfer.js | Waveform using rounded bars + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

Rounded bars Example

+
+ +
+
+ +
+ +
+
+
+ +
+
+
+
+ +
+

Rounded bars example

+
+

Draws a waveform with rounded bars.

+ +

+

var wavesurfer = WaveSurfer.create({
+    container: document.querySelector('#waveform'),
+    waveColor: '#D9DCFF',
+    progressColor: '#4353FF',
+    cursorColor: '#4353FF',
+    barWidth: 3,
+    barRadius: 3,
+    cursorWidth: 1,
+    height: 200,
+    barGap: 3
+});
+
+

+
+ + +
+ +
+
+ Fork me on GitHub +
+
+ + + + + diff --git a/example/rounded-bars/main.js b/example/rounded-bars/main.js new file mode 100644 index 000000000..f05f78766 --- /dev/null +++ b/example/rounded-bars/main.js @@ -0,0 +1,31 @@ +'use strict'; + +// Create an instance +var wavesurfer = {}; + +// Init & load audio file +document.addEventListener('DOMContentLoaded', function() { + wavesurfer = WaveSurfer.create({ + container: document.querySelector('#waveform'), + waveColor: '#D9DCFF', + progressColor: '#4353FF', + cursorColor: '#4353FF', + barWidth: 3, + barRadius: 3, + cursorWidth: 1, + height: 200, + barGap: 3 + }); + + wavesurfer.on('error', function(e) { + console.warn(e); + }); + + // Load audio from URL + wavesurfer.load('../media/demo.wav'); + + // Play button + var button = document.querySelector('[data-action="play"]'); + + button.addEventListener('click', wavesurfer.playPause.bind(wavesurfer)); +}); diff --git a/src/drawer.canvasentry.js b/src/drawer.canvasentry.js index cde80794d..5b7614d76 100644 --- a/src/drawer.canvasentry.js +++ b/src/drawer.canvasentry.js @@ -153,12 +153,20 @@ export default class CanvasEntry { * @param {number} y Y start position * @param {number} width Width of the rectangle * @param {number} height Height of the rectangle + * @param {number} radius Radius of the rectangle */ - fillRects(x, y, width, height) { - this.fillRectToContext(this.waveCtx, x, y, width, height); + fillRects(x, y, width, height, radius) { + this.fillRectToContext(this.waveCtx, x, y, width, height, radius); if (this.hasProgressCanvas) { - this.fillRectToContext(this.progressCtx, x, y, width, height); + this.fillRectToContext( + this.progressCtx, + x, + y, + width, + height, + radius + ); } } @@ -171,12 +179,61 @@ export default class CanvasEntry { * @param {number} y Y start position * @param {number} width Width of the rectangle * @param {number} height Height of the rectangle + * @param {number} radius Radius of the rectangle */ - fillRectToContext(ctx, x, y, width, height) { + fillRectToContext(ctx, x, y, width, height, radius) { if (!ctx) { return; } - ctx.fillRect(x, y, width, height); + + if (radius) { + this.drawRoundedRect(ctx, x, y, width, height, radius); + } else { + ctx.fillRect(x, y, width, height); + } + } + + /** + * Draw a rounded rectangle on Canvas + * + * @private + * @param {CanvasRenderingContext2D} ctx Canvas context + * @param {number} x X-position of the rectangle + * @param {number} y Y-position of the rectangle + * @param {number} width Width of the rectangle + * @param {number} height Height of the rectangle + * @param {number} radius Radius of the rectangle + * + * @return {void} + * @example drawRoundedRect(ctx, 50, 50, 5, 10, 3) + */ + drawRoundedRect(ctx, x, y, width, height, radius) { + if (height === 0) { + return; + } + // peaks are float values from -1 to 1. Use absolute height values in + // order to correctly calculate rounded rectangle coordinates + if (height < 0) { + height *= -1; + y -= height; + } + ctx.beginPath(); + ctx.moveTo(x + radius, y); + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo( + x + width, + y + height, + x + width - radius, + y + height + ); + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + ctx.fill(); } /** diff --git a/src/drawer.multicanvas.js b/src/drawer.multicanvas.js index b344d01ea..b42e84da8 100644 --- a/src/drawer.multicanvas.js +++ b/src/drawer.multicanvas.js @@ -74,6 +74,14 @@ export default class MultiCanvas extends Drawer { * @type {number} */ this.overlap = 2 * Math.ceil(params.pixelRatio / 2); + + /** + * The radius of the wave bars. Makes bars rounded + * + * @private + * @type {number} + */ + this.barRadius = params.barRadius || 0; } /** @@ -297,7 +305,8 @@ export default class MultiCanvas extends Drawer { i + this.halfPixel, halfH - h + offsetY, bar + this.halfPixel, - h * 2 + h * 2, + this.barRadius ); } } @@ -346,7 +355,8 @@ export default class MultiCanvas extends Drawer { 0, halfH + offsetY - this.halfPixel, this.width, - this.halfPixel + this.halfPixel, + this.barRadius ); } ); @@ -379,8 +389,9 @@ export default class MultiCanvas extends Drawer { * @param {number} y Y-position of the rectangle * @param {number} width Width of the rectangle * @param {number} height Height of the rectangle + * @param {number} radius Radius of the rectangle */ - fillRect(x, y, width, height) { + fillRect(x, y, width, height, radius) { const startCanvas = Math.floor(x / this.maxCanvasWidth); const endCanvas = Math.min( Math.ceil((x + width) / this.maxCanvasWidth) + 1, @@ -408,7 +419,8 @@ export default class MultiCanvas extends Drawer { intersection.x1 - leftOffset, intersection.y1, intersection.x2 - intersection.x1, - intersection.y2 - intersection.y1 + intersection.y2 - intersection.y1, + radius ); } } diff --git a/src/wavesurfer.js b/src/wavesurfer.js index 6f32387ef..13d3f4159 100755 --- a/src/wavesurfer.js +++ b/src/wavesurfer.js @@ -36,6 +36,7 @@ import PeakCache from './peakcache'; * @property {string} backgroundColor=null Change background color of the * waveform container. * @property {number} barHeight=1 The height of the wave bars. + * @property {number} barRadius=0 The radius of the wave bars. Makes bars rounded * @property {number} barGap=null The optional spacing between bars of the wave, * if not provided will be calculated in legacy format. * @property {number} barWidth=null Draw the waveform using bars. @@ -213,6 +214,7 @@ export default class WaveSurfer extends util.Observer { backend: 'WebAudio', backgroundColor: null, barHeight: 1, + barRadius: 0, barGap: null, container: null, cursorColor: '#333',