UNPKG

@antv/g6

Version:

graph visualization frame work

348 lines (302 loc) 12.8 kB
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * @fileOverview dom event handler * @author wuyue.lwy <wyueliu@gmail.com> */ var Base = require('./base'); var Util = require('../util/'); var EVENT = { MOUSEMOVE: 'mousemove', MOUSEDOWN: 'mousedown', MOUSEUP: 'mouseup', MOUSEENTER: 'mouseenter', MOUSELEAVE: 'mouseleave', CLICK: 'click', DBLCLICK: 'dblclick', DRAGSTART: 'dragstart', DRAG: 'drag', DRAGENTER: 'dragenter', DRAGLEAVE: 'dragleave', DRAGEND: 'dragend', DROP: 'drop', CONTEXTMENU: 'contextmenu', MOUSEWHEEL: 'mousewheel', KEYDOWN: 'keydown', KEYUP: 'keyup', KEYPRESS: 'keypress' }; var SHAKE_TOLERANCE = 9; // use to tolerate click shake prevent drag shake. The distance is tolerance sqrt. // native dom events list: var MouseEventTypes = [EVENT.DBLCLICK, EVENT.MOUSEDOWN, EVENT.MOUSEUP, EVENT.MOUSEENTER, EVENT.MOUSELEAVE, EVENT.MOUSEMOVE, EVENT.CONTEXTMENU, EVENT.MOUSEWHEEL]; var KeyboardEventTypes = [EVENT.KEYDOWN, EVENT.KEYUP, EVENT.KEYPRESS]; var CANVAS = 'canvas:'; var Controller = function (_Base) { _inherits(Controller, _Base); function Controller(cfg) { _classCallCheck(this, Controller); var _this = _possibleConstructorReturn(this, _Base.call(this, cfg)); _this._domEvents = []; _this._initEventStates(); _this._registerEvents(); return _this; } // init evnet states Controller.prototype._initEventStates = function _initEventStates() { this._pressing = false; this._dragging = false; this._currentEventObj = null; this._dragEventObj = {}; }; // register all native dom events Controller.prototype._registerEvents = function _registerEvents() { this._registerMouseEvents(); this._registerKeyboardEvents(); }; Controller.prototype._registerKeyboardEvents = function _registerKeyboardEvents() { var graph = this.graph; var el = graph.getKeyboardEventWrapper(); var _events = this._domEvents; var keyboardEnable = graph.get('keyboardEnable'); Util.each(KeyboardEventTypes, function (item) { _events.push(Util.addEventListener(el, item, function (ev) { var enable = true; if (Util.isFunction(keyboardEnable)) { enable = keyboardEnable(); } enable && graph.emit(item, { domEvent: ev }); })); }); }; Controller.prototype._registerMouseEvents = function _registerMouseEvents() { var _this2 = this; var graph = this.graph; var self = this; var el = graph.getMouseEventWrapper(); var _events = this._domEvents; Util.each(MouseEventTypes, function (item) { _events.push(Util.addEventListener(el, item, function (ev) { var oldEventObj = _this2._currentEventObj; _this2._oldEventObj = oldEventObj; _this2._processEventObj(ev); var currentEventObj = _this2._currentEventObj; // emit simulate events like click, dragstart, dragend, drop, dtagover, mouseenter, mouseleave self._simulateEvents(ev, oldEventObj, currentEventObj); // emit normal events if ([EVENT.MOUSELEAVE, EVENT.MOUSEENTER].indexOf(ev.type) !== -1) { self._triggerEvent(CANVAS + ev.type); } self._triggerEvent(ev.type); if (ev.type === EVENT.MOUSELEAVE) { // trigger canvas dragleave when out of canvas , user can clear things that record by themselves if (_this2._dragging) { self._triggerEvent(EVENT.DRAGLEAVE, Util.mix({}, currentEventObj, { item: null, shape: null, currentItem: _this2._dragEventObj.item, currentShape: _this2._dragEventObj.shape })); } self._initEventStates(); } })); }); }; // delete listeners Controller.prototype.destroy = function destroy() { var events = this._domEvents; Util.each(events, function (ev) { ev && ev.remove(); }); this._domEvents = null; }; /** * trigger event * @param {string} type - event type * @param {object} eventObj - event object */ Controller.prototype._triggerEvent = function _triggerEvent(type, eventObj) { if (!eventObj) { if (type === 'mouseleave') { eventObj = this._oldEventObj; } else { eventObj = this._currentEventObj; } } if (type === 'mousedown') { eventObj.button = this._button; } // emit shape event eventObj._type = type; this.emitGraphEvent(type, eventObj); if ([CANVAS + EVENT.MOUSELEAVE, CANVAS + EVENT.MOUSEENTER].indexOf(type) !== -1) { return; } var eventPreFix = eventObj.shape && eventObj.shape.eventPreFix; if ([EVENT.DRAGSTART, EVENT.DRAG, EVENT.DRAGEND].indexOf(type) !== -1) { // get correct prefix eventPreFix = eventObj.currentShape && eventObj.currentShape.eventPreFix; } if (eventPreFix) { var _type = eventPreFix + ':' + type; eventObj._type = _type; if (Util.isBoolean(eventObj._isItemChange)) { if (eventObj._isItemChange) { this.emitGraphEvent(_type, eventObj); } } else { this.emitGraphEvent(_type, eventObj); } } }; /** * emit graph event * @param {object} type - event type * @param {object} eventObj - event object */ Controller.prototype.emitGraphEvent = function emitGraphEvent(type, eventObj) { var graph = this.graph; graph.emit(type, eventObj); }; Controller.prototype._getDistanceToPress = function _getDistanceToPress(ev) { return Math.pow(ev.clientX - this._pressX, 2) + Math.pow(ev.clientY - this._pressY, 2); }; /** * check whether or not click and drag * @param {object} ev - native dom event * @param {object} oldEventObj - old event object * @param {object} currentEventObj - current event object */ Controller.prototype._simulateEvents = function _simulateEvents(ev) { var oldEventObj = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var currentEventObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var currentItem = this._dragEventObj.item; var currentShape = this._dragEventObj.shape; switch (ev.type) { case EVENT.MOUSEDOWN: this._pressing = true; this._button = ev.button; this._pressX = ev.clientX; this._pressY = ev.clientY; break; case EVENT.MOUSEMOVE: // record the element that was dragging if (this._dragging) { this._triggerEvent(EVENT.DRAG, Util.mix({}, currentEventObj, { button: this._button, currentItem: currentItem, currentShape: currentShape })); if (oldEventObj.shape !== currentEventObj.shape) { var _isItemChange = this._isItemChange(oldEventObj, currentEventObj); if (oldEventObj.shape) { this._triggerEvent(EVENT.DRAGLEAVE, Util.mix({}, currentEventObj, { button: this._button, item: oldEventObj.item, shape: oldEventObj.shape, toItem: currentEventObj.item, toShape: currentEventObj.shape, currentItem: currentItem, currentShape: currentShape, _isItemChange: _isItemChange })); } if (currentEventObj.shape) { this._triggerEvent(EVENT.DRAGENTER, Util.mix({}, currentEventObj, { button: this._button, currentItem: currentItem, currentShape: currentShape, fromItem: oldEventObj.item, fromShape: oldEventObj.shape, _isItemChange: _isItemChange })); } } } else if (this._pressing && this._getDistanceToPress(ev) > SHAKE_TOLERANCE) { this._dragging = true; this._dragEventObj = currentEventObj; currentItem = this._dragEventObj.item; currentShape = this._dragEventObj.shape; this._triggerEvent(EVENT.DRAGSTART, Util.mix({}, currentEventObj, { button: this._button, currentItem: currentItem, currentShape: currentShape })); } // normal move if (oldEventObj.shape !== currentEventObj.shape) { var _isItemChange2 = this._isItemChange(oldEventObj, currentEventObj); if (oldEventObj.shape) { // just canvas has no shape, it should not trigger leave this._triggerEvent(EVENT.MOUSELEAVE, Util.mix({}, currentEventObj, { item: oldEventObj.item, shape: oldEventObj.shape, toItem: currentEventObj.item, toShape: currentEventObj.shape, _isItemChange: _isItemChange2 })); } if (currentEventObj.shape) { // canvas should not trigger enter this._triggerEvent(EVENT.MOUSEENTER, Util.mix({}, currentEventObj, { fromtItem: oldEventObj.item, fromShape: oldEventObj.shape, _isItemChange: _isItemChange2 })); } } break; case EVENT.MOUSEUP: if (!this._dragging && this._pressing) { this._triggerEvent(EVENT.CLICK, Util.mix({}, currentEventObj, { button: this._button })); } else { this._triggerEvent(EVENT.DROP, Util.mix({}, currentEventObj, { button: this._button, currentItem: currentItem, currentShape: currentShape })); this._triggerEvent(EVENT.DRAGEND, Util.mix({}, currentEventObj, { button: this._button, currentItem: currentItem, currentShape: currentShape })); } this._pressing = false; this._dragging = false; this._dragEventObj = {}; break; default: return; } }; /** * checkout item is change * @param {object} oldEventObj - old event obj * @param {object} currentEventObj - current event obj * @return {boolean} rst */ Controller.prototype._isItemChange = function _isItemChange(oldEventObj, currentEventObj) { var oldShape = oldEventObj.shape; var currentShape = currentEventObj.shape; var shapeIsItemChange = oldShape && currentShape && (oldShape.get('isItemChange') || currentShape.get('isItemChange')); if (shapeIsItemChange) { return shapeIsItemChange(currentShape, oldShape); } if (Util.isObject(oldEventObj.item) && Util.isObject(currentEventObj.item)) { return oldEventObj.item.id !== currentEventObj.item.id; } return oldEventObj.item !== currentEventObj.item; }; /** * handle the native event by browser * @param {object} ev - native event by browser */ Controller.prototype._processEventObj = function _processEventObj(ev) { var graph = this.graph; var canvas = graph.get('_canvas'); var frontCanvas = graph.get('_frontCanvas'); var evObj = this._getEventObj(ev, canvas); var frontEvObj = this._getEventObj(ev, frontCanvas); // frontEvObj is the first if (frontEvObj.shape) { evObj.shape = frontEvObj.shape; evObj.item = frontEvObj.item; } evObj.frontEvObj = frontEvObj; this._currentEventObj = evObj; }; // transform point position by pixel Ratio Controller.prototype._parsePoint = function _parsePoint(x, y) { var graph = this.graph; return graph.getPointByCanvas({ x: x, y: y }); }; /** * get the source object which emitted event * @param {object} ev -native event by browser * @param {object} canvas -the scene that event occurred * @return {object} - event object */ Controller.prototype._getEventObj = function _getEventObj(ev, canvas) { var graph = this.graph; var clientX = ev.clientX; var clientY = ev.clientY; var canvasPoint = canvas.getPointByClient(clientX, clientY); var point = this._parsePoint(canvasPoint.x, canvasPoint.y); var shape = canvas.getShape(canvasPoint.x, canvasPoint.y); var item = graph.getItemByShape(shape); var pixelRatio = canvas.get('pixelRatio'); return { item: item, shape: shape, x: point.x, y: point.y, domX: canvasPoint.x / pixelRatio, domY: canvasPoint.y / pixelRatio, domEvent: ev }; }; return Controller; }(Base); module.exports = Controller;