From 1b75021716eba68bea29c9b09485a0498eba9bc3 Mon Sep 17 00:00:00 2001 From: jos Date: Mon, 5 Jan 2015 15:18:10 +0100 Subject: [PATCH] Network mostly working with Hammer2 --- index.js | 3 +- lib/hammerUtil.js | 57 ++++++---- lib/module/hammer.js | 2 +- lib/network/Network.js | 134 ++++++++++++------------ lib/network/mixins/ManipulationMixin.js | 6 +- lib/network/mixins/NavigationMixin.js | 9 +- lib/util.js | 4 +- 7 files changed, 117 insertions(+), 98 deletions(-) diff --git a/index.js b/index.js index a92b6d87..0a29352e 100644 --- a/index.js +++ b/index.js @@ -70,4 +70,5 @@ exports.Graph = function () { // bundled external libraries exports.moment = require('./lib/module/moment'); -exports.hammer = require('./lib/module/hammer'); +exports.hammer = require('./lib/module/hammer'); // TODO: deprecate exports.hammer some day +exports.Hammer = require('./lib/module/hammer'); diff --git a/lib/hammerUtil.js b/lib/hammerUtil.js index bf195c0f..5aae601e 100644 --- a/lib/hammerUtil.js +++ b/lib/hammerUtil.js @@ -1,28 +1,47 @@ var Hammer = require('./module/hammer'); /** - * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent - * @param {Element} element - * @param {Event} event + * Register a touch event, taking place before a gesture + * @param {Hammer} hammer A hammer instance + * @param {function} callback Callback, called as callback(event) */ -exports.fakeGesture = function(element, event) { - var eventType = null; +exports.onTouch = function (hammer, callback) { + callback.inputHandler = function (event) { + if (event.isFirst) { + callback(event); + } + }; - // for hammer.js 1.0.5 - // var gesture = Hammer.event.collectEventData(this, eventType, event); + hammer.on('hammer.input', callback.inputHandler); +}; - // for hammer.js 1.0.6+ - var touches = Hammer.event.getTouchList(event, eventType); - var gesture = Hammer.event.collectEventData(this, eventType, touches, event); +/** + * Register a release event, taking place after a gesture + * @param {Hammer} hammer A hammer instance + * @param {function} callback Callback, called as callback(event) + */ +exports.onRelease = function (hammer, callback) { + callback.inputHandler = function (event) { + if (event.isFinal) { + callback(event); + } + }; - // on IE in standards mode, no touches are recognized by hammer.js, - // resulting in NaN values for center.pageX and center.pageY - if (isNaN(gesture.center.pageX)) { - gesture.center.pageX = event.pageX; - } - if (isNaN(gesture.center.pageY)) { - gesture.center.pageY = event.pageY; - } + return hammer.on('hammer.input', callback.inputHandler); +}; - return gesture; +/** + * Unregister a touch event, taking place before a gesture + * @param {Hammer} hammer A hammer instance + * @param {function} callback Callback, called as callback(event) + */ +exports.offTouch = function (hammer, callback) { + hammer.off('hammer.input', callback.inputHandler); }; + +/** + * Unregister a release event, taking place before a gesture + * @param {Hammer} hammer A hammer instance + * @param {function} callback Callback, called as callback(event) + */ +exports.offRelease = exports.offTouch; diff --git a/lib/module/hammer.js b/lib/module/hammer.js index a2679764..05ef2956 100644 --- a/lib/module/hammer.js +++ b/lib/module/hammer.js @@ -1,8 +1,8 @@ // Only load hammer.js when in a browser environment // (loading hammer.js in a node.js environment gives errors) if (typeof window !== 'undefined') { - var Hammer = window['Hammer'] || require('hammerjs'); var propagating = require('propagating-hammerjs'); + var Hammer = window['Hammer'] || require('hammerjs'); module.exports = propagating(Hammer); } else { diff --git a/lib/network/Network.js b/lib/network/Network.js index e338578e..735378ed 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -764,29 +764,24 @@ Network.prototype._create = function () { var me = this; this.drag = {}; this.pinch = {}; - this.hammer = Hammer(this.frame.canvas, { - prevent_default: true - }); + this.hammer = new Hammer(this.frame.canvas); + this.hammer.get('pinch').set({enable: true}); + this.hammer.on('tap', me._onTap.bind(me) ); this.hammer.on('doubletap', me._onDoubleTap.bind(me) ); - this.hammer.on('hold', me._onHold.bind(me) ); + this.hammer.on('press', me._onHold.bind(me) ); this.hammer.on('pinch', me._onPinch.bind(me) ); - this.hammer.on('touch', me._onTouch.bind(me) ); - this.hammer.on('dragstart', me._onDragStart.bind(me) ); - this.hammer.on('drag', me._onDrag.bind(me) ); - this.hammer.on('dragend', me._onDragEnd.bind(me) ); - this.hammer.on('mousewheel',me._onMouseWheel.bind(me) ); - this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF - this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) ); - - this.hammerFrame = Hammer(this.frame, { - prevent_default: true - }); - this.hammerFrame.on('release', me._onRelease.bind(me) ); + hammerUtil.onTouch(this.hammer, me._onTouch.bind(me)); + this.hammer.on('panstart', me._onDragStart.bind(me) ); + this.hammer.on('panmove', me._onDrag.bind(me) ); + this.hammer.on('panend', me._onDragEnd.bind(me) ); + + this.frame.canvas.addEventListener('mousemove', me._onMouseMoveTitle.bind(me) ); + this.frame.canvas.addEventListener('mousewheel', me._onMouseWheel.bind(me)); + this.frame.canvas.addEventListener('DOMMouseScroll', me._onMouseWheel.bind(me)); // for FF // add the frame to the container element this.containerElement.appendChild(this.frame); - }; @@ -804,35 +799,35 @@ Network.prototype._createKeyBinds = function() { this.keycharm.reset(); if (this.constants.keyboard.enabled && this.isActive()) { - this.keycharm.bind("up", this._moveUp.bind(me) , "keydown"); - this.keycharm.bind("up", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("down", this._moveDown.bind(me) , "keydown"); - this.keycharm.bind("down", this._yStopMoving.bind(me), "keyup"); - this.keycharm.bind("left", this._moveLeft.bind(me) , "keydown"); - this.keycharm.bind("left", this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("right",this._moveRight.bind(me), "keydown"); - this.keycharm.bind("right",this._xStopMoving.bind(me), "keyup"); - this.keycharm.bind("=", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("=", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num+", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("num+", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("num-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("num-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("-", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("-", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("[", this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("[", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("]", this._zoomOut.bind(me), "keydown"); - this.keycharm.bind("]", this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pageup",this._zoomIn.bind(me), "keydown"); - this.keycharm.bind("pageup",this._stopZoom.bind(me), "keyup"); - this.keycharm.bind("pagedown",this._zoomOut.bind(me),"keydown"); - this.keycharm.bind("pagedown",this._stopZoom.bind(me), "keyup"); + this.keycharm.bind('up', this._moveUp.bind(me) , 'keydown'); + this.keycharm.bind('up', this._yStopMoving.bind(me), 'keyup'); + this.keycharm.bind('down', this._moveDown.bind(me) , 'keydown'); + this.keycharm.bind('down', this._yStopMoving.bind(me), 'keyup'); + this.keycharm.bind('left', this._moveLeft.bind(me) , 'keydown'); + this.keycharm.bind('left', this._xStopMoving.bind(me), 'keyup'); + this.keycharm.bind('right',this._moveRight.bind(me), 'keydown'); + this.keycharm.bind('right',this._xStopMoving.bind(me), 'keyup'); + this.keycharm.bind('=', this._zoomIn.bind(me), 'keydown'); + this.keycharm.bind('=', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('num+', this._zoomIn.bind(me), 'keydown'); + this.keycharm.bind('num+', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('num-', this._zoomOut.bind(me), 'keydown'); + this.keycharm.bind('num-', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('-', this._zoomOut.bind(me), 'keydown'); + this.keycharm.bind('-', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('[', this._zoomIn.bind(me), 'keydown'); + this.keycharm.bind('[', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind(']', this._zoomOut.bind(me), 'keydown'); + this.keycharm.bind(']', this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('pageup',this._zoomIn.bind(me), 'keydown'); + this.keycharm.bind('pageup',this._stopZoom.bind(me), 'keyup'); + this.keycharm.bind('pagedown',this._zoomOut.bind(me),'keydown'); + this.keycharm.bind('pagedown',this._stopZoom.bind(me), 'keyup'); } if (this.constants.dataManipulation.enabled == true) { - this.keycharm.bind("esc",this._createManipulatorBar.bind(me)); - this.keycharm.bind("delete",this._deleteSelected.bind(me)); + this.keycharm.bind('esc',this._createManipulatorBar.bind(me)); + this.keycharm.bind('delete',this._deleteSelected.bind(me)); } }; @@ -842,25 +837,23 @@ Network.prototype.destroy = function() { this.keycharm.reset(); // clear hammer bindings - this.hammer.dispose(); + this.hammer.destroy(); // clear events this.off(); - - -} +}; /** * Get the pointer location from a touch location - * @param {{pageX: Number, pageY: Number}} touch + * @param {{x: Number, y: Number}} center * @return {{x: Number, y: Number}} pointer * @private */ -Network.prototype._getPointer = function (touch) { +Network.prototype._getPointer = function (center) { return { - x: touch.pageX - util.getAbsoluteLeft(this.frame.canvas), - y: touch.pageY - util.getAbsoluteTop(this.frame.canvas) + x: center.x - util.getAbsoluteLeft(this.frame.canvas), + y: center.y - util.getAbsoluteTop(this.frame.canvas) }; }; @@ -871,7 +864,7 @@ Network.prototype._getPointer = function (touch) { */ Network.prototype._onTouch = function (event) { if (new Date().valueOf() - this.touchTime > 100) { - this.drag.pointer = this._getPointer(event.gesture.center); + this.drag.pointer = this._getPointer(event.center); this.drag.pinched = false; this.pinch.scale = this._getScale(); @@ -886,8 +879,8 @@ Network.prototype._onTouch = function (event) { * handle drag start event * @private */ -Network.prototype._onDragStart = function () { - this._handleDragStart(); +Network.prototype._onDragStart = function (event) { + this._handleDragStart(event); }; @@ -897,7 +890,7 @@ Network.prototype._onDragStart = function () { * * @private */ -Network.prototype._handleDragStart = function() { +Network.prototype._handleDragStart = function(event) { var drag = this.drag; var node = this._getNodeAt(drag.pointer); // note: drag.pointer is set in _onTouch to get the initial touch location @@ -940,6 +933,8 @@ Network.prototype._handleDragStart = function() { } } } + + event.preventDefault(); }; @@ -966,7 +961,7 @@ Network.prototype._handleOnDrag = function(event) { // remove the focus on node if it is focussed on by the focusOnNode this.releaseNode(); - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); var me = this; var drag = this.drag; var selection = drag.selection; @@ -1010,6 +1005,8 @@ Network.prototype._handleOnDrag = function(event) { // this.start(); } } + + event.preventDefault(); }; /** @@ -1043,13 +1040,15 @@ Network.prototype._handleDragEnd = function(event) { this.emit("dragEnd",{nodeIds:this.getSelection().nodes}); } -} + event.preventDefault(); +}; + /** * handle tap/click event: select/unselect a node * @private */ Network.prototype._onTap = function (event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); this.pointerPosition = pointer; this._handleTap(pointer); @@ -1061,7 +1060,7 @@ Network.prototype._onTap = function (event) { * @private */ Network.prototype._onDoubleTap = function (event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); this._handleDoubleTap(pointer); }; @@ -1071,7 +1070,7 @@ Network.prototype._onDoubleTap = function (event) { * @private */ Network.prototype._onHold = function (event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); this.pointerPosition = pointer; this._handleOnHold(pointer); }; @@ -1082,7 +1081,7 @@ Network.prototype._onHold = function (event) { * @private */ Network.prototype._onRelease = function (event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); this._handleOnRelease(pointer); }; @@ -1092,7 +1091,7 @@ Network.prototype._onRelease = function (event) { * @private */ Network.prototype._onPinch = function (event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); this.drag.pinched = true; if (!('scale' in this.pinch)) { @@ -1100,7 +1099,7 @@ Network.prototype._onPinch = function (event) { } // TODO: enabled moving while pinching? - var scale = this.pinch.scale * event.gesture.scale; + var scale = this.pinch.scale * event.scale; this._zoom(scale, pointer) }; @@ -1183,7 +1182,6 @@ Network.prototype._onMouseWheel = function(event) { // Basically, delta is now positive if wheel was scrolled up, // and negative, if wheel was scrolled down. if (delta) { - // calculate the new scale var scale = this._getScale(); var zoom = delta / 10; @@ -1193,8 +1191,7 @@ Network.prototype._onMouseWheel = function(event) { scale *= (1 + zoom); // calculate the pointer location - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); + var pointer = this._getPointer({x: event.pageX, y: event.pageY}); // apply the new scale this._zoom(scale, pointer); @@ -1211,8 +1208,7 @@ Network.prototype._onMouseWheel = function(event) { * @private */ Network.prototype._onMouseMoveTitle = function (event) { - var gesture = hammerUtil.fakeGesture(this, event); - var pointer = this._getPointer(gesture.center); + var pointer = this._getPointer({x: event.pageX, y: event.pageY}); // check if the previously selected node is still selected if (this.popupObj) { @@ -2336,7 +2332,7 @@ Network.prototype._initializeMixinLoaders = function () { * Load the XY positions of the nodes into the dataset. */ Network.prototype.storePosition = function() { - console.log("storePosition is depricated: use .storePositions() from now on.") + console.log("storePosition is deprecated: use .storePositions() from now on.") this.storePositions(); }; diff --git a/lib/network/mixins/ManipulationMixin.js b/lib/network/mixins/ManipulationMixin.js index ed405336..3486c072 100644 --- a/lib/network/mixins/ManipulationMixin.js +++ b/lib/network/mixins/ManipulationMixin.js @@ -393,7 +393,7 @@ exports._selectControlNode = function(pointer) { * @private */ exports._controlNodeDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) { this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x); this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y); @@ -459,7 +459,7 @@ exports._handleConnect = function(pointer) { this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag; this._handleOnDrag = function(event) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); var connectionEdge = this.edges['connectionEdge']; connectionEdge.to.x = this._XconvertDOMtoCanvas(pointer.x); connectionEdge.to.y = this._YconvertDOMtoCanvas(pointer.y); @@ -474,7 +474,7 @@ exports._handleConnect = function(pointer) { exports._finishConnect = function(event) { if (this._getSelectedNodeCount() == 1) { - var pointer = this._getPointer(event.gesture.center); + var pointer = this._getPointer(event.center); // restore the drag function this._handleOnDrag = this.cachedFunctions["_handleOnDrag"]; delete this.cachedFunctions["_handleOnDrag"]; diff --git a/lib/network/mixins/NavigationMixin.js b/lib/network/mixins/NavigationMixin.js index 01d92b51..ebccf581 100644 --- a/lib/network/mixins/NavigationMixin.js +++ b/lib/network/mixins/NavigationMixin.js @@ -1,11 +1,12 @@ var util = require('../../util'); +var hammerUtil = require('../../hammerUtil'); var Hammer = require('../../module/hammer'); exports._cleanNavigation = function() { // clean hammer bindings if (this.navigationHammers.existing.length != 0) { for (var i = 0; i < this.navigationHammers.existing.length; i++) { - this.navigationHammers.existing[i].dispose(); + this.navigationHammers.existing[i].destroy(); } this.navigationHammers.existing = []; } @@ -41,8 +42,10 @@ exports._loadNavigationElements = function() { this.navigationDivs[navigationDivs[i]].className = 'network-navigation ' + navigationDivs[i]; this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]); - var hammer = Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); - hammer.on('touch', this[navigationDivActions[i]].bind(this)); + var hammer = new Hammer(this.navigationDivs[navigationDivs[i]], {prevent_default: true}); + hammerUtil.onTouch(hammer, this[navigationDivActions[i]].bind(this)); + hammerUtil.onRelease(hammer, this._onRelease.bind(this)); + this.navigationHammers._new.push(hammer); } diff --git a/lib/util.js b/lib/util.js index 1cb61d2a..cb3b5e5e 100644 --- a/lib/util.js +++ b/lib/util.js @@ -454,7 +454,7 @@ exports.getType = function(object) { * in the browser page. */ exports.getAbsoluteLeft = function(elem) { - return elem.getBoundingClientRect().left + window.pageXOffset; + return elem.getBoundingClientRect().left; }; /** @@ -464,7 +464,7 @@ exports.getAbsoluteLeft = function(elem) { * in the browser page. */ exports.getAbsoluteTop = function(elem) { - return elem.getBoundingClientRect().top + window.pageYOffset; + return elem.getBoundingClientRect().top; }; /**