2011-03-06 19:50:44 -05:00
|
|
|
/*
|
|
|
|
* Paper.js
|
|
|
|
*
|
|
|
|
* This file is part of Paper.js, a JavaScript Vector Graphics Library,
|
|
|
|
* based on Scriptographer.org and designed to be largely API compatible.
|
2011-03-07 20:41:50 -05:00
|
|
|
* http://paperjs.org/
|
2011-03-06 19:50:44 -05:00
|
|
|
* http://scriptographer.org/
|
|
|
|
*
|
2011-03-07 20:41:50 -05:00
|
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
|
|
*
|
2011-03-06 19:50:44 -05:00
|
|
|
* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
|
|
|
|
* http://lehni.org/ & http://jonathanpuckey.com/
|
|
|
|
*
|
2011-03-07 20:41:50 -05:00
|
|
|
* All rights reserved.
|
2011-03-06 19:50:44 -05:00
|
|
|
*/
|
|
|
|
|
2011-03-04 08:34:31 -05:00
|
|
|
var Rectangle = this.Rectangle = Base.extend({
|
2011-02-11 08:40:36 -05:00
|
|
|
beans: true,
|
2011-02-13 13:52:17 -05:00
|
|
|
|
2011-03-06 07:15:15 -05:00
|
|
|
initialize: function(arg0, arg1, arg2, arg3) {
|
2011-02-13 11:26:24 -05:00
|
|
|
if (arguments.length == 1) {
|
2011-03-05 16:06:23 -05:00
|
|
|
// Use 0 as defaults, in case we're reading from a Point or Size
|
2011-03-06 07:15:15 -05:00
|
|
|
this.x = arg0.x || 0;
|
|
|
|
this.y = arg0.y || 0;
|
|
|
|
this.width = arg0.width || 0;
|
|
|
|
this.height = arg0.height || 0;
|
2011-02-13 11:26:24 -05:00
|
|
|
} else if (arguments.length == 2) {
|
2011-03-06 07:15:15 -05:00
|
|
|
if (arg1.x !== undefined) {
|
2011-02-07 13:28:09 -05:00
|
|
|
// new Rectangle(point1, point2)
|
2011-03-06 07:15:15 -05:00
|
|
|
var point1 = Point.read(arguments, 0, 1);
|
|
|
|
var point2 = Point.read(arguments, 1, 1);
|
2011-02-07 13:28:09 -05:00
|
|
|
this.x = point1.x;
|
|
|
|
this.y = point1.y;
|
|
|
|
this.width = point2.x - point1.x;
|
|
|
|
this.height = point2.y - point1.y;
|
2011-02-13 11:26:24 -05:00
|
|
|
if (this.width < 0) {
|
2011-02-07 13:28:09 -05:00
|
|
|
this.x = point2.x;
|
|
|
|
this.width = -this.width;
|
|
|
|
}
|
2011-02-13 11:26:24 -05:00
|
|
|
if (this.height < 0) {
|
2011-02-07 13:28:09 -05:00
|
|
|
this.y = point2.y;
|
|
|
|
this.height = -this.height;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// new Rectangle(point, size)
|
2011-03-06 07:15:15 -05:00
|
|
|
var point = Point.read(arguments, 0, 1);
|
|
|
|
var size = Size.read(arguments, 1, 1);
|
2011-02-07 13:28:09 -05:00
|
|
|
this.x = point.x;
|
|
|
|
this.y = point.y;
|
|
|
|
this.width = size.width;
|
|
|
|
this.height = size.height;
|
|
|
|
}
|
2011-02-13 11:26:24 -05:00
|
|
|
} else if (arguments.length == 4) {
|
2011-02-07 13:28:09 -05:00
|
|
|
// new Rectangle(x, y, width, height)
|
2011-03-06 07:15:15 -05:00
|
|
|
this.x = arg0;
|
|
|
|
this.y = arg1;
|
|
|
|
this.width = arg2;
|
|
|
|
this.height = arg3;
|
2011-02-07 13:28:09 -05:00
|
|
|
} else {
|
|
|
|
// new Rectangle()
|
|
|
|
this.x = this.y = this.width = this.height = 0;
|
|
|
|
}
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-28 14:14:10 -05:00
|
|
|
set: function(x, y, width, height) {
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-28 14:14:10 -05:00
|
|
|
},
|
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getPoint: function() {
|
2011-03-22 13:27:46 -04:00
|
|
|
return LinkedPoint.create(this, 'setPoint', this.x, this.y);
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-03-08 12:17:36 -05:00
|
|
|
setPoint: function(point) {
|
2011-03-13 13:31:00 -04:00
|
|
|
point = Point.read(arguments);
|
2011-02-07 13:28:09 -05:00
|
|
|
this.x = point.x;
|
|
|
|
this.y = point.y;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getSize: function() {
|
2011-03-03 12:07:12 -05:00
|
|
|
return Size.create(this.width, this.height);
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-03-08 12:17:36 -05:00
|
|
|
setSize: function(size) {
|
2011-03-13 13:31:00 -04:00
|
|
|
size = Size.read(arguments);
|
2011-02-07 13:28:09 -05:00
|
|
|
this.width = size.width;
|
|
|
|
this.height = size.height;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getLeft: function() {
|
|
|
|
return this.x;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setLeft: function(left) {
|
|
|
|
this.width -= left - this.x;
|
|
|
|
this.x = left;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getTop: function() {
|
|
|
|
return this.y;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setTop: function(top) {
|
|
|
|
this.height -= top - this.y;
|
|
|
|
this.y = top;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getRight: function() {
|
|
|
|
return this.x + this.width;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setRight: function(right) {
|
|
|
|
this.width = right - this.x;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getBottom: function() {
|
|
|
|
return this.y + this.height;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setBottom: function(bottom) {
|
|
|
|
this.height = bottom - this.y;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getCenterX: function() {
|
|
|
|
return this.x + this.width * 0.5;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setCenterX: function(x) {
|
|
|
|
this.x = x - this.width * 0.5;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getCenterY: function() {
|
|
|
|
return this.y + this.height * 0.5;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
setCenterY: function(y) {
|
|
|
|
this.y = y - this.height * 0.5;
|
2011-03-05 15:57:45 -05:00
|
|
|
return this;
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
getCenter: function() {
|
2011-03-22 13:27:46 -04:00
|
|
|
return LinkedPoint.create(this, 'setCenter',
|
2011-03-16 02:12:34 -04:00
|
|
|
this.getCenterX(), this.getCenterY());
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-03-08 12:17:36 -05:00
|
|
|
setCenter: function(point) {
|
2011-03-13 13:31:00 -04:00
|
|
|
point = Point.read(arguments);
|
2011-03-08 12:17:36 -05:00
|
|
|
return this.setCenterX(point.x).setCenterY(point.y);
|
2011-02-07 13:28:09 -05:00
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
clone: function() {
|
|
|
|
return new Rectangle(this);
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-03-08 12:17:36 -05:00
|
|
|
equals: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
2011-03-13 17:48:07 -04:00
|
|
|
return this.x == rect.x && this.y == rect.y
|
2011-02-07 13:28:09 -05:00
|
|
|
&& this.width == rect.width && this.height == rect.height;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
isEmpty: function() {
|
|
|
|
return this.width == 0 || this.height == 0;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
contains: function(rect) {
|
2011-02-13 11:26:24 -05:00
|
|
|
if (rect.width !== undefined) {
|
2011-02-07 13:28:09 -05:00
|
|
|
return rect.x >= this.x && rect.y >= this.y
|
|
|
|
&& rect.x + rect.width <= this.x + this.width
|
|
|
|
&& rect.y + rect.height <= this.y + this.height;
|
|
|
|
} else {
|
|
|
|
var point = Point.read(arguments);
|
|
|
|
return point.x >= this.x && point.y >= this.y
|
|
|
|
&& point.x <= this.x + this.width
|
|
|
|
&& point.y <= this.y + this.height;
|
|
|
|
}
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-03-08 12:17:36 -05:00
|
|
|
intersects: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
2011-03-13 17:48:07 -04:00
|
|
|
return rect.x + rect.width > this.x
|
2011-02-07 13:28:09 -05:00
|
|
|
&& rect.y + rect.height > this.y
|
|
|
|
&& rect.x < this.x + this.width
|
|
|
|
&& rect.y < this.y + this.height;
|
|
|
|
},
|
2011-02-13 14:21:56 -05:00
|
|
|
|
2011-04-28 09:44:05 -04:00
|
|
|
intersect: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
|
|
|
var x1 = Math.max(this.x, rect.x),
|
|
|
|
y1 = Math.max(this.y, rect.y),
|
|
|
|
x2 = Math.min(this.x + this.width, rect.x + rect.width),
|
|
|
|
y2 = Math.min(this.y + this.height, rect.y + rect.height);
|
|
|
|
return Rectangle.create(x1, y1, x2 - x1, y2 - y1);
|
|
|
|
},
|
|
|
|
|
|
|
|
unite: function(rect) {
|
|
|
|
rect = Rectangle.read(arguments);
|
|
|
|
var x1 = Math.min(this.x, rect.x),
|
|
|
|
y1 = Math.min(this.y, rect.y),
|
|
|
|
x2 = Math.max(this.x + this.width, rect.x + rect.width),
|
|
|
|
y2 = Math.max(this.y + this.height, rect.y + rect.height);
|
|
|
|
return Rectangle.create(x1, y1, x2 - x1, y2 - y1);
|
|
|
|
},
|
|
|
|
|
|
|
|
include: function(point) {
|
|
|
|
point = Point.read(arguments);
|
|
|
|
var x1 = Math.min(this.x, point.x),
|
|
|
|
y1 = Math.min(this.y, point.y),
|
|
|
|
x2 = Math.max(this.x + this.width, point.x),
|
|
|
|
y2 = Math.max(this.y + this.height, point.y);
|
|
|
|
return Rectangle.create(x1, y1, x2 - x1, y2 - y1);
|
|
|
|
},
|
|
|
|
|
2011-02-07 13:28:09 -05:00
|
|
|
toString: function() {
|
2011-05-04 14:42:50 -04:00
|
|
|
var format = Base.formatNumber;
|
|
|
|
return '{ x: ' + format(this.x)
|
|
|
|
+ ', y: ' + format(this.y)
|
|
|
|
+ ', width: ' + format(this.width)
|
|
|
|
+ ', height: ' + format(this.height)
|
2011-02-07 13:28:09 -05:00
|
|
|
+ ' }';
|
2011-03-06 13:45:56 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
statics: {
|
|
|
|
// See Point.create()
|
|
|
|
create: function(x, y, width, height) {
|
2011-03-06 16:02:57 -05:00
|
|
|
return new Rectangle(Rectangle.dont).set(x, y, width, height);
|
2011-03-06 13:45:56 -05:00
|
|
|
}
|
2011-02-07 13:28:09 -05:00
|
|
|
}
|
2011-03-07 06:58:00 -05:00
|
|
|
}, new function() {
|
2011-03-08 12:17:36 -05:00
|
|
|
return Base.each([
|
|
|
|
['Top', 'Left'], ['Top', 'Right'],
|
|
|
|
['Bottom', 'Left'], ['Bottom', 'Right'],
|
|
|
|
['Left', 'Center'], ['Top', 'Center'],
|
|
|
|
['Right', 'Center'], ['Bottom', 'Center']
|
|
|
|
],
|
2011-03-07 07:42:50 -05:00
|
|
|
function(parts, index) {
|
2011-03-16 02:12:34 -04:00
|
|
|
var part = parts.join('');
|
2011-03-07 06:58:00 -05:00
|
|
|
// find out if the first of the pair is an x or y property,
|
|
|
|
// by checking the first character for [R]ight or [L]eft;
|
2011-03-16 02:12:34 -04:00
|
|
|
var xFirst = /^[RL]/.test(part);
|
2011-03-07 06:58:00 -05:00
|
|
|
// Rename Center to CenterX or CenterY:
|
2011-03-07 11:49:24 -05:00
|
|
|
if (index >= 4)
|
|
|
|
parts[1] += xFirst ? 'Y' : 'X';
|
|
|
|
var x = parts[xFirst ? 0 : 1],
|
|
|
|
y = parts[xFirst ? 1 : 0],
|
|
|
|
getX = 'get' + x,
|
|
|
|
getY = 'get' + y,
|
|
|
|
setX = 'set' + x,
|
2011-03-22 13:15:56 -04:00
|
|
|
setY = 'set' + y,
|
|
|
|
get = 'get' + part,
|
|
|
|
set = 'set' + part;
|
|
|
|
this[get] = function() {
|
2011-03-22 13:27:46 -04:00
|
|
|
return LinkedPoint.create(this, set,
|
2011-03-16 02:12:34 -04:00
|
|
|
this[getX](), this[getY]());
|
2011-03-07 06:58:00 -05:00
|
|
|
};
|
2011-03-22 13:15:56 -04:00
|
|
|
this[set] = function(point) {
|
2011-03-13 13:31:00 -04:00
|
|
|
point = Point.read(arguments);
|
2011-03-22 13:15:56 -04:00
|
|
|
// Note: call chaining happens here.
|
|
|
|
return this[setX](point.x)[setY](point.y);
|
2011-03-07 06:58:00 -05:00
|
|
|
};
|
|
|
|
}, { beans: true });
|
2011-02-13 11:26:24 -05:00
|
|
|
});
|
2011-03-16 18:32:46 -04:00
|
|
|
|
2011-03-22 13:27:46 -04:00
|
|
|
/**
|
|
|
|
* An internal version of Rectangle that notifies its owner of each change
|
|
|
|
* through setting itself again on the setter that corresponds to the getter
|
|
|
|
* that produced this LinkedRectangle. See uses of LinkedRectangle.create()
|
|
|
|
* Note: This prototype is not exported.
|
|
|
|
*/
|
|
|
|
var LinkedRectangle = Rectangle.extend({
|
2011-03-16 18:32:46 -04:00
|
|
|
beans: true,
|
|
|
|
|
|
|
|
set: function(x, y, width, height) {
|
|
|
|
this._x = x;
|
|
|
|
this._y = y;
|
|
|
|
this._width = width;
|
|
|
|
this._height = height;
|
2011-03-22 13:27:46 -04:00
|
|
|
if (this._owner)
|
|
|
|
this._owner[this._set](this);
|
2011-03-16 18:32:46 -04:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
statics: {
|
|
|
|
/**
|
|
|
|
* Provide a faster creator for Points out of two coordinates that
|
|
|
|
* does not rely on Point#initialize at all. This speeds up all math
|
|
|
|
* operations a lot.
|
|
|
|
*/
|
2011-03-22 13:27:46 -04:00
|
|
|
create: function(owner, set, x, y, width, height) {
|
|
|
|
var rect = new LinkedRectangle(LinkedRectangle.dont).set(x, y,
|
2011-03-16 18:32:46 -04:00
|
|
|
width, height);
|
2011-03-22 13:27:46 -04:00
|
|
|
rect._owner = owner;
|
2011-03-16 18:32:46 -04:00
|
|
|
rect._set = set;
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
}
|
2011-03-22 13:15:56 -04:00
|
|
|
}, new function() {
|
|
|
|
var proto = Rectangle.prototype;
|
|
|
|
|
|
|
|
return Base.each(['x', 'y', 'width', 'height'], function(key) {
|
|
|
|
var part = Base.capitalize(key);
|
|
|
|
var internal = '_' + key;
|
|
|
|
this['get' + part] = function() {
|
|
|
|
return this[internal];
|
2011-05-02 06:23:42 -04:00
|
|
|
};
|
2011-03-22 13:15:56 -04:00
|
|
|
|
|
|
|
this['set' + part] = function(value) {
|
|
|
|
this[internal] = value;
|
|
|
|
// Check if this setter is called from another one which sets
|
|
|
|
// _dontNotify, as it will notify itself
|
|
|
|
if (!this._dontNotify)
|
2011-03-22 13:27:46 -04:00
|
|
|
this._owner[this._set](this);
|
2011-05-02 06:23:42 -04:00
|
|
|
};
|
2011-03-22 13:15:56 -04:00
|
|
|
}, Base.each(['Point', 'Size', 'Center',
|
|
|
|
'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY',
|
|
|
|
'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight',
|
|
|
|
'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'],
|
|
|
|
function(key) {
|
|
|
|
var name = 'set' + key;
|
|
|
|
this[name] = function(value) {
|
|
|
|
// Make sure the above setters of x, y, width, height do not
|
2011-03-22 13:27:46 -04:00
|
|
|
// each notify the owner, as we're going to take care of this
|
2011-03-22 13:15:56 -04:00
|
|
|
// afterwards here, only once per change.
|
|
|
|
this._dontNotify = true;
|
|
|
|
proto[name].apply(this, arguments);
|
|
|
|
delete this._dontNotify;
|
2011-03-22 13:27:46 -04:00
|
|
|
this._owner[this._set](this);
|
2011-03-22 13:15:56 -04:00
|
|
|
return this;
|
2011-05-02 06:23:42 -04:00
|
|
|
};
|
2011-03-22 13:15:56 -04:00
|
|
|
}, { beans: true })
|
|
|
|
);
|
2011-03-16 18:32:46 -04:00
|
|
|
});
|