2011-03-06 19:50:44 -05:00
|
|
|
/*
|
|
|
|
* Paper.js
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-03-06 19:50:44 -05:00
|
|
|
* 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-06-30 06:01:51 -04:00
|
|
|
*
|
2011-03-06 19:50:44 -05:00
|
|
|
* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
|
|
|
|
* http://lehni.org/ & http://jonathanpuckey.com/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-07-01 06:17:45 -04:00
|
|
|
* Distributed under the MIT license. See LICENSE file for details.
|
|
|
|
*
|
2011-03-07 20:41:50 -05:00
|
|
|
* All rights reserved.
|
2011-03-06 19:50:44 -05:00
|
|
|
*/
|
|
|
|
|
2011-02-17 15:04:02 -05:00
|
|
|
Path.inject({ statics: new function() {
|
2011-02-17 09:55:26 -05:00
|
|
|
var kappa = 2 / 3 * (Math.sqrt(2) - 1);
|
|
|
|
|
|
|
|
var ovalSegments = [
|
|
|
|
new Segment([0, 0.5], [0, kappa ], [0, -kappa]),
|
|
|
|
new Segment([0.5, 0], [-kappa, 0], [kappa, 0 ]),
|
|
|
|
new Segment([1, 0.5], [0, -kappa], [0, kappa ]),
|
|
|
|
new Segment([0.5, 1], [kappa, 0 ], [-kappa, 0])
|
|
|
|
];
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-06-22 18:58:50 -04:00
|
|
|
return /** @lends Path */{
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
2011-05-30 11:13:19 -04:00
|
|
|
* {@grouptitle Shaped Paths}
|
2011-06-27 06:31:39 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* Creates a Path Item with two anchor points forming a line.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} pt1 the first anchor point of the path
|
|
|
|
* @param {Point} pt2 the second anchor point of the path
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var from = new Point(20, 20);
|
|
|
|
* var to = new Point(100, 100);
|
|
|
|
* var path = new Path.Line(from, to);
|
|
|
|
* path.strokeColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-02-17 09:55:26 -05:00
|
|
|
Line: function() {
|
2011-03-13 13:31:00 -04:00
|
|
|
var step = Math.floor(arguments.length / 2);
|
|
|
|
return new Path(
|
|
|
|
Segment.read(arguments, 0, step),
|
|
|
|
Segment.read(arguments, step, step)
|
|
|
|
);
|
2011-02-17 09:55:26 -05:00
|
|
|
},
|
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates a rectangle shaped Path Item from the passed point and size.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:17:35 -04:00
|
|
|
* @name Path.Rectangle
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} point
|
|
|
|
* @param {Size} size
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var point = new Point(100, 100);
|
|
|
|
* var size = new Size(100, 100);
|
|
|
|
* var rectangle = new Rectangle(point, size);
|
|
|
|
* var path = new Path.Rectangle(rectangle);
|
|
|
|
* path.strokeColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Creates a rectangle shaped Path Item from the passed points. These do not
|
|
|
|
* necessarily need to be the top left and bottom right corners, the
|
|
|
|
* constructor figures out how to fit a rectangle between them.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-27 20:17:35 -04:00
|
|
|
* @name Path.Rectangle
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} point1 The first point defining the rectangle
|
|
|
|
* @param {Point} point2 The second point defining the rectangle
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var point = new Point(100, 100);
|
|
|
|
* var point2 = new Point(200, 300);
|
|
|
|
* var path = new Path.Rectangle(point, point2);
|
|
|
|
* path.strokeColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Creates a rectangle shaped Path Item from the passed abstract
|
|
|
|
* {@link Rectangle}.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @param {Rectangle} rect
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @example
|
2011-05-30 11:13:19 -04:00
|
|
|
* var point = new Point(100, 100);
|
|
|
|
* var size = new Size(100, 100);
|
|
|
|
* var rectangle = new Rectangle(point, size);
|
2011-05-23 08:33:22 -04:00
|
|
|
* var path = new Path.Rectangle(rectangle);
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*/
|
2011-03-08 12:20:30 -05:00
|
|
|
Rectangle: function(rect) {
|
2011-03-13 13:31:00 -04:00
|
|
|
rect = Rectangle.read(arguments);
|
2011-08-16 07:39:37 -04:00
|
|
|
var left = rect.x,
|
2011-12-19 07:16:06 -05:00
|
|
|
top = rect.y,
|
2011-08-16 07:39:37 -04:00
|
|
|
right = left + rect.width,
|
|
|
|
bottom = top + rect.height,
|
|
|
|
path = new Path();
|
|
|
|
path._add([
|
|
|
|
new Segment(Point.create(left, bottom)),
|
|
|
|
new Segment(Point.create(left, top)),
|
|
|
|
new Segment(Point.create(right, top)),
|
|
|
|
new Segment(Point.create(right, bottom))
|
|
|
|
]);
|
2011-05-04 13:42:40 -04:00
|
|
|
path._closed = true;
|
2011-02-17 09:55:26 -05:00
|
|
|
return path;
|
|
|
|
},
|
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates a rectangular Path Item with rounded corners.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Rectangle} rect
|
|
|
|
* @param {Size} size the size of the rounded corners
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var point = new Point(100, 100);
|
|
|
|
* var size = new Size(100, 100);
|
|
|
|
* var rectangle = new Rectangle(point, size);
|
|
|
|
* var cornerSize = new Size(30, 30);
|
|
|
|
* var path = new Path.RoundRectangle(rectangle, cornerSize);
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-03-08 12:20:30 -05:00
|
|
|
RoundRectangle: function(rect, size) {
|
2011-02-17 09:55:26 -05:00
|
|
|
if (arguments.length == 2) {
|
2011-03-06 13:46:28 -05:00
|
|
|
rect = Rectangle.read(arguments, 0, 1);
|
|
|
|
size = Size.read(arguments, 1, 1);
|
|
|
|
} else if (arguments.length == 6) {
|
|
|
|
rect = Rectangle.read(arguments, 0, 4);
|
|
|
|
size = Size.read(arguments, 4, 2);
|
2011-02-17 09:55:26 -05:00
|
|
|
}
|
2011-08-16 07:52:18 -04:00
|
|
|
size = Size.min(size, rect.getSize(true).divide(2));
|
2011-03-08 12:20:30 -05:00
|
|
|
var path = new Path(),
|
|
|
|
uSize = size.multiply(kappa * 2),
|
2011-08-16 07:52:18 -04:00
|
|
|
bl = rect.getBottomLeft(true),
|
|
|
|
tl = rect.getTopLeft(true),
|
|
|
|
tr = rect.getTopRight(true),
|
|
|
|
br = rect.getBottomRight(true);
|
2011-05-04 13:42:40 -04:00
|
|
|
path._add([
|
|
|
|
new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]),
|
|
|
|
new Segment(bl.subtract(0, size.height), [0, uSize.height], null),
|
2011-02-17 09:55:26 -05:00
|
|
|
|
2011-05-04 13:42:40 -04:00
|
|
|
new Segment(tl.add(0, size.height), null, [0, -uSize.height]),
|
|
|
|
new Segment(tl.add(size.width, 0), [-uSize.width, 0], null),
|
2011-02-17 09:55:26 -05:00
|
|
|
|
2011-05-04 13:42:40 -04:00
|
|
|
new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]),
|
|
|
|
new Segment(tr.add(0, size.height), [0, -uSize.height], null),
|
2011-02-17 09:55:26 -05:00
|
|
|
|
2011-05-04 13:42:40 -04:00
|
|
|
new Segment(br.subtract(0, size.height), null, [0, uSize.height]),
|
|
|
|
new Segment(br.subtract(size.width, 0), [uSize.width, 0], null)
|
|
|
|
]);
|
|
|
|
path._closed = true;
|
2011-02-17 09:55:26 -05:00
|
|
|
return path;
|
|
|
|
},
|
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates an oval shaped Path Item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Rectangle} rect
|
2011-05-31 08:28:42 -04:00
|
|
|
* @param {Boolean} [circumscribed=false] when set to {@code true} the
|
2011-05-23 08:33:22 -04:00
|
|
|
* oval shaped path will be created so the rectangle fits into
|
2011-05-31 08:28:42 -04:00
|
|
|
* it. When set to {@code false} the oval path will fit within
|
|
|
|
* the rectangle.
|
2011-05-23 08:33:22 -04:00
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var topLeft = new Point(100, 100);
|
|
|
|
* var size = new Size(150, 100);
|
|
|
|
* var rectangle = new Rectangle(topLeft, size);
|
|
|
|
* var path = new Path.Oval(rectangle);
|
|
|
|
* path.fillColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-03-08 12:20:30 -05:00
|
|
|
Oval: function(rect) {
|
2011-03-13 13:31:00 -04:00
|
|
|
rect = Rectangle.read(arguments);
|
2011-03-06 13:46:28 -05:00
|
|
|
var path = new Path(),
|
2011-08-16 07:52:18 -04:00
|
|
|
point = rect.getPoint(true),
|
|
|
|
size = rect.getSize(true),
|
2011-05-04 13:42:40 -04:00
|
|
|
segments = new Array(4);
|
2011-02-17 09:55:26 -05:00
|
|
|
for (var i = 0; i < 4; i++) {
|
|
|
|
var segment = ovalSegments[i];
|
2011-05-04 13:42:40 -04:00
|
|
|
segments[i] = new Segment(
|
2011-08-16 07:52:18 -04:00
|
|
|
segment._point.multiply(size).add(point),
|
2011-03-06 05:57:14 -05:00
|
|
|
segment._handleIn.multiply(size),
|
|
|
|
segment._handleOut.multiply(size)
|
2011-05-04 13:42:40 -04:00
|
|
|
);
|
2011-02-17 09:55:26 -05:00
|
|
|
}
|
2011-05-04 13:42:40 -04:00
|
|
|
path._add(segments);
|
|
|
|
path._closed = true;
|
2011-02-17 09:55:26 -05:00
|
|
|
return path;
|
|
|
|
},
|
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates a circle shaped Path Item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} center the center point of the circle
|
2011-05-27 15:21:49 -04:00
|
|
|
* @param {Number} radius the radius of the circle
|
2011-05-23 08:33:22 -04:00
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var path = new Path.Circle(new Point(100, 100), 50);
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-03-08 12:20:30 -05:00
|
|
|
Circle: function(center, radius) {
|
2011-02-17 09:55:26 -05:00
|
|
|
if (arguments.length == 3) {
|
2011-03-08 12:20:30 -05:00
|
|
|
center = Point.read(arguments, 0, 2);
|
2011-02-17 09:55:26 -05:00
|
|
|
radius = arguments[2];
|
|
|
|
} else {
|
2011-03-08 12:20:30 -05:00
|
|
|
center = Point.read(arguments, 0, 1);
|
2011-02-17 09:55:26 -05:00
|
|
|
}
|
|
|
|
return Path.Oval(new Rectangle(center.subtract(radius),
|
2011-08-16 07:52:31 -04:00
|
|
|
Size.create(radius * 2, radius * 2)));
|
2011-02-17 09:55:26 -05:00
|
|
|
},
|
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates a circular arc shaped Path Item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} from the starting point of the circular arc
|
|
|
|
* @param {Point} through the point the arc passes through
|
|
|
|
* @param {Point} to the end point of the arc
|
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var start = new Point(0, 0);
|
|
|
|
* var through = new Point(100, 100);
|
|
|
|
* var to = new Point(200, 150);
|
|
|
|
* var path = new Path.Arc(start, through, to);
|
|
|
|
* path.strokeColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-02-17 09:55:26 -05:00
|
|
|
Arc: function(from, through, to) {
|
|
|
|
var path = new Path();
|
|
|
|
path.moveTo(from);
|
|
|
|
path.arcTo(through, to);
|
|
|
|
return path;
|
2011-02-26 13:19:02 -05:00
|
|
|
},
|
2011-03-03 17:45:17 -05:00
|
|
|
|
2011-05-23 08:33:22 -04:00
|
|
|
/**
|
|
|
|
* Creates a regular polygon shaped Path Item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} center the center point of the polygon
|
2011-05-27 15:21:49 -04:00
|
|
|
* @param {Number} numSides the number of sides of the polygon
|
|
|
|
* @param {Number} radius the radius of the polygon
|
2011-05-23 08:33:22 -04:00
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* // Create a triangle shaped path
|
|
|
|
* var center = new Point(100, 100);
|
|
|
|
* var sides = 3;
|
|
|
|
* var radius = 50;
|
|
|
|
* var triangle = new Path.RegularPolygon(center, sides, radius);
|
|
|
|
* triangle.fillColor = 'black';
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* // Create a decahedron shaped path
|
|
|
|
* var center = new Point(100, 100);
|
|
|
|
* var sides = 10;
|
|
|
|
* var radius = 50;
|
|
|
|
* var decahedron = new Path.RegularPolygon(center, sides, radius);
|
|
|
|
* decahedron.fillColor = 'black';
|
2011-05-23 08:33:22 -04:00
|
|
|
*/
|
2011-02-26 13:19:02 -05:00
|
|
|
RegularPolygon: function(center, numSides, radius) {
|
2011-04-12 18:05:46 -04:00
|
|
|
center = Point.read(arguments, 0, 1);
|
2011-03-06 13:46:28 -05:00
|
|
|
var path = new Path(),
|
2011-05-04 13:42:40 -04:00
|
|
|
step = 360 / numSides,
|
2011-03-06 13:46:28 -05:00
|
|
|
three = !(numSides % 3),
|
|
|
|
vector = new Point(0, three ? -radius : radius),
|
2011-05-04 13:42:40 -04:00
|
|
|
offset = three ? -1 : 0.5,
|
|
|
|
segments = new Array(numSides);
|
2011-02-28 12:30:08 -05:00
|
|
|
for (var i = 0; i < numSides; i++) {
|
2011-05-04 13:42:40 -04:00
|
|
|
segments[i] = new Segment(center.add(
|
|
|
|
vector.rotate((i + offset) * step)));
|
2011-02-26 13:19:02 -05:00
|
|
|
}
|
2011-05-04 13:42:40 -04:00
|
|
|
path._add(segments);
|
|
|
|
path._closed = true;
|
2011-02-26 13:19:02 -05:00
|
|
|
return path;
|
2011-04-12 08:18:00 -04:00
|
|
|
},
|
2011-05-23 08:33:22 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a star shaped Path Item.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* The largest of {@code radius1} and {@code radius2} will be the outer
|
|
|
|
* radius of the star. The smallest of radius1 and radius2 will be the
|
|
|
|
* inner radius.
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-23 08:33:22 -04:00
|
|
|
* @param {Point} center the center point of the star
|
2011-05-27 15:21:49 -04:00
|
|
|
* @param {Number} numPoints the number of points of the star
|
|
|
|
* @param {Number} radius1
|
|
|
|
* @param {Number} radius2
|
2011-05-23 08:33:22 -04:00
|
|
|
* @return {Path} the newly created path
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2011-05-30 11:13:19 -04:00
|
|
|
* @example
|
|
|
|
* var center = new Point(100, 100);
|
|
|
|
* var points = 6;
|
|
|
|
* var radius1 = 20;
|
|
|
|
* var radius2 = 50;
|
|
|
|
* var path = new Path.Star(center, points, radius1, radius2);
|
|
|
|
* path.fillColor = 'black';
|
2011-06-30 06:01:51 -04:00
|
|
|
*/
|
2011-04-12 08:18:00 -04:00
|
|
|
Star: function(center, numPoints, radius1, radius2) {
|
2011-04-12 18:05:46 -04:00
|
|
|
center = Point.read(arguments, 0, 1);
|
2011-04-12 08:18:00 -04:00
|
|
|
numPoints *= 2;
|
2011-05-04 13:42:40 -04:00
|
|
|
var path = new Path(),
|
|
|
|
step = 360 / numPoints,
|
|
|
|
vector = new Point(0, -1),
|
|
|
|
segments = new Array(numPoints);
|
2011-04-12 08:18:00 -04:00
|
|
|
for (var i = 0; i < numPoints; i++) {
|
2011-05-04 13:42:40 -04:00
|
|
|
segments[i] = new Segment(center.add(
|
|
|
|
vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1)));
|
2011-04-12 08:18:00 -04:00
|
|
|
}
|
2011-05-04 13:42:40 -04:00
|
|
|
path._add(segments);
|
|
|
|
path._closed = true;
|
2011-04-12 08:18:00 -04:00
|
|
|
return path;
|
2011-02-17 09:55:26 -05:00
|
|
|
}
|
|
|
|
};
|
2011-02-17 15:04:02 -05:00
|
|
|
}});
|