mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-04-06 15:30:59 +00:00
308 lines
No EOL
9.4 KiB
JavaScript
308 lines
No EOL
9.4 KiB
JavaScript
(function() {
|
|
|
|
var degreesToRadians = fabric.util.degreesToRadians;
|
|
|
|
fabric.util.object.extend(fabric.Object.prototype, /** @scope fabric.Object.prototype */ {
|
|
|
|
/**
|
|
* Returns true if object intersects with an area formed by 2 points
|
|
* @method intersectsWithRect
|
|
* @param {Object} selectionTL
|
|
* @param {Object} selectionBR
|
|
* @return {Boolean}
|
|
*/
|
|
intersectsWithRect: function(selectionTL, selectionBR) {
|
|
var oCoords = this.oCoords,
|
|
tl = new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
|
tr = new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
|
bl = new fabric.Point(oCoords.bl.x, oCoords.bl.y),
|
|
br = new fabric.Point(oCoords.br.x, oCoords.br.y);
|
|
|
|
var intersection = fabric.Intersection.intersectPolygonRectangle(
|
|
[tl, tr, br, bl],
|
|
selectionTL,
|
|
selectionBR
|
|
);
|
|
return intersection.status === 'Intersection';
|
|
},
|
|
|
|
/**
|
|
* Returns true if object intersects with another object
|
|
* @method intersectsWithObject
|
|
* @param {Object} other Object to test
|
|
* @return {Boolean}
|
|
*/
|
|
intersectsWithObject: function(other) {
|
|
// extracts coords
|
|
function getCoords(oCoords) {
|
|
return {
|
|
tl: new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
|
tr: new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
|
bl: new fabric.Point(oCoords.bl.x, oCoords.bl.y),
|
|
br: new fabric.Point(oCoords.br.x, oCoords.br.y)
|
|
};
|
|
}
|
|
var thisCoords = getCoords(this.oCoords),
|
|
otherCoords = getCoords(other.oCoords);
|
|
|
|
var intersection = fabric.Intersection.intersectPolygonPolygon(
|
|
[thisCoords.tl, thisCoords.tr, thisCoords.br, thisCoords.bl],
|
|
[otherCoords.tl, otherCoords.tr, otherCoords.br, otherCoords.bl]
|
|
);
|
|
|
|
return intersection.status === 'Intersection';
|
|
},
|
|
|
|
/**
|
|
* Returns true if object is fully contained within area of another object
|
|
* @method isContainedWithinObject
|
|
* @param {Object} other Object to test
|
|
* @return {Boolean}
|
|
*/
|
|
isContainedWithinObject: function(other) {
|
|
return this.isContainedWithinRect(other.oCoords.tl, other.oCoords.br);
|
|
},
|
|
|
|
/**
|
|
* Returns true if object is fully contained within area formed by 2 points
|
|
* @method isContainedWithinRect
|
|
* @param {Object} selectionTL
|
|
* @param {Object} selectionBR
|
|
* @return {Boolean}
|
|
*/
|
|
isContainedWithinRect: function(selectionTL, selectionBR) {
|
|
var oCoords = this.oCoords,
|
|
tl = new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
|
tr = new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
|
bl = new fabric.Point(oCoords.bl.x, oCoords.bl.y);
|
|
|
|
return tl.x > selectionTL.x
|
|
&& tr.x < selectionBR.x
|
|
&& tl.y > selectionTL.y
|
|
&& bl.y < selectionBR.y;
|
|
},
|
|
|
|
/**
|
|
* Returns width of an object's bounding rectangle
|
|
* @deprecated since 1.0.4
|
|
* @method getBoundingRectWidth
|
|
* @return {Number} width value
|
|
*/
|
|
getBoundingRectWidth: function() {
|
|
return this.getBoundingRect().width;
|
|
},
|
|
|
|
/**
|
|
* Returns height of an object's bounding rectangle
|
|
* @deprecated since 1.0.4
|
|
* @method getBoundingRectHeight
|
|
* @return {Number} height value
|
|
*/
|
|
getBoundingRectHeight: function() {
|
|
return this.getBoundingRect().height;
|
|
},
|
|
|
|
/**
|
|
* Returns coordinates of object's bounding rectangle (left, top, width, height)
|
|
* @method getBoundingRect
|
|
* @return {Object} Object with left, top, width, height properties
|
|
*/
|
|
getBoundingRect: function() {
|
|
this.oCoords || this.setCoords();
|
|
|
|
var xCoords = [this.oCoords.tl.x, this.oCoords.tr.x, this.oCoords.br.x, this.oCoords.bl.x];
|
|
var minX = fabric.util.array.min(xCoords);
|
|
var maxX = fabric.util.array.max(xCoords);
|
|
var width = Math.abs(minX - maxX);
|
|
|
|
var yCoords = [this.oCoords.tl.y, this.oCoords.tr.y, this.oCoords.br.y, this.oCoords.bl.y];
|
|
var minY = fabric.util.array.min(yCoords);
|
|
var maxY = fabric.util.array.max(yCoords);
|
|
var height = Math.abs(minY - maxY);
|
|
|
|
return {
|
|
left: minX,
|
|
top: minY,
|
|
width: width,
|
|
height: height
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Returns width of an object
|
|
* @method getWidth
|
|
* @return {Number} width value
|
|
*/
|
|
getWidth: function() {
|
|
return this.width * this.scaleX;
|
|
},
|
|
|
|
/**
|
|
* Returns height of an object
|
|
* @method getHeight
|
|
* @return {Number} height value
|
|
*/
|
|
getHeight: function() {
|
|
return this.height * this.scaleY;
|
|
},
|
|
|
|
/**
|
|
* Makes sure the scale is valid and modifies it if necessary
|
|
* @private
|
|
* @method _constrainScale
|
|
* @param {Number} value
|
|
* @return {Number}
|
|
*/
|
|
_constrainScale: function(value) {
|
|
if (Math.abs(value) < this.minScaleLimit) {
|
|
if (value < 0)
|
|
return -this.minScaleLimit;
|
|
else
|
|
return this.minScaleLimit;
|
|
}
|
|
|
|
return value;
|
|
},
|
|
|
|
/**
|
|
* Scales an object (equally by x and y)
|
|
* @method scale
|
|
* @param value {Number} scale factor
|
|
* @return {fabric.Object} thisArg
|
|
* @chainable
|
|
*/
|
|
scale: function(value) {
|
|
value = this._constrainScale(value);
|
|
|
|
if (value < 0) {
|
|
this.flipX = !this.flipX;
|
|
this.flipY = !this.flipY;
|
|
value *= -1;
|
|
}
|
|
|
|
this.scaleX = value;
|
|
this.scaleY = value;
|
|
this.setCoords();
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Scales an object to a given width, with respect to bounding box (scaling by x/y equally)
|
|
* @method scaleToWidth
|
|
* @param value {Number} new width value
|
|
* @return {fabric.Object} thisArg
|
|
* @chainable
|
|
*/
|
|
scaleToWidth: function(value) {
|
|
// adjust to bounding rect factor so that rotated shapes would fit as well
|
|
var boundingRectFactor = this.getBoundingRectWidth() / this.getWidth();
|
|
return this.scale(value / this.width / boundingRectFactor);
|
|
},
|
|
|
|
/**
|
|
* Scales an object to a given height, with respect to bounding box (scaling by x/y equally)
|
|
* @method scaleToHeight
|
|
* @param value {Number} new height value
|
|
* @return {fabric.Object} thisArg
|
|
* @chainable
|
|
*/
|
|
scaleToHeight: function(value) {
|
|
// adjust to bounding rect factor so that rotated shapes would fit as well
|
|
var boundingRectFactor = this.getBoundingRectHeight() / this.getHeight();
|
|
return this.scale(value / this.height / boundingRectFactor);
|
|
},
|
|
|
|
/**
|
|
* Sets corner position coordinates based on current angle, width and height
|
|
* @method setCoords
|
|
* @return {fabric.Object} thisArg
|
|
* @chainable
|
|
*/
|
|
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(this.currentHeight / this.currentWidth);
|
|
|
|
// 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: tl.x + (this.currentWidth/2 * cosTh),
|
|
y: tl.y + (this.currentWidth/2 * sinTh)
|
|
};
|
|
|
|
// debugging
|
|
|
|
// setTimeout(function() {
|
|
// canvas.contextTop.fillStyle = 'green';
|
|
// canvas.contextTop.fillRect(mb.x, mb.y, 3, 3);
|
|
// canvas.contextTop.fillRect(bl.x, bl.y, 3, 3);
|
|
// canvas.contextTop.fillRect(br.x, br.y, 3, 3);
|
|
// canvas.contextTop.fillRect(tl.x, tl.y, 3, 3);
|
|
// canvas.contextTop.fillRect(tr.x, tr.y, 3, 3);
|
|
// canvas.contextTop.fillRect(ml.x, ml.y, 3, 3);
|
|
// canvas.contextTop.fillRect(mr.x, mr.y, 3, 3);
|
|
// canvas.contextTop.fillRect(mt.x, mt.y, 3, 3);
|
|
// }, 50);
|
|
|
|
// clockwise
|
|
this.oCoords = { tl: tl, tr: tr, br: br, bl: bl, ml: ml, mt: mt, mr: mr, mb: mb, mtr: mtr };
|
|
|
|
// set coordinates of the draggable boxes in the corners used to scale/rotate the image
|
|
this._setCornerCoords();
|
|
|
|
return this;
|
|
}
|
|
});
|
|
})(); |