Skip to content

Commit

Permalink
events drag (fabricjs#4421)
Browse files Browse the repository at this point in the history
added drag and drop events
  • Loading branch information
asturur authored Feb 24, 2018
1 parent 5135e30 commit 7cec1df
Show file tree
Hide file tree
Showing 6 changed files with 733 additions and 547 deletions.
7 changes: 5 additions & 2 deletions src/canvas.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas}
* @see {@link fabric.Canvas#initialize} for constructor definition
*
* @fires object:added
* @fires object:removed
* @fires object:modified
* @fires object:rotating
* @fires object:scaling
Expand All @@ -37,6 +35,11 @@
* @fires mouse:out
* @fires mouse:dblclick
*
* @fires dragover
* @fires dragenter
* @fires dragleave
* @fires drop
*
*/
fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {

Expand Down
128 changes: 106 additions & 22 deletions src/mixins/canvas_events.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
addListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter);
addListener(this.upperCanvasEl, 'wheel', this._onMouseWheel);
addListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu);

addListener(this.upperCanvasEl, 'dragover', this._onDragOver);
addListener(this.upperCanvasEl, 'dragenter', this._onDragEnter);
addListener(this.upperCanvasEl, 'dragleave', this._onDragLeave);
addListener(this.upperCanvasEl, 'drop', this._onDrop);
// touch events
addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown, { passive: false });
addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove, { passive: false });
Expand All @@ -74,7 +77,7 @@
* @private
*/
_bindEvents: function() {
if (this.eventsBinded) {
if (this.eventsBound) {
// for any reason we pass here twice we do not want to bind events twice.
return;
}
Expand All @@ -92,7 +95,11 @@
this._onMouseEnter = this._onMouseEnter.bind(this);
this._onContextMenu = this._onContextMenu.bind(this);
this._onDoubleClick = this._onDoubleClick.bind(this);
this.eventsBinded = true;
this._onDragOver = this._onDragOver.bind(this);
this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter');
this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave');
this._onDrop = this._simpleEventHandler.bind(this, 'drop');
this.eventsBound = true;
},

/**
Expand All @@ -110,6 +117,10 @@
removeListener(this.upperCanvasEl, 'doubleclick', this._onDoubleClick);
removeListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);
removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);
removeListener(this.upperCanvasEl, 'dragover', this._onDragOver);
removeListener(this.upperCanvasEl, 'dragenter', this._onDragEnter);
removeListener(this.upperCanvasEl, 'dragleave', this._onDragLeave);
removeListener(this.upperCanvasEl, 'drop', this._onDrop);

if (typeof eventjs !== 'undefined' && 'remove' in eventjs) {
eventjs.remove(this.upperCanvasEl, 'gesture', this._onGesture);
Expand Down Expand Up @@ -202,6 +213,17 @@
this.__onLongPress && this.__onLongPress(e, self);
},

/**
* prevent default to allow drop event to be fired
* @private
* @param {Event} [e] Event object fired on Event.js shake
*/
_onDragOver: function(e) {
e.preventDefault();
var target = this._simpleEventHandler('dragover', e);
this._fireEnterLeaveEvents(target, e);
},

/**
* @private
* @param {Event} e Event object fired on mousedown
Expand Down Expand Up @@ -378,6 +400,32 @@
shouldRender && this.requestRenderAll();
},

/**
* @private
* Handle event firing for target and subtargets
* @param {Event} e event from mouse
* @param {String} eventType event to fire (up, down or move)
* @return {Fabric.Object} target return the the target found, for internal reasons.
*/
_simpleEventHandler: function(eventType, e) {
var target = this.findTarget(e),
targets = this.targets,
options = {
e: e,
target: target,
subTargets: targets,
};
this.fire(eventType, options);
target && target.fire(eventType, options);
if (!targets) {
return target;
}
for (var i = 0; i < targets.length; i++) {
targets[i].fire(eventType, options);
}
return target;
},

/**
* @private
* Handle event firing for target and subtargets
Expand Down Expand Up @@ -663,28 +711,64 @@
},

/**
* Manage the mouseout, mouseover events for the fabric object on the canvas
* @param {Fabric.Object} target the target where the target from the mousemove event
* @param {Event} e Event object fired on mousemove
* @private
*/
_fireOverOutEvents: function(target, e) {
var overOpt, outOpt, hoveredTarget = this._hoveredTarget;
if (hoveredTarget !== target) {
overOpt = { e: e, target: target, previousTarget: this._hoveredTarget };
outOpt = { e: e, target: this._hoveredTarget, nextTarget: target };
this._hoveredTarget = target;
}
if (target) {
if (hoveredTarget !== target) {
if (hoveredTarget) {
this.fire('mouse:out', outOpt);
hoveredTarget.fire('mouseout', outOpt);
}
this.fire('mouse:over', overOpt);
target.fire('mouseover', overOpt);
}
}
else if (hoveredTarget) {
this.fire('mouse:out', outOpt);
hoveredTarget.fire('mouseout', outOpt);
this.fireSynteticInOutEvents(target, e, {
targetName: '_hoveredTarget',
canvasEvtOut: 'mouse:out',
evtOut: 'mouseout',
canvasEvtIn: 'mouse:over',
evtIn: 'mouseover',
});
},

/**
* Manage the dragEnter, dragLeave events for the fabric objects on the canvas
* @param {Fabric.Object} target the target where the target from the onDrag event
* @param {Event} e Event object fired on ondrag
* @private
*/
_fireEnterLeaveEvents: function(target, e) {
this.fireSynteticInOutEvents(target, e, {
targetName: '_draggedoverTarget',
evtOut: 'dragleave',
evtIn: 'dragenter',
});
},

/**
* Manage the syntetic in/out events for the fabric objects on the canvas
* @param {Fabric.Object} target the target where the target from the supported events
* @param {Event} e Event object fired
* @param {Object} config configuration for the function to work
* @param {String} config.targetName property on the canvas where the old target is stored
* @param {String} [config.canvasEvtOut] name of the event to fire at canvas level for out
* @param {String} config.evtOut name of the event to fire for out
* @param {String} [config.canvasEvtIn] name of the event to fire at canvas level for in
* @param {String} config.evtIn name of the event to fire for in
* @private
*/
fireSynteticInOutEvents: function(target, e, config) {
var inOpt, outOpt, oldTarget = this[config.targetName], outFires, inFires,
targetChanged = oldTarget !== target, canvasEvtIn = config.canvasEvtIn, canvasEvtOut = config.canvasEvtOut;
if (targetChanged) {
inOpt = { e: e, target: target, previousTarget: oldTarget };
outOpt = { e: e, target: oldTarget, nextTarget: target };
this[config.targetName] = target;
}
inFires = target && targetChanged;
outFires = oldTarget && targetChanged;
if (outFires) {
canvasEvtOut && this.fire(canvasEvtOut, outOpt);
oldTarget.fire(config.evtOut, outOpt);
}
if (inFires) {
canvasEvtIn && this.fire(canvasEvtIn, inOpt);
target.fire(config.evtIn, inOpt);
}
},

Expand Down
5 changes: 5 additions & 0 deletions src/shapes/object.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
* @fires mouseout
* @fires mousewheel
* @fires mousedblclick
*
* @fires dragover
* @fires dragenter
* @fires dragleave
* @fires drop
*/
fabric.Object = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.Object.prototype */ {

Expand Down
1 change: 1 addition & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ testrunner.run({
'./test/unit/intersection.js',
'./test/unit/stateful.js',
'./test/unit/textbox.js',
'./test/unit/canvas_events.js',
],
// tests: ['./test/unit/pattern.js'],
}, function(err, report) {
Expand Down
Loading

0 comments on commit 7cec1df

Please sign in to comment.