wavesurfer.js
Version:
Interactive navigable audio visualization using Web Audio and Canvas
167 lines (140 loc) • 6.46 kB
JavaScript
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['wavesurfer'], factory);
} else {
root.WaveSurfer.Timeline = factory(root.WaveSurfer);
}
}(this, function (WaveSurfer) {
'use strict';
WaveSurfer.Timeline = {
init: function (params) {
this.params = params;
var wavesurfer = this.wavesurfer = params.wavesurfer;
if (!this.wavesurfer) {
throw Error('No WaveSurfer intance provided');
}
var drawer = this.drawer = this.wavesurfer.drawer;
this.container = 'string' == typeof params.container ?
document.querySelector(params.container) : params.container;
if (!this.container) {
throw Error('No container for WaveSurfer timeline');
}
this.width = drawer.width;
this.height = this.params.height || 20;
this.notchPercentHeight = this.params.notchPercentHeight || 90;
this.primaryColor = this.params.primaryColor || '#000';
this.secondaryColor = this.params.secondaryColor || '#c0c0c0';
this.primaryFontColor = this.params.primaryFontColor || '#000';
this.secondaryFontColor = this.params.secondaryFontColor || '#000';
this.fontFamily = this.params.fontFamily || 'Arial';
this.fontSize = this.params.fontSize || 10;
this.createWrapper();
this.createCanvas();
this.render();
wavesurfer.drawer.wrapper.onscroll = this.updateScroll.bind(this);
wavesurfer.on('redraw', this.render.bind(this));
},
createWrapper: function () {
var wsParams = this.wavesurfer.params;
this.wrapper = this.container.appendChild(
document.createElement('wave')
);
this.drawer.style(this.wrapper, {
display: 'block',
position: 'relative',
userSelect: 'none',
webkitUserSelect: 'none',
height: this.height + 'px'
});
if (wsParams.fillParent || wsParams.scrollParent) {
this.drawer.style(this.wrapper, {
width: '100%',
overflowX: 'hidden',
overflowY: 'hidden'
});
}
var my = this;
this.wrapper.addEventListener('click', function (e) {
e.preventDefault();
var relX = 'offsetX' in e ? e.offsetX : e.layerX;
my.fireEvent('click', (relX / my.wrapper.scrollWidth) || 0);
});
},
createCanvas: function () {
var canvas = this.canvas = this.wrapper.appendChild(
document.createElement('canvas')
);
this.timeCc = canvas.getContext('2d');
this.wavesurfer.drawer.style(canvas, {
position: 'absolute',
zIndex: 4
});
},
render: function () {
this.updateCanvasStyle();
this.drawTimeCanvas();
},
updateCanvasStyle: function () {
var width = Math.round(this.drawer.wrapper.scrollWidth / this.wavesurfer.params.pixelRatio);
this.canvas.width = width;
this.canvas.height = this.height;
this.canvas.style.width = width + 'px';
},
drawTimeCanvas: function() {
var backend = this.wavesurfer.backend,
wsParams = this.wavesurfer.params,
duration = backend.getDuration();
if (wsParams.fillParent && !wsParams.scrollParent) {
var width = this.drawer.getWidth();
var pixelsPerSecond = width/duration;
} else {
var width = backend.getDuration() * wsParams.minPxPerSec;
var pixelsPerSecond = wsParams.minPxPerSec;
}
pixelsPerSecond = pixelsPerSecond / wsParams.pixelRatio;
if (duration > 0) {
var curPixel = 0,
curSeconds = 0,
totalSeconds = parseInt(duration, 10) + 1,
timeInterval = (pixelsPerSecond < 10) ? 10 : 1,
formatTime = function(seconds) {
if (seconds/60 > 1) {
var minutes = parseInt(seconds / 60),
seconds = parseInt(seconds % 60);
seconds = (seconds < 10) ? '0' + seconds : seconds;
return '' + minutes + ':' + seconds;
} else {
return seconds;
}
};
var height1 = this.height - 4,
height2 = (this.height * (this.notchPercentHeight / 100.0)) - 4;
for (var i = 0; i < totalSeconds/timeInterval; i++) {
if (i % 10 == 0) {
this.timeCc.fillStyle = this.primaryColor;
this.timeCc.fillRect(curPixel, 0, 1, height1);
this.timeCc.font = this.fontSize + 'px ' + this.fontFamily;
this.timeCc.fillStyle = this.primaryFontColor;
this.timeCc.fillText(formatTime(curSeconds), curPixel + 5, height1);
} else if (i % 10 == 5) {
this.timeCc.fillStyle = this.secondaryColor;
this.timeCc.fillRect(curPixel, 0, 1, height1);
this.timeCc.font = this.fontSize + 'px ' + this.fontFamily;
this.timeCc.fillStyle = this.secondaryFontColor;
this.timeCc.fillText(formatTime(curSeconds), curPixel + 5, height1);
} else {
this.timeCc.fillStyle = this.secondaryColor;
this.timeCc.fillRect(curPixel, 0, 1, height2);
}
curSeconds += timeInterval;
curPixel += pixelsPerSecond * timeInterval;
}
}
},
updateScroll: function(e){
this.wrapper.scrollLeft = e.target.scrollLeft;
}
};
WaveSurfer.util.extend(WaveSurfer.Timeline, WaveSurfer.Observer);
return WaveSurfer.Timeline;
}));