@checksub_team/peaks_timeline
Version:
JavaScript UI component for displaying audio waveforms
208 lines (168 loc) • 5.42 kB
JavaScript
/**
* @file
*
* Defines the {@link MouseDragHandler} class.
*
* @module mouse-drag-handler
*/
define([
'konva'
], function(Konva) {
'use strict';
function getMarkerObject(obj) {
while (obj.parent !== null) {
if (obj.parent instanceof Konva.Layer) {
return obj;
}
obj = obj.parent;
}
return null;
}
/**
* An object to receive callbacks on mouse drag events. Each function is
* called with the current mouse X position, relative to the stage's
* container HTML element.
*
* @typedef {Object} MouseDragHandlers
* @global
* @property {Function} onMouseDown Mouse down event handler.
* @property {Function} onMouseMove Mouse move event handler.
* @property {Function} onMouseUp Mouse up event handler.
*/
/**
* Creates a handler for mouse events to allow interaction with the waveform
* views by clicking and dragging the mouse.
*
* @class
* @alias MouseDragHandler
*
* @param {Konva.Stage} stage
* @param {MouseDragHandlers} handlers
*/
function MouseDragHandler(stage, handlers) {
this._stage = stage;
this._handlers = handlers;
this._dragging = false;
this._mouseDown = this._mouseDown.bind(this);
this._mouseUp = this._mouseUp.bind(this);
this._mouseMove = this._mouseMove.bind(this);
this._stage.on('mousedown', this._mouseDown);
this._stage.on('touchstart', this._mouseDown);
this._mouseDownClientX = null;
}
/**
* Mouse down event handler.
*
* @param {MouseEvent} event
*/
MouseDragHandler.prototype._mouseDown = function(event) {
var marker = getMarkerObject(event.target);
// Avoid interfering with drag/drop of point and segment markers.
if (marker && marker.attrs.draggable) {
return;
}
if (event.type === 'touchstart') {
this._mouseDownClientX = Math.floor(event.evt.touches[0].clientX);
}
else {
this._mouseDownClientX = event.evt.clientX;
}
if (this._handlers.onMouseDown) {
var mouseDownPosX = this._getMousePosX(this._mouseDownClientX);
var mouseDownPosY = this._getMousePosY(event.evt.clientY);
this._handlers.onMouseDown(mouseDownPosX, mouseDownPosY);
}
// Use the window mousemove and mouseup handlers instead of the
// Konva.Stage ones so that we still receive events if the user moves the
// mouse outside the stage.
window.addEventListener('mousemove', this._mouseMove, false);
window.addEventListener('touchmove', this._mouseMove, false);
window.addEventListener('mouseup', this._mouseUp, false);
window.addEventListener('touchend', this._mouseUp, false);
window.addEventListener('blur', this._mouseUp, false);
};
/**
* Mouse move event handler.
*
* @param {MouseEvent} event
*/
MouseDragHandler.prototype._mouseMove = function(event) {
var clientX = null;
if (event.type === 'touchmove') {
clientX = Math.floor(event.changedTouches[0].clientX);
}
else {
clientX = event.clientX;
}
// Don't update on vertical mouse movement.
if (clientX === this._mouseDownClientX) {
return;
}
this._dragging = true;
if (this._handlers.onMouseMove) {
var mousePosX = this._getMousePosX(clientX);
var mousePosY = this._getMousePosY(event.clientY);
this._handlers.onMouseMove(mousePosX, mousePosY);
}
};
/**
* Mouse up event handler.
*
* @param {MouseEvent} event
*/
MouseDragHandler.prototype._mouseUp = function(event) {
var clientX = null;
if (event.type === 'touchend') {
clientX = Math.floor(event.changedTouches[0].clientX);
if (event.cancelable) {
event.preventDefault();
}
}
else {
clientX = event.clientX;
}
if (this._handlers.onMouseUp) {
var mousePosX = this._getMousePosX(clientX);
var mousePosY = this._getMousePosY(event.clientY);
this._handlers.onMouseUp(mousePosX, event, mousePosY);
}
window.removeEventListener('mousemove', this._mouseMove, false);
window.removeEventListener('touchmove', this._mouseMove, false);
window.removeEventListener('mouseup', this._mouseUp, false);
window.removeEventListener('touchend', this._mouseUp, false);
window.removeEventListener('blur', this._mouseUp, false);
this._dragging = false;
};
/**
* @returns {Number} The mouse X position, relative to the container that
* received the mouse down event.
*
* @private
* @param {Number} clientX Mouse client X position.
*/
MouseDragHandler.prototype._getMousePosX = function(clientX) {
var containerPos = this._stage.getContainer().getBoundingClientRect();
return clientX - containerPos.left;
};
/**
* @returns {Number} The mouse Y position, relative to the container that
* received the mouse down event.
*
* @private
* @param {Number} clientY Mouse client X position.
*/
MouseDragHandler.prototype._getMousePosY = function(clientY) {
var containerPos = this._stage.getContainer().getBoundingClientRect();
return clientY - containerPos.top;
};
/**
* Returns <code>true</code> if the mouse is being dragged, i.e., moved with
* the mouse button held down.
*
* @returns {Boolean}
*/
MouseDragHandler.prototype.isDragging = function() {
return this._dragging;
};
return MouseDragHandler;
});