2013-04-07 12:49:34 -04:00
|
|
|
/*
|
2013-01-28 21:03:27 -05:00
|
|
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
2011-03-07 20:41:50 -05:00
|
|
|
* http://paperjs.org/
|
2011-06-30 06:01:51 -04:00
|
|
|
*
|
2015-12-27 12:09:25 -05:00
|
|
|
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
2014-01-03 19:47:16 -05:00
|
|
|
* http://scratchdisk.com/ & 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-06-22 18:56:05 -04:00
|
|
|
/**
|
|
|
|
* @name PathItem
|
2011-07-01 05:22:33 -04:00
|
|
|
*
|
2015-12-27 14:04:26 -05:00
|
|
|
* @class The PathItem class is the base for any items that describe paths and
|
|
|
|
* offer standardised methods for drawing and path manipulation, such as
|
|
|
|
* {@link Path} and {@link CompoundPath}.
|
2011-07-01 05:22:33 -04:00
|
|
|
*
|
2011-06-22 18:56:05 -04:00
|
|
|
* @extends Item
|
|
|
|
*/
|
2013-05-27 15:48:58 -04:00
|
|
|
var PathItem = Item.extend(/** @lends PathItem# */{
|
2014-08-16 13:24:54 -04:00
|
|
|
_class: 'PathItem',
|
2013-06-23 23:18:32 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
initialize: function PathItem() {
|
|
|
|
// Do nothing.
|
|
|
|
},
|
2013-05-27 18:55:44 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Returns all intersections between two {@link PathItem} items as an array
|
|
|
|
* of {@link CurveLocation} objects. {@link CompoundPath} items are also
|
|
|
|
* supported.
|
|
|
|
*
|
|
|
|
* @param {PathItem} path the other item to find the intersections with
|
2015-09-21 10:41:59 -04:00
|
|
|
* @param {Function} [include] a callback function that can be used to
|
2015-12-27 14:04:26 -05:00
|
|
|
* filter out undesired locations right while they are collected. When
|
|
|
|
* defined, it shall return {@true to include a location}.
|
2014-08-16 13:24:54 -04:00
|
|
|
* @return {CurveLocation[]} the locations of all intersection between the
|
2015-12-27 14:04:26 -05:00
|
|
|
* paths
|
2015-10-03 17:15:45 -04:00
|
|
|
* @see #getCrossings(path)
|
2014-08-16 13:24:54 -04:00
|
|
|
* @example {@paperscript} // Finding the intersections between two paths
|
|
|
|
* var path = new Path.Rectangle(new Point(30, 25), new Size(50, 50));
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* var secondPath = path.clone();
|
|
|
|
* var intersectionGroup = new Group();
|
|
|
|
*
|
|
|
|
* function onFrame(event) {
|
|
|
|
* secondPath.rotate(1);
|
|
|
|
*
|
|
|
|
* var intersections = path.getIntersections(secondPath);
|
|
|
|
* intersectionGroup.removeChildren();
|
|
|
|
*
|
|
|
|
* for (var i = 0; i < intersections.length; i++) {
|
|
|
|
* var intersectionPath = new Path.Circle({
|
|
|
|
* center: intersections[i].point,
|
|
|
|
* radius: 4,
|
|
|
|
* fillColor: 'red',
|
|
|
|
* parent: intersectionGroup
|
|
|
|
* });
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*/
|
2015-09-21 10:41:59 -04:00
|
|
|
getIntersections: function(path, include, _matrix, _returnFirst) {
|
2014-08-16 13:24:54 -04:00
|
|
|
// NOTE: For self-intersection, path is null. This means you can also
|
|
|
|
// just call path.getIntersections() without an argument to get self
|
|
|
|
// intersections.
|
2014-10-20 10:53:49 -04:00
|
|
|
// NOTE: The hidden argument _matrix is used internally to override the
|
|
|
|
// passed path's transformation matrix.
|
2015-09-18 11:31:23 -04:00
|
|
|
var self = this === path || !path, // self-intersections?
|
2014-08-16 13:24:54 -04:00
|
|
|
matrix1 = this._matrix.orNullIfIdentity(),
|
2015-09-09 01:28:08 -04:00
|
|
|
matrix2 = self ? matrix1
|
2015-10-20 09:18:09 -04:00
|
|
|
: (_matrix || path._matrix).orNullIfIdentity();
|
2014-10-20 10:53:49 -04:00
|
|
|
// First check the bounds of the two paths. If they don't intersect,
|
|
|
|
// we don't need to iterate through their curves.
|
2015-09-18 11:31:23 -04:00
|
|
|
if (!self && !this.getBounds(matrix1).touches(path.getBounds(matrix2)))
|
2015-10-20 09:18:09 -04:00
|
|
|
return [];
|
|
|
|
var curves1 = this.getCurves(),
|
|
|
|
curves2 = self ? curves1 : path.getCurves(),
|
|
|
|
length1 = curves1.length,
|
|
|
|
length2 = self ? length1 : curves2.length,
|
|
|
|
values2 = [],
|
2015-10-20 09:21:03 -04:00
|
|
|
arrays = [],
|
2015-10-20 09:18:09 -04:00
|
|
|
locations,
|
|
|
|
path;
|
2015-09-12 04:12:17 -04:00
|
|
|
// Cache values for curves2 as we re-iterate them for each in curves1.
|
2014-08-16 13:24:54 -04:00
|
|
|
for (var i = 0; i < length2; i++)
|
|
|
|
values2[i] = curves2[i].getValues(matrix2);
|
|
|
|
for (var i = 0; i < length1; i++) {
|
|
|
|
var curve1 = curves1[i],
|
2015-10-20 09:18:09 -04:00
|
|
|
values1 = self ? values2[i] : curve1.getValues(matrix1),
|
|
|
|
path1 = curve1.getPath();
|
|
|
|
// NOTE: Due to the nature of Curve._getIntersections(), we need to
|
|
|
|
// use separate location arrays per path1, to make sure the
|
|
|
|
// circularity checks are not getting confused by locations on
|
|
|
|
// separate paths. We are flattening the separate arrays at the end.
|
|
|
|
if (path1 !== path) {
|
|
|
|
path = path1;
|
|
|
|
locations = [];
|
2015-10-20 09:21:03 -04:00
|
|
|
arrays.push(locations);
|
2015-10-20 09:18:09 -04:00
|
|
|
}
|
2015-09-09 01:28:08 -04:00
|
|
|
if (self) {
|
2015-10-20 04:02:33 -04:00
|
|
|
// First check for self-intersections within the same curve.
|
|
|
|
Curve._getSelfIntersection(values1, curve1, locations, {
|
|
|
|
include: include,
|
|
|
|
// Only possible if there is only one closed curve:
|
|
|
|
startConnected: length1 === 1 &&
|
|
|
|
curve1.getPoint1().equals(curve1.getPoint2())
|
|
|
|
});
|
2014-08-16 13:24:54 -04:00
|
|
|
}
|
|
|
|
// Check for intersections with other curves. For self intersection,
|
|
|
|
// we can start at i + 1 instead of 0
|
2015-09-09 01:28:08 -04:00
|
|
|
for (var j = self ? i + 1 : 0; j < length2; j++) {
|
2015-08-25 05:45:28 -04:00
|
|
|
// There might be already one location from the above
|
|
|
|
// self-intersection check:
|
2015-09-18 11:31:23 -04:00
|
|
|
if (_returnFirst && locations.length)
|
2015-10-20 09:18:09 -04:00
|
|
|
return locations;
|
2015-09-12 04:12:17 -04:00
|
|
|
var curve2 = curves2[j];
|
2015-09-09 01:28:08 -04:00
|
|
|
// Avoid end point intersections on consecutive curves when
|
|
|
|
// self intersecting.
|
2015-10-20 04:02:33 -04:00
|
|
|
Curve._getIntersections(
|
2015-09-12 04:12:17 -04:00
|
|
|
values1, values2[j], curve1, curve2, locations,
|
2015-09-23 13:33:35 -04:00
|
|
|
{
|
2015-09-21 10:41:59 -04:00
|
|
|
include: include,
|
2015-09-12 04:12:17 -04:00
|
|
|
// Do not compare indices here to determine connection,
|
|
|
|
// since one array of curves can contain curves from
|
|
|
|
// separate sup-paths of a compound path.
|
2015-09-23 13:33:35 -04:00
|
|
|
startConnected: self && curve1.getPrevious() === curve2,
|
|
|
|
endConnected: self && curve1.getNext() === curve2
|
2015-09-21 10:41:59 -04:00
|
|
|
}
|
2014-08-16 13:24:54 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2015-10-20 09:18:09 -04:00
|
|
|
// Now flatten the list of location arrays to one array and return it.
|
|
|
|
locations = [];
|
2015-10-20 09:21:03 -04:00
|
|
|
for (var i = 0, l = arrays.length; i < l; i++) {
|
|
|
|
locations.push.apply(locations, arrays[i]);
|
2015-10-20 09:18:09 -04:00
|
|
|
}
|
2015-08-25 05:45:28 -04:00
|
|
|
return locations;
|
2015-09-18 11:31:23 -04:00
|
|
|
},
|
|
|
|
|
2015-10-03 17:15:45 -04:00
|
|
|
/**
|
2015-12-27 12:34:41 -05:00
|
|
|
* Returns all crossings between two {@link PathItem} items as an array of
|
|
|
|
* {@link CurveLocation} objects. {@link CompoundPath} items are also
|
|
|
|
* supported. Crossings are intersections where the paths actually are
|
|
|
|
* crossing each other, as opposed to simply touching.
|
2015-10-03 17:15:45 -04:00
|
|
|
*
|
|
|
|
* @param {PathItem} path the other item to find the crossings with
|
2015-12-27 12:34:41 -05:00
|
|
|
* @param {Boolean} includeOverlaps whether to also count overlaps as
|
2015-12-27 14:04:26 -05:00
|
|
|
* crossings
|
2015-10-03 17:15:45 -04:00
|
|
|
* @see #getIntersections(path)
|
|
|
|
*/
|
2015-12-27 12:34:41 -05:00
|
|
|
getCrossings: function(path, includeOverlaps) {
|
2015-09-21 10:41:59 -04:00
|
|
|
return this.getIntersections(path, function(inter) {
|
2015-11-03 19:19:20 -05:00
|
|
|
// Check overlap first since it's the cheaper test between the two.
|
2015-12-27 12:34:41 -05:00
|
|
|
return includeOverlaps && inter.isOverlap() || inter.isCrossing();
|
2015-09-21 10:41:59 -04:00
|
|
|
});
|
2014-08-16 13:24:54 -04:00
|
|
|
},
|
2013-12-29 07:06:25 -05:00
|
|
|
|
2014-10-20 12:00:07 -04:00
|
|
|
_asPathItem: function() {
|
|
|
|
// See Item#_asPathItem()
|
|
|
|
return this;
|
2014-10-20 11:00:18 -04:00
|
|
|
},
|
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* The path's geometry, formatted as SVG style path data.
|
|
|
|
*
|
|
|
|
* @name PathItem#getPathData
|
|
|
|
* @type String
|
|
|
|
* @bean
|
|
|
|
*/
|
2014-04-02 14:53:18 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
setPathData: function(data) {
|
|
|
|
// NOTE: #getPathData() is defined in CompoundPath / Path
|
|
|
|
// This is a very compact SVG Path Data parser that works both for Path
|
|
|
|
// and CompoundPath.
|
2013-02-28 22:13:46 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// First split the path data into parts of command-coordinates pairs
|
|
|
|
// Commands are any of these characters: mzlhvcsqta
|
|
|
|
var parts = data.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig),
|
|
|
|
coords,
|
|
|
|
relative = false,
|
|
|
|
previous,
|
|
|
|
control,
|
|
|
|
current = new Point(),
|
|
|
|
start = new Point();
|
2013-02-28 22:13:46 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
function getCoord(index, coord) {
|
|
|
|
var val = +coords[index];
|
|
|
|
if (relative)
|
|
|
|
val += current[coord];
|
|
|
|
return val;
|
|
|
|
}
|
2013-02-28 22:13:46 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
function getPoint(index) {
|
|
|
|
return new Point(
|
|
|
|
getCoord(index, 'x'),
|
|
|
|
getCoord(index + 1, 'y')
|
|
|
|
);
|
|
|
|
}
|
2013-02-28 22:13:46 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// First clear the previous content
|
|
|
|
this.clear();
|
2013-03-03 19:56:48 -05:00
|
|
|
|
2015-02-28 13:20:48 -05:00
|
|
|
for (var i = 0, l = parts && parts.length; i < l; i++) {
|
2014-08-16 13:24:54 -04:00
|
|
|
var part = parts[i],
|
|
|
|
command = part[0],
|
|
|
|
lower = command.toLowerCase();
|
|
|
|
// Match all coordinate values
|
|
|
|
coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g);
|
|
|
|
var length = coords && coords.length;
|
|
|
|
relative = command === lower;
|
|
|
|
if (previous === 'z' && !/[mz]/.test(lower))
|
|
|
|
this.moveTo(current = start);
|
|
|
|
switch (lower) {
|
|
|
|
case 'm':
|
|
|
|
case 'l':
|
|
|
|
var move = lower === 'm';
|
|
|
|
for (var j = 0; j < length; j += 2)
|
|
|
|
this[j === 0 && move ? 'moveTo' : 'lineTo'](
|
|
|
|
current = getPoint(j));
|
|
|
|
control = current;
|
|
|
|
if (move)
|
|
|
|
start = current;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
case 'v':
|
|
|
|
var coord = lower === 'h' ? 'x' : 'y';
|
|
|
|
for (var j = 0; j < length; j++) {
|
|
|
|
current[coord] = getCoord(j, coord);
|
|
|
|
this.lineTo(current);
|
|
|
|
}
|
|
|
|
control = current;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
for (var j = 0; j < length; j += 6) {
|
|
|
|
this.cubicCurveTo(
|
|
|
|
getPoint(j),
|
|
|
|
control = getPoint(j + 2),
|
|
|
|
current = getPoint(j + 4));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
// Smooth cubicCurveTo
|
|
|
|
for (var j = 0; j < length; j += 4) {
|
|
|
|
this.cubicCurveTo(
|
|
|
|
/[cs]/.test(previous)
|
|
|
|
? current.multiply(2).subtract(control)
|
|
|
|
: current,
|
|
|
|
control = getPoint(j),
|
|
|
|
current = getPoint(j + 2));
|
|
|
|
previous = lower;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
for (var j = 0; j < length; j += 4) {
|
|
|
|
this.quadraticCurveTo(
|
|
|
|
control = getPoint(j),
|
|
|
|
current = getPoint(j + 2));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
// Smooth quadraticCurveTo
|
|
|
|
for (var j = 0; j < length; j += 2) {
|
|
|
|
this.quadraticCurveTo(
|
|
|
|
control = (/[qt]/.test(previous)
|
|
|
|
? current.multiply(2).subtract(control)
|
|
|
|
: current),
|
|
|
|
current = getPoint(j));
|
|
|
|
previous = lower;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
for (var j = 0; j < length; j += 7) {
|
|
|
|
this.arcTo(current = getPoint(j + 5),
|
2015-01-05 15:47:15 -05:00
|
|
|
new Size(+coords[j], +coords[j + 1]),
|
2015-01-05 15:32:21 -05:00
|
|
|
+coords[j + 2], +coords[j + 4], +coords[j + 3]);
|
2014-08-16 13:24:54 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
this.closePath(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
previous = lower;
|
|
|
|
}
|
|
|
|
},
|
2013-06-19 11:22:08 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
_canComposite: function() {
|
2015-12-28 11:54:07 -05:00
|
|
|
// A path with only a fill or a stroke can be directly blended, but if
|
2014-08-16 13:24:54 -04:00
|
|
|
// it has both, it needs to be drawn into a separate canvas first.
|
|
|
|
return !(this.hasFill() && this.hasStroke());
|
|
|
|
},
|
2013-10-29 12:57:25 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
_contains: function(point) {
|
|
|
|
// NOTE: point is reverse transformed by _matrix, so we don't need to
|
|
|
|
// apply here.
|
2014-02-20 13:50:37 -05:00
|
|
|
/*#*/ if (__options.nativeContains || !__options.booleanOperations) {
|
2014-08-16 13:24:54 -04:00
|
|
|
// To compare with native canvas approach:
|
|
|
|
var ctx = CanvasProvider.getContext(1, 1);
|
|
|
|
// Use dontFinish to tell _draw to only produce geometries for hit-test.
|
|
|
|
this._draw(ctx, new Base({ dontFinish: true }));
|
2015-12-24 10:32:08 -05:00
|
|
|
var res = ctx.isPointInPath(point.x, point.y, this.getFillRule());
|
2014-08-16 13:24:54 -04:00
|
|
|
CanvasProvider.release(ctx);
|
|
|
|
return res;
|
2014-02-20 13:50:37 -05:00
|
|
|
/*#*/ } else { // !__options.nativeContains && __options.booleanOperations
|
2015-12-28 05:58:51 -05:00
|
|
|
// Check the transformed point against the untransformed (internal)
|
|
|
|
// handle bounds, which is the fastest rough bounding box to calculate
|
|
|
|
// for a quick check before calculating the actual winding.
|
|
|
|
var winding = point.isInside(this.getInternalHandleBounds())
|
2015-12-30 14:13:55 -05:00
|
|
|
&& this._getWinding(point);
|
2015-12-24 10:32:08 -05:00
|
|
|
return !!(this.getFillRule() === 'evenodd' ? winding & 1 : winding);
|
2014-02-20 13:50:37 -05:00
|
|
|
/*#*/ } // !__options.nativeContains && __options.booleanOperations
|
2014-08-16 13:24:54 -04:00
|
|
|
}
|
2013-12-29 07:29:54 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Smooth bezier curves without changing the amount of segments or their
|
|
|
|
* points, by only smoothing and adjusting their handle points, for both
|
|
|
|
* open ended and closed paths.
|
|
|
|
*
|
|
|
|
* @name PathItem#smooth
|
|
|
|
* @function
|
|
|
|
*
|
|
|
|
* @example {@paperscript}
|
|
|
|
* // Smoothing a closed shape:
|
|
|
|
*
|
|
|
|
* // Create a rectangular path with its top-left point at
|
|
|
|
* // {x: 30, y: 25} and a size of {width: 50, height: 50}:
|
|
|
|
* var path = new Path.Rectangle(new Point(30, 25), new Size(50, 50));
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* // Select the path, so we can see its handles:
|
|
|
|
* path.fullySelected = true;
|
|
|
|
*
|
|
|
|
* // Create a copy of the path and move it 100pt to the right:
|
|
|
|
* var copy = path.clone();
|
|
|
|
* copy.position.x += 100;
|
|
|
|
*
|
|
|
|
* // Smooth the segments of the copy:
|
|
|
|
* copy.smooth();
|
|
|
|
*
|
|
|
|
* @example {@paperscript height=220}
|
|
|
|
* var path = new Path();
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* path.add(new Point(30, 50));
|
|
|
|
*
|
|
|
|
* var y = 5;
|
|
|
|
* var x = 3;
|
|
|
|
*
|
|
|
|
* for (var i = 0; i < 28; i++) {
|
|
|
|
* y *= -1.1;
|
|
|
|
* x *= 1.1;
|
|
|
|
* path.lineBy(x, y);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Create a copy of the path and move it 100pt down:
|
|
|
|
* var copy = path.clone();
|
|
|
|
* copy.position.y += 120;
|
|
|
|
*
|
|
|
|
* // Set its stroke color to red:
|
|
|
|
* copy.strokeColor = 'red';
|
|
|
|
*
|
|
|
|
* // Smooth the segments of the copy:
|
|
|
|
* copy.smooth();
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* {@grouptitle Postscript Style Drawing Commands}
|
|
|
|
*
|
|
|
|
* On a normal empty {@link Path}, the point is simply added as the path's
|
|
|
|
* first segment. If called on a {@link CompoundPath}, a new {@link Path} is
|
|
|
|
* created as a child and the point is added as its first segment.
|
|
|
|
*
|
|
|
|
* @name PathItem#moveTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} point
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document #lineTo()
|
|
|
|
/**
|
|
|
|
* @name PathItem#lineTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} point
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Adds a cubic bezier curve to the path, defined by two handles and a to
|
|
|
|
* point.
|
|
|
|
*
|
|
|
|
* @name PathItem#cubicCurveTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} handle1
|
|
|
|
* @param {Point} handle2
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Adds a quadratic bezier curve to the path, defined by a handle and a to
|
|
|
|
* point.
|
|
|
|
*
|
|
|
|
* @name PathItem#quadraticCurveTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} handle
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document PathItem#curveTo() 'paramater' param.
|
|
|
|
/**
|
|
|
|
* Draws a curve from the position of the last segment point in the path
|
2015-12-27 12:09:25 -05:00
|
|
|
* that goes through the specified `through` point, to the specified `to`
|
|
|
|
* point by adding one segment to the path.
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @name PathItem#curveTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} through the point through which the curve should go
|
|
|
|
* @param {Point} to the point where the curve should end
|
|
|
|
* @param {Number} [parameter=0.5]
|
|
|
|
*
|
|
|
|
* @example {@paperscript height=300}
|
|
|
|
* // Interactive example. Move your mouse around the view below:
|
|
|
|
*
|
|
|
|
* var myPath;
|
|
|
|
* function onMouseMove(event) {
|
|
|
|
* // If we created a path before, remove it:
|
|
|
|
* if (myPath) {
|
|
|
|
* myPath.remove();
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Create a new path and add a segment point to it
|
|
|
|
* // at {x: 150, y: 150):
|
|
|
|
* myPath = new Path();
|
|
|
|
* myPath.add(150, 150);
|
|
|
|
*
|
|
|
|
* // Draw a curve through the position of the mouse to 'toPoint'
|
|
|
|
* var toPoint = new Point(350, 150);
|
|
|
|
* myPath.curveTo(event.point, toPoint);
|
|
|
|
*
|
|
|
|
* // Select the path, so we can see its segments:
|
|
|
|
* myPath.selected = true;
|
|
|
|
* }
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Draws an arc from the position of the last segment point in the path that
|
2015-12-27 12:09:25 -05:00
|
|
|
* goes through the specified `through` point, to the specified `to` point
|
|
|
|
* by adding one or more segments to the path.
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @name PathItem#arcTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} through the point where the arc should pass through
|
|
|
|
* @param {Point} to the point where the arc should end
|
|
|
|
*
|
|
|
|
* @example {@paperscript}
|
|
|
|
* var path = new Path();
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* var firstPoint = new Point(30, 75);
|
|
|
|
* path.add(firstPoint);
|
|
|
|
*
|
|
|
|
* // The point through which we will create the arc:
|
|
|
|
* var throughPoint = new Point(40, 40);
|
|
|
|
*
|
|
|
|
* // The point at which the arc will end:
|
|
|
|
* var toPoint = new Point(130, 75);
|
|
|
|
*
|
|
|
|
* // Draw an arc through 'throughPoint' to 'toPoint'
|
|
|
|
* path.arcTo(throughPoint, toPoint);
|
|
|
|
*
|
|
|
|
* // Add a red circle shaped path at the position of 'throughPoint':
|
|
|
|
* var circle = new Path.Circle(throughPoint, 3);
|
|
|
|
* circle.fillColor = 'red';
|
|
|
|
*
|
|
|
|
* @example {@paperscript height=300}
|
|
|
|
* // Interactive example. Click and drag in the view below:
|
|
|
|
*
|
|
|
|
* var myPath;
|
|
|
|
* function onMouseDrag(event) {
|
|
|
|
* // If we created a path before, remove it:
|
|
|
|
* if (myPath) {
|
|
|
|
* myPath.remove();
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Create a new path and add a segment point to it
|
|
|
|
* // at {x: 150, y: 150):
|
|
|
|
* myPath = new Path();
|
|
|
|
* myPath.add(150, 150);
|
|
|
|
*
|
|
|
|
* // Draw an arc through the position of the mouse to 'toPoint'
|
|
|
|
* var toPoint = new Point(350, 150);
|
|
|
|
* myPath.arcTo(event.point, toPoint);
|
|
|
|
*
|
|
|
|
* // Select the path, so we can see its segments:
|
|
|
|
* myPath.selected = true;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // When the mouse is released, deselect the path
|
|
|
|
* // and fill it with black.
|
|
|
|
* function onMouseUp(event) {
|
|
|
|
* myPath.selected = false;
|
|
|
|
* myPath.fillColor = 'black';
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Draws an arc from the position of the last segment point in the path to
|
|
|
|
* the specified point by adding one or more segments to the path.
|
|
|
|
*
|
|
|
|
* @name PathItem#arcTo
|
|
|
|
* @function
|
|
|
|
* @param {Point} to the point where the arc should end
|
|
|
|
* @param {Boolean} [clockwise=true] specifies whether the arc should be
|
2015-12-27 14:04:26 -05:00
|
|
|
* drawn in clockwise direction
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @example {@paperscript}
|
|
|
|
* var path = new Path();
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* path.add(new Point(30, 75));
|
|
|
|
* path.arcTo(new Point(130, 75));
|
|
|
|
*
|
|
|
|
* var path2 = new Path();
|
|
|
|
* path2.strokeColor = 'red';
|
|
|
|
* path2.add(new Point(180, 25));
|
|
|
|
*
|
|
|
|
* // To draw an arc in anticlockwise direction,
|
2014-09-26 12:03:37 -04:00
|
|
|
* // we pass `false` as the second argument to arcTo:
|
2014-08-16 13:24:54 -04:00
|
|
|
* path2.arcTo(new Point(280, 25), false);
|
|
|
|
*
|
|
|
|
* @example {@paperscript height=300}
|
|
|
|
* // Interactive example. Click and drag in the view below:
|
|
|
|
* var myPath;
|
|
|
|
*
|
|
|
|
* // The mouse has to move at least 20 points before
|
|
|
|
* // the next mouse drag event is fired:
|
|
|
|
* tool.minDistance = 20;
|
|
|
|
*
|
|
|
|
* // When the user clicks, create a new path and add
|
|
|
|
* // the current mouse position to it as its first segment:
|
|
|
|
* function onMouseDown(event) {
|
|
|
|
* myPath = new Path();
|
|
|
|
* myPath.strokeColor = 'black';
|
|
|
|
* myPath.add(event.point);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // On each mouse drag event, draw an arc to the current
|
|
|
|
* // position of the mouse:
|
|
|
|
* function onMouseDrag(event) {
|
|
|
|
* myPath.arcTo(event.point);
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
// DOCS: PathItem#arcTo(to, radius, rotation, clockwise, large)
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
2015-12-27 14:04:26 -05:00
|
|
|
* Closes the path. When closed, Paper.js connects the first and last
|
|
|
|
* segment of the path with an additional curve.
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @name PathItem#closePath
|
|
|
|
* @function
|
|
|
|
* @param {Boolean} join controls whether the method should attempt to merge
|
2015-12-27 14:04:26 -05:00
|
|
|
* the first segment with the last if they lie in the same location
|
2014-08-16 13:24:54 -04:00
|
|
|
* @see Path#closed
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* {@grouptitle Relative Drawing Commands}
|
|
|
|
*
|
|
|
|
* If called on a {@link CompoundPath}, a new {@link Path} is created as a
|
2015-12-27 14:04:26 -05:00
|
|
|
* child and a point is added as its first segment relative to the position
|
|
|
|
* of the last segment of the current path.
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @name PathItem#moveBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
/**
|
|
|
|
* Adds a segment relative to the last segment point of the path.
|
|
|
|
*
|
|
|
|
* @name PathItem#lineBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} to the vector which is added to the position of the last
|
2015-12-27 14:04:26 -05:00
|
|
|
* segment of the path, to get to the position of the new segment
|
2014-08-16 13:24:54 -04:00
|
|
|
*
|
|
|
|
* @example {@paperscript}
|
|
|
|
* var path = new Path();
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* // Add a segment at {x: 50, y: 50}
|
|
|
|
* path.add(25, 25);
|
|
|
|
*
|
|
|
|
* // Add a segment relative to the last segment of the path.
|
|
|
|
* // 50 in x direction and 0 in y direction, becomes {x: 75, y: 25}
|
|
|
|
* path.lineBy(50, 0);
|
|
|
|
*
|
|
|
|
* // 0 in x direction and 50 in y direction, becomes {x: 75, y: 75}
|
|
|
|
* path.lineBy(0, 50);
|
|
|
|
*
|
|
|
|
* @example {@paperscript height=300}
|
|
|
|
* // Drawing a spiral using lineBy:
|
|
|
|
* var path = new Path();
|
|
|
|
* path.strokeColor = 'black';
|
|
|
|
*
|
|
|
|
* // Add the first segment at {x: 50, y: 50}
|
|
|
|
* path.add(view.center);
|
|
|
|
*
|
|
|
|
* // Loop 500 times:
|
|
|
|
* for (var i = 0; i < 500; i++) {
|
|
|
|
* // Create a vector with an ever increasing length
|
|
|
|
* // and an angle in increments of 45 degrees
|
|
|
|
* var vector = new Point({
|
|
|
|
* angle: i * 45,
|
|
|
|
* length: i / 2
|
|
|
|
* });
|
|
|
|
* // Add the vector relatively to the last segment point:
|
|
|
|
* path.lineBy(vector);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Smooth the handles of the path:
|
|
|
|
* path.smooth();
|
|
|
|
*
|
|
|
|
* // Uncomment the following line and click on 'run' to see
|
|
|
|
* // the construction of the path:
|
|
|
|
* // path.selected = true;
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document Path#curveBy()
|
|
|
|
/**
|
|
|
|
* @name PathItem#curveBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} through
|
|
|
|
* @param {Point} to
|
|
|
|
* @param {Number} [parameter=0.5]
|
|
|
|
*/
|
2011-06-16 17:07:00 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document Path#cubicCurveBy()
|
|
|
|
/**
|
|
|
|
* @name PathItem#cubicCurveBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} handle1
|
|
|
|
* @param {Point} handle2
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2013-10-29 20:43:55 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document Path#quadraticCurveBy()
|
|
|
|
/**
|
|
|
|
* @name PathItem#quadraticCurveBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} handle
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2013-10-29 20:43:55 -04:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document Path#arcBy(through, to)
|
|
|
|
/**
|
|
|
|
* @name PathItem#arcBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} through
|
|
|
|
* @param {Point} to
|
|
|
|
*/
|
2013-11-24 19:04:51 -05:00
|
|
|
|
2014-08-16 13:24:54 -04:00
|
|
|
// DOCS: Document Path#arcBy(to, clockwise)
|
|
|
|
/**
|
|
|
|
* @name PathItem#arcBy
|
|
|
|
* @function
|
|
|
|
* @param {Point} to
|
|
|
|
* @param {Boolean} [clockwise=true]
|
|
|
|
*/
|
2011-02-13 11:26:24 -05:00
|
|
|
});
|