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);
In 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.com/per-pixel-drag-drop/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With