wavesurfer
Version:
Interactive navigable audio visualization using Web Audio and Canvas
223 lines (174 loc) • 6.34 kB
JavaScript
'use strict';
WaveSurfer.Drawer = {
init: function (container, params) {
this.container = container;
this.params = params;
this.width = 0;
this.height = params.height * this.params.pixelRatio;
this.lastPos = 0;
this.initDrawer(params);
this.createWrapper();
this.createElements();
},
createWrapper: function () {
this.wrapper = this.container.appendChild(
document.createElement('wave')
);
this.style(this.wrapper, {
display: 'block',
position: 'relative',
userSelect: 'none',
webkitUserSelect: 'none',
height: this.params.height + 'px'
});
if (this.params.fillParent || this.params.scrollParent) {
this.style(this.wrapper, {
width: '100%',
overflowX: this.params.hideScrollbar ? 'hidden' : 'auto',
overflowY: 'hidden'
});
}
this.setupWrapperEvents();
},
handleEvent: function (e, noPrevent) {
!noPrevent && e.preventDefault();
var clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX;
var bbox = this.wrapper.getBoundingClientRect();
var nominalWidth = this.width;
var parentWidth = this.getWidth();
var progress;
if (!this.params.fillParent && nominalWidth < parentWidth) {
progress = ((clientX - bbox.left) * this.params.pixelRatio / nominalWidth) || 0;
if (progress > 1) {
progress = 1;
}
} else {
progress = ((clientX - bbox.left + this.wrapper.scrollLeft) / this.wrapper.scrollWidth) || 0;
}
return progress;
},
setupWrapperEvents: function () {
var my = this;
this.wrapper.addEventListener('click', function (e) {
var scrollbarHeight = my.wrapper.offsetHeight - my.wrapper.clientHeight;
if (scrollbarHeight != 0) {
// scrollbar is visible. Check if click was on it
var bbox = my.wrapper.getBoundingClientRect();
if (e.clientY >= bbox.bottom - scrollbarHeight) {
// ignore mousedown as it was on the scrollbar
return;
}
}
if (my.params.interact) {
my.fireEvent('click', e, my.handleEvent(e));
}
});
this.wrapper.addEventListener('scroll', function (e) {
my.fireEvent('scroll', e);
});
},
drawPeaks: function (peaks, length, start, end) {
this.setWidth(length);
this.params.barWidth ?
this.drawBars(peaks, 0, start, end) :
this.drawWave(peaks, 0, start, end);
},
style: function (el, styles) {
Object.keys(styles).forEach(function (prop) {
if (el.style[prop] !== styles[prop]) {
el.style[prop] = styles[prop];
}
});
return el;
},
resetScroll: function () {
if (this.wrapper !== null) {
this.wrapper.scrollLeft = 0;
}
},
recenter: function (percent) {
var position = this.wrapper.scrollWidth * percent;
this.recenterOnPosition(position, true);
},
recenterOnPosition: function (position, immediate) {
var scrollLeft = this.wrapper.scrollLeft;
var half = ~~(this.wrapper.clientWidth / 2);
var target = position - half;
var offset = target - scrollLeft;
var maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;
if (maxScroll == 0) {
// no need to continue if scrollbar is not there
return;
}
// if the cursor is currently visible...
if (!immediate && -half <= offset && offset < half) {
// we'll limit the "re-center" rate.
var rate = 5;
offset = Math.max(-rate, Math.min(rate, offset));
target = scrollLeft + offset;
}
// limit target to valid range (0 to maxScroll)
target = Math.max(0, Math.min(maxScroll, target));
// no use attempting to scroll if we're not moving
if (target != scrollLeft) {
this.wrapper.scrollLeft = target;
}
},
getScrollX: function() {
return Math.round(this.wrapper.scrollLeft * this.params.pixelRatio);
},
getWidth: function () {
return Math.round(this.container.clientWidth * this.params.pixelRatio);
},
setWidth: function (width) {
if (this.width == width) {
return;
}
this.width = width;
if (this.params.fillParent || this.params.scrollParent) {
this.style(this.wrapper, {
width: ''
});
} else {
this.style(this.wrapper, {
width: ~~(this.width / this.params.pixelRatio) + 'px'
});
}
this.updateSize();
},
setHeight: function (height) {
if (height == this.height) { return; }
this.height = height;
this.style(this.wrapper, {
height: ~~(this.height / this.params.pixelRatio) + 'px'
});
this.updateSize();
},
progress: function (progress) {
var minPxDelta = 1 / this.params.pixelRatio;
var pos = Math.round(progress * this.width) * minPxDelta;
if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {
this.lastPos = pos;
if (this.params.scrollParent && this.params.autoCenter) {
var newPos = ~~(this.wrapper.scrollWidth * progress);
this.recenterOnPosition(newPos);
}
this.updateProgress(pos);
}
},
destroy: function () {
this.unAll();
if (this.wrapper) {
this.container.removeChild(this.wrapper);
this.wrapper = null;
}
},
/* Renderer-specific methods */
initDrawer: function () {},
createElements: function () {},
updateSize: function () {},
drawWave: function (peaks, max) {},
clearWave: function () {},
updateProgress: function (position) {}
};
WaveSurfer.util.extend(WaveSurfer.Drawer, WaveSurfer.Observer);