Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events in grouped object #2729

Closed
wants to merge 11 commits into from
88 changes: 44 additions & 44 deletions src/canvas.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,15 @@
* @param {fabric.Object} target Object to test against
* @return {Boolean} true if point is contained within an area of given object
*/
containsPoint: function (e, target) {
var pointer = this.getPointer(e, true),
xy = this._normalizePointer(target, pointer);
containsPoint: function (pointer, target) {

var xy;
if (target.group && target.group === this.getActiveGroup()) {
xy = this._normalizePointer(target.group, pointer);
}
else {
xy = { x: pointer.x, y: pointer.y };
}
// http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html
// http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
return (target.containsPoint(xy) || target._findTargetCorner(pointer));
Expand All @@ -274,24 +279,17 @@
* @private
*/
_normalizePointer: function (object, pointer) {
var activeGroup = this.getActiveGroup(),
isObjectInGroup = (
activeGroup &&
object.type !== 'group' &&
activeGroup.contains(object)),
lt, m;

if (isObjectInGroup) {
m = fabric.util.multiplyTransformMatrices(
this.viewportTransform,
activeGroup.calcTransformMatrix());

m = fabric.util.invertTransform(m);
pointer = fabric.util.transformPoint(pointer, m , false);
lt = fabric.util.transformPoint(activeGroup.getCenterPoint(), m , false);
pointer.x -= lt.x;
pointer.y -= lt.y;
}
var lt, m;

m = fabric.util.multiplyTransformMatrices(
this.viewportTransform,
object.calcTransformMatrix());

m = fabric.util.invertTransform(m);
pointer = fabric.util.transformPoint(pointer, m , false);
lt = fabric.util.transformPoint(object.getCenterPoint(), m , false);
pointer.x -= lt.x;
pointer.y -= lt.y;
return { x: pointer.x, y: pointer.y };
},

Expand Down Expand Up @@ -860,38 +858,37 @@
/**
* @private
*/
_isLastRenderedObject: function(e) {
_isLastRenderedObject: function(pointer) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is a shortcut to check last selected target before all. But why just with controls above overaly? i think it should be checked always.

var lastRendered = this.lastRenderedObjectWithControlsAboveOverlay;
return (
this.controlsAboveOverlay &&
this.lastRenderedObjectWithControlsAboveOverlay &&
this.lastRenderedObjectWithControlsAboveOverlay.visible &&
this.containsPoint(e, this.lastRenderedObjectWithControlsAboveOverlay) &&
this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(this.getPointer(e, true)));
lastRendered &&
lastRendered.visible &&
(this.containsPoint(pointer, lastRendered) ||
lastRendered._findTargetCorner(pointer)));
},

/**
* Method that determines what object we are clicking on
* @param {Event} e mouse event
* @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through
* @param {Boolean} skipGroup when true, ActiveGroup is skipped and only objects are traversed through
*/
findTarget: function (e, skipGroup) {
if (this.skipTargetFind) {
return;
}

if (this._isLastRenderedObject(e)) {
this.targets = [ ];
var pointer = this.getPointer(e, true);
if (this._isLastRenderedObject(pointer)) {
return this.lastRenderedObjectWithControlsAboveOverlay;
}

// first check current group (if one exists)
var activeGroup = this.getActiveGroup();
if (activeGroup && !skipGroup && this.containsPoint(e, activeGroup)) {
if (activeGroup && !skipGroup && this.containsPoint(pointer, activeGroup)) {
return activeGroup;
}

var target = this._searchPossibleTargets(e, skipGroup);
this._fireOverOutEvents(target, e);

var target = this._searchPossibleTargets(e, pointer, this._objects);
return target;
},

Expand Down Expand Up @@ -920,11 +917,11 @@
/**
* @private
*/
_checkTarget: function(e, obj, pointer) {
_checkTarget: function(pointer, obj) {
if (obj &&
obj.visible &&
obj.evented &&
this.containsPoint(e, obj)){
this.containsPoint(pointer, obj)){
if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {
var isTransparent = this.isTargetTransparent(obj, pointer.x, pointer.y);
if (!isTransparent) {
Expand All @@ -940,22 +937,24 @@
/**
* @private
*/
_searchPossibleTargets: function(e, skipGroup) {
_searchPossibleTargets: function(e, pointer, objects) {

// Cache all targets where their bounding box contains point.
var target,
pointer = this.getPointer(e, true),
i = this._objects.length;
var target, i = objects.length, normalizedPointer;
// Do not check for currently grouped objects, since we check the parent group itself.
// untill we call this function specifically to search inside the activeGroup
while (i--) {
if ((!this._objects[i].group || skipGroup) && this._checkTarget(e, this._objects[i], pointer)){
this.relatedTarget = this._objects[i];
target = this._objects[i];
if (this._checkTarget(pointer, objects[i])) {
target = objects[i];
this.targets.push(target);
if (target.type === 'group') {
normalizedPointer = this._normalizePointer(target, pointer);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i made normalizePointer callable explicity, outside the scope of an activeGroup

this._searchPossibleTargets(e, normalizedPointer, target._objects);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.relatedTarget was here, but undocumented as i can see. It gets override by canvas.targets that now will keep the list last found targets

break;
}
}

this._fireOverOutEvents(target, e);
return target;
},

Expand Down Expand Up @@ -1293,3 +1292,4 @@
*/
fabric.Element = fabric.Canvas;
})();
s

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably not be here :)

32 changes: 17 additions & 15 deletions src/mixins/canvas_events.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,8 @@
if (target) {
target.isMoving = false;
}

shouldRender && this.renderAll();

this._handleCursorAndEvent(e, target);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why mouseup is managed different from other events? it gets its own function to fire the events.

shouldRender && this.renderAll();
},

_handleCursorAndEvent: function(e, target) {
Expand All @@ -287,7 +285,9 @@
}, 50);

this.fire('mouse:up', { target: target, e: e });
target && target.fire('mouseup', { e: e });
for (var i = 0; i < this.targets.length; i++) {
this.targets[i].fire('mouseup', { e: e })
}
},

/**
Expand Down Expand Up @@ -352,8 +352,8 @@
this.fire('mouse:down', { e: e });

var target = this.findTarget(e);
if (typeof target !== 'undefined') {
target.fire('mousedown', { e: e, target: target });
for (var i = 0; i < this.targets.length; i++) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only way i could come out to manage one-click-many-targets events firing. Does it looks ok for you?

this.targets[i].fire('mousedown', { e: e })
}
},

Expand All @@ -371,8 +371,8 @@
this.fire('mouse:move', { e: e });

var target = this.findTarget(e);
if (typeof target !== 'undefined') {
target.fire('mousemove', { e: e, target: target });
for (var i = 0; i < this.targets.length; i++) {
this.targets[i].fire('mousemove', { e: e })
}
},

Expand All @@ -389,8 +389,8 @@
this.fire('mouse:up', { e: e });

var target = this.findTarget(e);
if (typeof target !== 'undefined') {
target.fire('mouseup', { e: e, target: target });
for (var i = 0; i < this.targets.length; i++) {
this.targets[i].fire('mouseup', { e: e })
}
},

Expand Down Expand Up @@ -422,7 +422,6 @@

var target = this.findTarget(e),
pointer = this.getPointer(e, true);

// save pointer for check in __onMouseUp event
this._previousPointer = pointer;

Expand All @@ -441,11 +440,12 @@
this._beforeTransform(e, target);
this._setupCurrentTransform(e, target);
}
// we must renderAll so that active image is placed on the top canvas
shouldRender && this.renderAll();

this.fire('mouse:down', { target: target, e: e });
target && target.fire('mousedown', { e: e });
for (var i = 0; i < this.targets.length; i++) {
this.targets[i].fire('mousedown', { e: e })
}
shouldRender && this.renderAll();
},

/**
Expand Down Expand Up @@ -572,7 +572,9 @@
}

this.fire('mouse:move', { target: target, e: e });
target && target.fire('mousemove', { e: e });
for (var i = 0; i < this.targets.length; i++) {
this.targets[i].fire('mousemove', { e: e })
}
},

/**
Expand Down
11 changes: 5 additions & 6 deletions src/mixins/canvas_grouping.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,17 @@
* @param {fabric.Object} target
*/
_handleGrouping: function (e, target) {

if (target === this.getActiveGroup()) {

// if it's a group, find target again, this time skipping group
var activeGroup = this.getActiveGroup();
if (target === activeGroup) {
// if it's a group, find target again, specifiy active group objects
target = this.findTarget(e, true);

// if even object is not found, bail out
if (!target || target.isType('group')) {
if (!target) {
return;
}
}
if (this.getActiveGroup()) {
if (activeGroup) {
this._updateActiveGroup(target, e);
}
else {
Expand Down
3 changes: 3 additions & 0 deletions src/mixins/object_geometry.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
* @return {Boolean} true if point is inside the object
*/
containsPoint: function(point) {
if (!this.oCoords) {
this.setCoords();
}
var lines = this._getImageLines(this.oCoords),
xPoints = this._findCrossPoints(point, lines);

Expand Down