213 lines
7.0 KiB
JavaScript
213 lines
7.0 KiB
JavaScript
/* *
|
|
*
|
|
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
|
*
|
|
* */
|
|
import H from '../parts/Globals.js';
|
|
import U from '../parts/Utilities.js';
|
|
var addEvent = U.addEvent, fireEvent = U.fireEvent, inArray = U.inArray, objectEach = U.objectEach, pick = U.pick, removeEvent = U.removeEvent;
|
|
/* eslint-disable valid-jsdoc */
|
|
/**
|
|
* It provides methods for:
|
|
* - adding and handling DOM events and a drag event,
|
|
* - mapping a mouse move event to the distance between two following events.
|
|
* The units of the distance are specific to a transformation,
|
|
* e.g. for rotation they are radians, for scaling they are scale factors.
|
|
*
|
|
* @private
|
|
* @mixin
|
|
* @memberOf Annotation
|
|
*/
|
|
var eventEmitterMixin = {
|
|
/**
|
|
* Add emitter events.
|
|
*/
|
|
addEvents: function () {
|
|
var emitter = this, addMouseDownEvent = function (element) {
|
|
addEvent(element, 'mousedown', function (e) {
|
|
emitter.onMouseDown(e);
|
|
});
|
|
};
|
|
addMouseDownEvent(this.graphic.element);
|
|
(emitter.labels || []).forEach(function (label) {
|
|
if (label.options.useHTML && label.graphic.text) {
|
|
// Mousedown event bound to HTML element (#13070).
|
|
addMouseDownEvent(label.graphic.text.element);
|
|
}
|
|
});
|
|
objectEach(emitter.options.events, function (event, type) {
|
|
var eventHandler = function (e) {
|
|
if (type !== 'click' || !emitter.cancelClick) {
|
|
event.call(emitter, emitter.chart.pointer.normalize(e), emitter.target);
|
|
}
|
|
};
|
|
if (inArray(type, emitter.nonDOMEvents || []) === -1) {
|
|
emitter.graphic.on(type, eventHandler);
|
|
}
|
|
else {
|
|
addEvent(emitter, type, eventHandler);
|
|
}
|
|
});
|
|
if (emitter.options.draggable) {
|
|
addEvent(emitter, 'drag', emitter.onDrag);
|
|
if (!emitter.graphic.renderer.styledMode) {
|
|
var cssPointer_1 = {
|
|
cursor: {
|
|
x: 'ew-resize',
|
|
y: 'ns-resize',
|
|
xy: 'move'
|
|
}[emitter.options.draggable]
|
|
};
|
|
emitter.graphic.css(cssPointer_1);
|
|
(emitter.labels || []).forEach(function (label) {
|
|
if (label.options.useHTML && label.graphic.text) {
|
|
label.graphic.text.css(cssPointer_1);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if (!emitter.isUpdating) {
|
|
fireEvent(emitter, 'add');
|
|
}
|
|
},
|
|
/**
|
|
* Remove emitter document events.
|
|
*/
|
|
removeDocEvents: function () {
|
|
if (this.removeDrag) {
|
|
this.removeDrag = this.removeDrag();
|
|
}
|
|
if (this.removeMouseUp) {
|
|
this.removeMouseUp = this.removeMouseUp();
|
|
}
|
|
},
|
|
/**
|
|
* Mouse down handler.
|
|
*/
|
|
onMouseDown: function (e) {
|
|
var emitter = this, pointer = emitter.chart.pointer, prevChartX, prevChartY;
|
|
if (e.preventDefault) {
|
|
e.preventDefault();
|
|
}
|
|
// On right click, do nothing:
|
|
if (e.button === 2) {
|
|
return;
|
|
}
|
|
e = pointer.normalize(e);
|
|
prevChartX = e.chartX;
|
|
prevChartY = e.chartY;
|
|
emitter.cancelClick = false;
|
|
emitter.chart.hasDraggedAnnotation = true;
|
|
emitter.removeDrag = addEvent(H.doc, 'mousemove', function (e) {
|
|
emitter.hasDragged = true;
|
|
e = pointer.normalize(e);
|
|
e.prevChartX = prevChartX;
|
|
e.prevChartY = prevChartY;
|
|
fireEvent(emitter, 'drag', e);
|
|
prevChartX = e.chartX;
|
|
prevChartY = e.chartY;
|
|
});
|
|
emitter.removeMouseUp = addEvent(H.doc, 'mouseup', function (e) {
|
|
emitter.cancelClick = emitter.hasDragged;
|
|
emitter.hasDragged = false;
|
|
emitter.chart.hasDraggedAnnotation = false;
|
|
// ControlPoints vs Annotation:
|
|
fireEvent(pick(emitter.target, emitter), 'afterUpdate');
|
|
emitter.onMouseUp(e);
|
|
});
|
|
},
|
|
/**
|
|
* Mouse up handler.
|
|
*/
|
|
onMouseUp: function (_e) {
|
|
var chart = this.chart, annotation = this.target || this, annotationsOptions = chart.options.annotations, index = chart.annotations.indexOf(annotation);
|
|
this.removeDocEvents();
|
|
annotationsOptions[index] = annotation.options;
|
|
},
|
|
/**
|
|
* Drag and drop event. All basic annotations should share this
|
|
* capability as well as the extended ones.
|
|
*/
|
|
onDrag: function (e) {
|
|
if (this.chart.isInsidePlot(e.chartX - this.chart.plotLeft, e.chartY - this.chart.plotTop)) {
|
|
var translation = this.mouseMoveToTranslation(e);
|
|
if (this.options.draggable === 'x') {
|
|
translation.y = 0;
|
|
}
|
|
if (this.options.draggable === 'y') {
|
|
translation.x = 0;
|
|
}
|
|
if (this.points.length) {
|
|
this.translate(translation.x, translation.y);
|
|
}
|
|
else {
|
|
this.shapes.forEach(function (shape) {
|
|
shape.translate(translation.x, translation.y);
|
|
});
|
|
this.labels.forEach(function (label) {
|
|
label.translate(translation.x, translation.y);
|
|
});
|
|
}
|
|
this.redraw(false);
|
|
}
|
|
},
|
|
/**
|
|
* Map mouse move event to the radians.
|
|
*/
|
|
mouseMoveToRadians: function (e, cx, cy) {
|
|
var prevDy = e.prevChartY - cy, prevDx = e.prevChartX - cx, dy = e.chartY - cy, dx = e.chartX - cx, temp;
|
|
if (this.chart.inverted) {
|
|
temp = prevDx;
|
|
prevDx = prevDy;
|
|
prevDy = temp;
|
|
temp = dx;
|
|
dx = dy;
|
|
dy = temp;
|
|
}
|
|
return Math.atan2(dy, dx) - Math.atan2(prevDy, prevDx);
|
|
},
|
|
/**
|
|
* Map mouse move event to the distance between two following events.
|
|
*/
|
|
mouseMoveToTranslation: function (e) {
|
|
var dx = e.chartX - e.prevChartX, dy = e.chartY - e.prevChartY, temp;
|
|
if (this.chart.inverted) {
|
|
temp = dy;
|
|
dy = dx;
|
|
dx = temp;
|
|
}
|
|
return {
|
|
x: dx,
|
|
y: dy
|
|
};
|
|
},
|
|
/**
|
|
* Map mouse move to the scale factors.
|
|
*
|
|
* @param {Object} e event
|
|
* @param {number} cx center x
|
|
* @param {number} cy center y
|
|
**/
|
|
mouseMoveToScale: function (e, cx, cy) {
|
|
var prevDx = e.prevChartX - cx, prevDy = e.prevChartY - cy, dx = e.chartX - cx, dy = e.chartY - cy, sx = (dx || 1) / (prevDx || 1), sy = (dy || 1) / (prevDy || 1), temp;
|
|
if (this.chart.inverted) {
|
|
temp = sy;
|
|
sy = sx;
|
|
sx = temp;
|
|
}
|
|
return {
|
|
x: sx,
|
|
y: sy
|
|
};
|
|
},
|
|
/**
|
|
* Destroy the event emitter.
|
|
*/
|
|
destroy: function () {
|
|
this.removeDocEvents();
|
|
removeEvent(this);
|
|
this.hcEvents = null;
|
|
}
|
|
};
|
|
export default eventEmitterMixin;
|