Wavesurfer.js: Custom Renderer code example

Created on 1 Sep 2017  Â·  7Comments  Â·  Source: katspaugh/wavesurfer.js

Hey,

I am interested in creating a custom renderer. Can you please provide a short example of how to do that?

Thx for your help,
Rakesh

enhancement question

Most helpful comment

The easiest way would be to extend upon the MultiCanvas renderer and define custom methods for the parts you want to customise (overwriting the inherited ones) – Then you inject it into wavesurfer by passing the class as the renderer parameter.

Note that you need a code transpiler for this to work (like babel). Please refer to the documentation (https://wavesurfer-js.org/doc/) and to the code in drawer.js and drawer.multicanvas.js to find out what you can overwrite & how it all fits together.

Custom renderer:

import MultiCanvas from 'wavesurfer.js/src/drawer.multicanvas.js';

export default class MyCustomRenderer extends MultiCanvas {
  constructor(container, params) {
        // call the constructor of MultiCanvas:
        super(container, params);
        // ... custom instantiation stuff goes here
        // (you can overwrite properties etc.)
  }

  // overwrite methods, for example:
  createWrapper() {
    // overwrite the function from drawer.js,
    // f.x. your wrapper should have some special elements
  }

  // overwrite another method
  drawBars(peaks, channelIndex, start, end) {
    // ... overwrite the way bars are drawn from multicanvas.drawer.js
  }
}

Then initialise Wavesurfer with your custom renderer:

import WaveSurfer from 'wavesurfer.js';
import MyCustomRenderer from './path/to/renderer.js';

const ws = WaveSurfer.create({
  renderer: MyCustomRenderer
  // ...
});

All 7 comments

The easiest way would be to extend upon the MultiCanvas renderer and define custom methods for the parts you want to customise (overwriting the inherited ones) – Then you inject it into wavesurfer by passing the class as the renderer parameter.

Note that you need a code transpiler for this to work (like babel). Please refer to the documentation (https://wavesurfer-js.org/doc/) and to the code in drawer.js and drawer.multicanvas.js to find out what you can overwrite & how it all fits together.

Custom renderer:

import MultiCanvas from 'wavesurfer.js/src/drawer.multicanvas.js';

export default class MyCustomRenderer extends MultiCanvas {
  constructor(container, params) {
        // call the constructor of MultiCanvas:
        super(container, params);
        // ... custom instantiation stuff goes here
        // (you can overwrite properties etc.)
  }

  // overwrite methods, for example:
  createWrapper() {
    // overwrite the function from drawer.js,
    // f.x. your wrapper should have some special elements
  }

  // overwrite another method
  drawBars(peaks, channelIndex, start, end) {
    // ... overwrite the way bars are drawn from multicanvas.drawer.js
  }
}

Then initialise Wavesurfer with your custom renderer:

import WaveSurfer from 'wavesurfer.js';
import MyCustomRenderer from './path/to/renderer.js';

const ws = WaveSurfer.create({
  renderer: MyCustomRenderer
  // ...
});

Thx a lot. I actually did it the same way but now I get the following Error:

TypeError: Class constructor MultiCanvas cannot be invoked without 'new'

Any ideas?

SOLVED

Hi, @GitHubRakeshSharma How did you solve the
TypeError: Class constructor MultiCanvas cannot be invoked without 'new'
issue?

Hi @GitHubRakeshSharma , I have the same problem, how did you solve it?

Hi. Sorry to comment on a closed issue, but this is the one that I found when searching for how to implement a custom renderer, so thought it would be the most useful place to put it.

I'm not a full-time javascript developer, and so didn't particularly want to go down the route of having to install transpilers, etc., but just wanted to make some small changes to the rendering. I've therefore just overridden the drawBars function, as seen in this fiddle.

The code is basically a function which changes the way the bars are drawn, which is based on the current source code lifted from 'drawer.multicanvas.js':

function customDrawBars (wavesurfer, peaks, channelIndex, start, end) {

    return wavesurfer.drawer.prepareDraw(peaks, channelIndex, start, end, function (_ref) {
            var absmax = _ref.absmax,
                hasMinVals = _ref.hasMinVals,
                height = _ref.height,
                offsetY = _ref.offsetY,
                halfH = _ref.halfH,
                peaks = _ref.peaks;

            // if drawBars was called within ws.empty we don't pass a start and
            // don't want anything to happen
            if (start === undefined) {
                return;
            } // Skip every other value if there are negatives.


            var peakIndexScale = hasMinVals ? 2 : 1;
            var length = peaks.length / peakIndexScale;
            var bar = wavesurfer.params.barWidth * wavesurfer.params.pixelRatio;
            var gap = wavesurfer.params.barGap === null ? Math.max(wavesurfer.params.pixelRatio, ~~(bar / 2)) : Math.max(wavesurfer.params.pixelRatio, wavesurfer.params.barGap * wavesurfer.params.pixelRatio);
            var step = bar + gap;
            var scale = length / wavesurfer.drawer.width;
            var first = start;
            var last = end;
            var i;

            var topRatio = 0.7;
            var bottomRatio = 0.25;
            var topBottomGap = 1;


            for (i = first; i < last; i += step) {
                var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0;
                var h = Math.abs(Math.round(peak / absmax * height));

                // Upper bar
                var fx = i + wavesurfer.drawer.halfPixel;
                var fy = (height * topRatio) + offsetY - (h * topRatio);
                var fwidth = bar + wavesurfer.drawer.halfPixel;
                var fheight = h * topRatio;

                wavesurfer.drawer.fillRect(fx, fy, fwidth, fheight);

                // Recalculate for lower bar
                fy = (height * topRatio) + offsetY + topBottomGap;
                fheight = h * bottomRatio;

                wavesurfer.drawer.fillRect(fx, fy, fwidth, fheight);
            }
    });
}

and then a few lines to override the existing function:

wavesurfer.drawer.drawBars = function (peaks, channelIndex, start, end) {
    return customDrawBars(wavesurfer, peaks, channelIndex, start, end);
};

Can anyone comment on whether this is a bad idea or not?

Anyone managed to solve this one?
TypeError: Class constructor MultiCanvas cannot be invoked without 'new'

This is because of transpliation...
https://stackoverflow.com/questions/51860043/javascript-es6-typeerror-class-constructor-client-cannot-be-invoked-without-ne/51860850
If turn it off, you can pass your custom renderer to ws in your app.
Did anybody knows how to correctly config babel in this case?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CramericaIndustries picture CramericaIndustries  Â·  4Comments

sebhoff picture sebhoff  Â·  4Comments

ghost picture ghost  Â·  6Comments

thijstriemstra picture thijstriemstra  Â·  5Comments

Gabrielfcs picture Gabrielfcs  Â·  3Comments