Is it possible to capture object:over
in Fabric.js only if mouse is on the shape itself and not on the imaginary square that contains it?
I have a jsFiddle demo, which contains an U shape. You can see that even if i have the pointer inside the U and not touching any of the lines, it still detects it as a object:over
event.
Javascript:
var canvas = new fabric.Canvas("c1", {
isDrawingMode: false
});
canvas.loadFromJSON(objectsJson, function () {
canvas.renderAll();
});
canvas.on("object:over", function () {
console.log("object over");
});
canvas.on("object:out", function () {
console.log("object out");
});
// code to capture mouse over object while isDrawingMode = false
canvas.findTarget = (function (originalFn) {
return function () {
var target = originalFn.apply(this, arguments);
if (target) {
if (this._hoveredTarget !== target) {
canvas.fire('object:over', { target: target });
if (this._hoveredTarget) {
canvas.fire('object:out', { target: this._hoveredTarget });
}
this._hoveredTarget = target;
}
}
else if (this._hoveredTarget) {
canvas.fire('object:out', { target: this._hoveredTarget });
this._hoveredTarget = null;
}
return target;
};
})(canvas.findTarget);
Is it possible to capture object:over
in Fabric.js only if mouse is on the shape itself and not on the imaginary square that contains it?
I have a jsFiddle demo, which contains an U shape. You can see that even if i have the pointer inside the U and not touching any of the lines, it still detects it as a object:over
event.
Javascript:
var canvas = new fabric.Canvas("c1", {
isDrawingMode: false
});
canvas.loadFromJSON(objectsJson, function () {
canvas.renderAll();
});
canvas.on("object:over", function () {
console.log("object over");
});
canvas.on("object:out", function () {
console.log("object out");
});
// code to capture mouse over object while isDrawingMode = false
canvas.findTarget = (function (originalFn) {
return function () {
var target = originalFn.apply(this, arguments);
if (target) {
if (this._hoveredTarget !== target) {
canvas.fire('object:over', { target: target });
if (this._hoveredTarget) {
canvas.fire('object:out', { target: this._hoveredTarget });
}
this._hoveredTarget = target;
}
}
else if (this._hoveredTarget) {
canvas.fire('object:out', { target: this._hoveredTarget });
this._hoveredTarget = null;
}
return target;
};
})(canvas.findTarget);
Share
Improve this question
edited Feb 3, 2014 at 18:16
kangax
39.2k13 gold badges100 silver badges135 bronze badges
asked Feb 2, 2014 at 13:54
CatalinCatalin
11.7k19 gold badges80 silver badges152 bronze badges
3
-
1
You need
perPixelTargetFind
andtargetFindTolerance
(see this demo — fabricjs./per-pixel-drag-drop) – kangax Commented Feb 2, 2014 at 17:00 -
1
@kangax: Works perfect! although i think
targetFindTolerance
works only "inside" the element, not also outside .i've set it to a 100 to but still activates only when i "touch" the object. BTW, good gratulations for this awesome project you have made. It just works out-of-box! Awesome – Catalin Commented Feb 3, 2014 at 11:36 - perfect! glad you like it – kangax Commented Feb 3, 2014 at 18:16
1 Answer
Reset to default 2In fabric.js,
for each shape there would created virtual box and when you intersect with this virtual box, the binded event is triggered.
During the create of any shape on fabric.js,
this below function create the virtual box by creating various points eg:
top left, top right, bottom left, bottom right, middle left, middle right, middle bottom and middle top.
setCoords: function() {
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,
padding = this.padding,
theta = degreesToRadians(this.angle);
this.currentWidth = (this.width + strokeWidth) * this.scaleX + padding * 2;
this.currentHeight = (this.height + strokeWidth) * this.scaleY + padding * 2;
// If width is negative, make postive. Fixes path selection issue
if (this.currentWidth < 0) {
this.currentWidth = Math.abs(this.currentWidth);
}
var _hypotenuse = Math.sqrt(
Math.pow(this.currentWidth / 2, 2) +
Math.pow(this.currentHeight / 2, 2));
var _angle = Math.atan(isFinite(this.currentHeight / this.currentWidth) ? this.currentHeight / this.currentWidth : 0);
// offset added for rotate and scale actions
var offsetX = Math.cos(_angle + theta) * _hypotenuse,
offsetY = Math.sin(_angle + theta) * _hypotenuse,
sinTh = Math.sin(theta),
cosTh = Math.cos(theta);
var coords = this.getCenterPoint();
var tl = {
x: coords.x - offsetX,
y: coords.y - offsetY
};
var tr = {
x: tl.x + (this.currentWidth * cosTh),
y: tl.y + (this.currentWidth * sinTh)
};
var br = {
x: tr.x - (this.currentHeight * sinTh),
y: tr.y + (this.currentHeight * cosTh)
};
var bl = {
x: tl.x - (this.currentHeight * sinTh),
y: tl.y + (this.currentHeight * cosTh)
};
var ml = {
x: tl.x - (this.currentHeight/2 * sinTh),
y: tl.y + (this.currentHeight/2 * cosTh)
};
var mt = {
x: tl.x + (this.currentWidth/2 * cosTh),
y: tl.y + (this.currentWidth/2 * sinTh)
};
var mr = {
x: tr.x - (this.currentHeight/2 * sinTh),
y: tr.y + (this.currentHeight/2 * cosTh)
};
var mb = {
x: bl.x + (this.currentWidth/2 * cosTh),
y: bl.y + (this.currentWidth/2 * sinTh)
};
var mtr = {
x: mt.x,
y: mt.y
};
this.oCoords = {
// corners
tl: tl, tr: tr, br: br, bl: bl,
// middle
ml: ml, mt: mt, mr: mr, mb: mb,
// rotating point
mtr: mtr
};
// set coordinates of the draggable boxes in the corners used to scale/rotate the image
this._setCornerCoords && this._setCornerCoords();
return this;
}
So whenever you intersect with any of these 8 points by mouse, the attached event would be fired.
As I know fabric.js
, it does not provide the functionality you wanted.
UPDATE:-
As RaraituL said, the pixel detection is possible through perPixelTargetFind()
, you can get the example on here. http://fabricjs./per-pixel-drag-drop/