wavesurfer
Version:
Interactive navigable audio visualization using Web Audio and Canvas
216 lines (190 loc) • 7.72 kB
JavaScript
'use strict';
/* Minimap */
WaveSurfer.Minimap = WaveSurfer.util.extend({}, WaveSurfer.Drawer, WaveSurfer.Drawer.Canvas, {
init: function (wavesurfer, params) {
this.wavesurfer = wavesurfer;
this.container = this.wavesurfer.drawer.container;
this.lastPos = this.wavesurfer.drawer.lastPos;
this.params = wavesurfer.util.extend(
{}, this.wavesurfer.drawer.params, {
showRegions: false,
showOverview: false,
overviewBorderColor: 'green',
overviewBorderSize: 2
}, params, {
scrollParent: false,
fillParent: true
}
);
this.width = 0;
this.height = this.params.height * this.params.pixelRatio;
this.createWrapper();
this.createElements();
if (WaveSurfer.Regions && this.params.showRegions) {
this.regions();
}
this.bindWaveSurferEvents();
this.bindMinimapEvents();
},
regions: function() {
var my = this;
this.regions = {};
this.wavesurfer.on('region-created', function(region) {
my.regions[region.id] = region;
my.renderRegions();
});
this.wavesurfer.on('region-updated', function(region) {
my.regions[region.id] = region;
my.renderRegions();
});
this.wavesurfer.on('region-removed', function(region) {
delete my.regions[region.id];
my.renderRegions();
});
},
renderRegions: function() {
var my = this;
var regionElements = this.wrapper.querySelectorAll('region');
for (var i = 0; i < regionElements.length; ++i) {
this.wrapper.removeChild(regionElements[i]);
}
Object.keys(this.regions).forEach(function(id){
var region = my.regions[id];
var width = (my.width * ((region.end - region.start) / my.wavesurfer.getDuration()));
var left = (my.width * (region.start / my.wavesurfer.getDuration()));
var regionElement = my.style(document.createElement('region'), {
height: 'inherit',
backgroundColor: region.color,
width: width + 'px',
left: left + 'px',
display: 'block',
position: 'absolute'
});
regionElement.classList.add(id);
my.wrapper.appendChild(regionElement);
});
},
createElements: function() {
WaveSurfer.Drawer.Canvas.createElements.call(this);
if (this.params.showOverview) {
this.overviewRegion = this.style(document.createElement('overview'), {
height: (this.wrapper.offsetHeight - (this.params.overviewBorderSize * 2)) + 'px',
width: '0px',
display: 'block',
position: 'absolute',
cursor: 'move',
border: this.params.overviewBorderSize + 'px solid ' + this.params.overviewBorderColor,
zIndex: 2,
opacity: this.params.overviewOpacity
});
this.wrapper.appendChild(this.overviewRegion);
}
},
bindWaveSurferEvents: function () {
var my = this;
// render on load
this.render();
this.wavesurfer.on('audioprocess', function (currentTime) {
my.progress(my.wavesurfer.backend.getPlayedPercents());
});
this.wavesurfer.on('seek', function(progress) {
my.progress(my.wavesurfer.backend.getPlayedPercents());
});
if (this.params.showOverview) {
this.wavesurfer.on('scroll', function(event) {
if (!my.draggingOverview) {
my.moveOverviewRegion(event.target.scrollLeft / my.ratio);
}
});
this.wavesurfer.drawer.wrapper.addEventListener('mouseover', function(event) {
if (my.draggingOverview) {
my.draggingOverview = false;
}
});
}
var prevWidth = 0;
var onResize = this.wavesurfer.util.debounce(function () {
if (prevWidth != my.wrapper.clientWidth) {
prevWidth = my.wrapper.clientWidth;
my.render();
my.progress(my.wavesurfer.backend.getPlayedPercents());
}
}, 100);
window.addEventListener('resize', onResize, true);
window.addEventListener('orientationchange', onResize, true);
this.wavesurfer.on('destroy', function () {
my.destroy.bind(this);
window.removeEventListener('resize', onResize, true);
});
},
bindMinimapEvents: function () {
var my = this;
var relativePositionX = 0;
var seek = true;
var positionMouseDown = {
clientX: 0,
clientY: 0
};
this.on('click', (function (e, position) {
if (seek) {
this.progress(position);
this.wavesurfer.seekAndCenter(position);
} else {
seek = true;
}
}).bind(this));
if (this.params.showOverview) {
this.overviewRegion.addEventListener('mousedown', function(event) {
my.draggingOverview = true;
relativePositionX = event.layerX;
positionMouseDown.clientX = event.clientX;
positionMouseDown.clientY = event.clientY;
});
this.wrapper.addEventListener('mousemove', function(event) {
if(my.draggingOverview) {
my.moveOverviewRegion(event.clientX - my.container.getBoundingClientRect().left - relativePositionX);
}
});
this.wrapper.addEventListener('mouseup', function(event) {
if (positionMouseDown.clientX - event.clientX === 0 && positionMouseDown.clientX - event.clientX === 0) {
seek = true;
my.draggingOverview = false;
} else if (my.draggingOverview) {
seek = false;
my.draggingOverview = false;
}
});
}
},
render: function () {
var len = this.getWidth();
var peaks = this.wavesurfer.backend.getPeaks(len, 0, len);
this.drawPeaks(peaks, len, 0, len);
if (this.params.showOverview) {
//get proportional width of overview region considering the respective
//width of the drawers
this.ratio = this.wavesurfer.drawer.width / this.width;
this.waveShowedWidth = this.wavesurfer.drawer.width / this.ratio;
this.waveWidth = this.wavesurfer.drawer.width;
this.overviewWidth = (this.width / this.ratio);
this.overviewPosition = 0;
this.overviewRegion.style.width = (this.overviewWidth - (this.params.overviewBorderSize * 2)) + 'px';
}
},
moveOverviewRegion: function(pixels) {
if (pixels < 0) {
this.overviewPosition = 0;
} else if (pixels + this.overviewWidth < this.width) {
this.overviewPosition = pixels;
} else {
this.overviewPosition = (this.width - this.overviewWidth);
}
this.overviewRegion.style.left = this.overviewPosition + 'px';
this.wavesurfer.drawer.wrapper.scrollLeft = this.overviewPosition * this.ratio;
}
});
WaveSurfer.initMinimap = function (params) {
var map = Object.create(WaveSurfer.Minimap);
map.init(this, params);
return map;
};