From 4e0a857ee7ee07ea600882a017e012228d704df1 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 14:51:37 +0200 Subject: [PATCH 01/14] Fix a problem in Path#arcTo where it wasn't defaulting to a clockwise arc. --- src/path/Path.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/path/Path.js b/src/path/Path.js index 33b366be..2e06f65e 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1097,7 +1097,7 @@ var Path = this.Path = PathItem.extend({ to = Point.read(arguments, 1, 1); } else { to = Point.read(arguments, 0, 1); - if (clockwise === null) + if (clockwise === undefined) clockwise = true; var middle = current._point.add(to).divide(2), step = middle.subtract(current._point); From bb956c890f2162f0b6b03db9d173b7c0c23c12ea Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 14:52:01 +0200 Subject: [PATCH 02/14] Add documentation stub for Path#arcTo(through, to) --- src/path/Path.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/path/Path.js b/src/path/Path.js index 2e06f65e..96b0e5ce 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1084,6 +1084,12 @@ var Path = this.Path = PathItem.extend({ }, // DOCS: document Path#arcTo + /** + * @name Path#arcTo + * @function + * @param {Point} through + * @param {Point} to + */ /** * @param {Point} to * @param {Boolean} [clockwise=true] From 34b510bf1cfa53f848e43879513ac21b0308e6bb Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 15:00:43 +0200 Subject: [PATCH 03/14] Path: add examples to #getPointAt, #getNormalAt and #getTangentAt. --- src/path/Path.js | 156 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/src/path/Path.js b/src/path/Path.js index 96b0e5ce..0d52d927 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -641,11 +641,53 @@ var Path = this.Path = PathItem.extend({ // DOCS: improve Path#getPointAt documenation. /** - * Get the point of the path at the given offset. + * Get the point on the path at the given offset. * * @param {Number} offset * @param {Boolean} [isParameter=false] * @return {Point} the point at the given offset + * + * @example {@paperscript height=150} + * // Finding the point on a path at a given offset: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * // We're going to be working with a third of the length + * // of the path as the offset: + * var offset = path.length / 3; + * + * // Find the point on the path: + * var point = path.getPointAt(offset); + * + * // Create a small circle shaped path at the point: + * var circle = new Path.Circle(point, 3); + * circle.fillColor = 'red'; + * + * @example {@paperscript height=150} + * // Iterating over the length of a path: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * var amount = 5; + * var length = path.length; + * for (var i = 0; i < amount + 1; i++) { + * var offset = i / amount * length; + * + * // Find the point on the path at the given offset: + * var point = path.getPointAt(offset); + * + * // Create a small circle shaped path at the point: + * var circle = new Path.Circle(point, 3); + * circle.fillColor = 'red'; + * } */ getPointAt: function(offset, isParameter) { var loc = this.getLocationAt(offset, isParameter); @@ -659,6 +701,62 @@ var Path = this.Path = PathItem.extend({ * @param {Number} offset * @param {Boolean} [isParameter=false] * @return {Point} the tangent vector at the given offset + * + * @example {@paperscript height=150} + * // Working with the tangent vector at a given offset: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * // We're going to be working with a third of the length + * // of the path as the offset: + * var offset = path.length / 3; + * + * // Find the point on the path: + * var point = path.getPointAt(offset); + * + * // Find the tangent vector at the given offset: + * var tangent = path.getTangentAt(offset); + * + * // Make the tangent vector 60pt long: + * tangent.length = 60; + * + * var path = new Path(); + * path.strokeColor = 'red'; + * path.add(point); + * path.add(point + tangent); + * + * @example {@paperscript height=200} + * // Iterating over the length of a path: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * var amount = 6; + * var length = path.length; + * for (var i = 0; i < amount + 1; i++) { + * var offset = i / amount * length; + * + * // Find the point on the path at the given offset: + * var point = path.getPointAt(offset); + * + * // Find the normal vector on the path at the given offset: + * var tangent = path.getTangentAt(offset); + * + * // Make the tangent vector 60pt long: + * tangent.length = 60; + * + * var line = new Path(); + * line.strokeColor = 'red'; + * line.add(point); + * line.add(point + tangent); + * } */ getTangentAt: function(offset, isParameter) { var loc = this.getLocationAt(offset, isParameter); @@ -671,6 +769,62 @@ var Path = this.Path = PathItem.extend({ * @param {Number} offset * @param {Boolean} [isParameter=false] * @return {Point} the normal vector at the given offset + * + * @example {@paperscript height=150} + * // Working with the normal vector at a given offset: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * // We're going to be working with a third of the length + * // of the path as the offset: + * var offset = path.length / 3; + * + * // Find the point on the path: + * var point = path.getPointAt(offset); + * + * // Find the normal vector at the given offset: + * var normal = path.getNormalAt(offset); + * + * // Make the normal vector 30pt long: + * normal.length = 30; + * + * var path = new Path(); + * path.strokeColor = 'red'; + * path.add(point); + * path.add(point + normal); + * + * @example {@paperscript height=200} + * // Iterating over the length of a path: + * + * // Create an arc shaped path: + * var path = new Path(); + * path.strokeColor = 'black'; + * path.add(new Point(40, 100)); + * path.arcTo(new Point(150, 100)); + * + * var amount = 10; + * var length = path.length; + * for (var i = 0; i < amount + 1; i++) { + * var offset = i / amount * length; + * + * // Find the point on the path at the given offset: + * var point = path.getPointAt(offset); + * + * // Find the normal vector on the path at the given offset: + * var normal = path.getNormalAt(offset); + * + * // Make the normal vector 30pt long: + * normal.length = 30; + * + * var line = new Path(); + * line.strokeColor = 'red'; + * line.add(point); + * line.add(point + normal); + * } */ getNormalAt: function(offset, isParameter) { var loc = this.getLocationAt(offset, isParameter); From deec7512cccfbdbd4c738d7ed112348e6e5a1d3d Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 15:04:34 +0200 Subject: [PATCH 04/14] Path: fix return type in #getLocationAt documentation. --- src/path/Path.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/path/Path.js b/src/path/Path.js index 0d52d927..0b4ec87a 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -611,7 +611,7 @@ var Path = this.Path = PathItem.extend({ * * @param {Number} offset * @param {Boolean} [isParameter=false] - * @return CurveLocation + * @return {CurveLocation} */ getLocationAt: function(offset, isParameter) { var curves = this.getCurves(), From c10aa01de0a862646bdafeca93bbc65b65e98bed Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 15:56:37 +0200 Subject: [PATCH 05/14] Fix a bug in Path#join. --- src/path/Path.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/path/Path.js b/src/path/Path.js index 152c058c..312d1bfd 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -564,9 +564,10 @@ var Path = this.Path = PathItem.extend({ var first1 = this.getFirstSegment(); if (first1._point.equals(first2._point)) path.reverse(); + last2 = path.getLastSegment(); if (first1._point.equals(last2._point)) { first1.setHandleIn(last2._handleIn); - // Prepend all segments from path except last one + // Prepend all segments from path except the last one this._add(segments.slice(0, segments.length - 1), 0); } else { this._add(segments.slice(0)); From ab09a44dc682bceca6edf46cf97d652a5f9b50a6 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 16:11:13 +0200 Subject: [PATCH 06/14] Add examples to Path#join documentation. --- src/path/Path.js | 57 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src/path/Path.js b/src/path/Path.js index 312d1bfd..8d990c3c 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -544,11 +544,58 @@ var Path = this.Path = PathItem.extend({ // DOCS: document Path#join in more detail. /** - * Joins the path with the specified path, which will be removed in the - * process. - * - * @param {Path} path - */ + * Joins the path with the specified path, which will be removed in the + * process. + * + * @param {Path} path + * + * @example {@paperscript} + * // Joining two paths: + * var path = new Path([30, 25], [30, 75]); + * path.strokeColor = 'black'; + * + * var path2 = new Path([200, 25], [200, 75]); + * path2.strokeColor = 'black'; + * + * // Join the paths: + * path.join(path2); + * + * @example {@paperscript} + * // Joining two paths that share a point at the start or end of their + * // segments array: + * var path = new Path([30, 25], [30, 75]); + * path.strokeColor = 'black'; + * + * var path2 = new Path([30, 25], [80, 25]); + * path2.strokeColor = 'black'; + * + * // Join the paths: + * path.join(path2); + * + * // After joining, path with have 3 segments, since it + * // shared its first segment point with the first + * // segment point of path2. + * + * // Select the path to show that they have joined: + * path.selected = true; + * + * @example {@paperscript} + * // Joining two paths that connect at two points: + * var path = new Path([30, 25], [80, 25], [80, 75]); + * path.strokeColor = 'black'; + * + * var path2 = new Path([30, 25], [30, 75], [80, 75]); + * path2.strokeColor = 'black'; + * + * // Join the paths: + * path.join(path2); + * + * // Because the paths were joined at two points, the path is closed + * // and has 4 segments. + * + * // Select the path to show that they have joined: + * path.selected = true; + */ join: function(path) { if (path) { var segments = path._segments, From a81b6f86bfe031bd5be63a88fd5a917ce828de33 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 17:22:00 +0200 Subject: [PATCH 07/14] Add failing Path#arcTo tests. --- test/tests/Path_Drawing_Commands.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/tests/Path_Drawing_Commands.js b/test/tests/Path_Drawing_Commands.js index 1f21c0e2..8ab5cf50 100644 --- a/test/tests/Path_Drawing_Commands.js +++ b/test/tests/Path_Drawing_Commands.js @@ -12,4 +12,31 @@ test('path.arcTo(from, through, to);', function() { path.moveTo([50, 50]); path.arcTo([100, 100], [75, 75]); equals(path.segments.toString(), '{ point: { x: 50, y: 50 }, handleOut: { x: 10.11156, y: -10.11156 } },{ point: { x: 88.5299, y: 42.33593 }, handleIn: { x: -13.21138, y: -5.47233 }, handleOut: { x: 13.21138, y: 5.47233 } },{ point: { x: 110.35534, y: 75 }, handleIn: { x: 0, y: -14.2999 } }'); +}); + +test('path.arcTo(from, through, to); where from, through and to all share the same y position and through lies in between from and to', function() { + var path = new Path(); + path.strokeColor = 'black'; + + path.add([40, 75]); + path.arcTo([50, 75], [100, 75]); + equals(path.lastSegment.point.toString(), '{ x: 100, y: 75 }', 'We expect the last segment point to be at the position where we wanted to draw the arc to.'); +}); + +test('path.arcTo(from, through, to); where from, through and to all share the same y position and through lies to the right of to', function() { + var path = new Path(); + path.strokeColor = 'black'; + + path.add([40, 75]); + path.arcTo([150, 75], [100, 75]); + equals(path.lastSegment.point.toString(), '{ x: 100, y: 75 }', 'We expect the last segment point to be at the position where we wanted to draw the arc to.'); +}); + +test('path.arcTo(from, through, to); where from, through and to all share the same y position and through lies to the left of to', function() { + var path = new Path(); + path.strokeColor = 'black'; + + path.add([40, 75]); + path.arcTo([10, 75], [100, 75]); + equals(path.lastSegment.point.toString(), '{ x: 100, y: 75 }', 'We expect the last segment point to be at the position where we wanted to draw the arc to.'); }); \ No newline at end of file From 14e2a61d25c430da2211b4ddaf94fe842dcb369c Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 17:22:35 +0200 Subject: [PATCH 08/14] Add examples to Path#arcTo docs. --- src/path/Path.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/path/Path.js b/src/path/Path.js index 8d990c3c..b84ad3ef 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1304,6 +1304,56 @@ var Path = this.Path = PathItem.extend({ * @function * @param {Point} through * @param {Point} to + * + * @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'; + * } */ /** * @param {Point} to From e4eb463204ff4e00f28913efe020ff947fb1f7c9 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 18:40:33 +0200 Subject: [PATCH 09/14] Path: document arcTo and curveTo. --- src/path/Path.js | 96 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 8 deletions(-) diff --git a/src/path/Path.js b/src/path/Path.js index b84ad3ef..d7c75d23 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1276,11 +1276,45 @@ var Path = this.Path = PathItem.extend({ ); }, - // DOCS: document Path#curveTo + // DOCS: document Path#curveTo 'paramater' param. /** - * @param {Point} through - * @param {Point} to + * Draws a curve from the position of the last segment point in + * the path that goes through the specified {@code through} point, + * to the specified {@code to} point by adding one segment to the path. + * + * @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. 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 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; + * } + * + * // When the mouse is released, deselect the path + * // and set its stroke-color to black: + * function onMouseUp(event) { + * myPath.selected = false; + * myPath.strokeColor = 'black'; + * } */ curveTo: function(through, to, parameter) { through = Point.read(arguments, 0, 1); @@ -1298,12 +1332,16 @@ var Path = this.Path = PathItem.extend({ this.quadraticCurveTo(handle, to); }, - // DOCS: document Path#arcTo /** + * Draws an arc from the position of the last segment point in + * the path that goes through the specified {@code through} point, + * to the specified {@code to} point by adding one or more segments to + * the path. + * * @name Path#arcTo * @function - * @param {Point} through - * @param {Point} to + * @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(); @@ -1356,8 +1394,50 @@ var Path = this.Path = PathItem.extend({ * } */ /** - * @param {Point} to - * @param {Boolean} [clockwise=true] + * 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. + * + * @param {Point} point + * @param {Boolean} [clockwise=true] specifies whether the arc should + * be drawn in clockwise direction. + * + * @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, + * // we pass 'false' as the second argument to arcTo: + * 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); + * } */ arcTo: function(to, clockwise) { // Get the start point: From af5aa67c36bdea6f89fc5595ee104815ff338ff3 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 19:50:24 +0200 Subject: [PATCH 10/14] Change Path#removeSegments(from, to) test to fail and add a todo questioning if its behaviour is correct. Also add a failing Path#removeSegments() test. --- test/tests/Path.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/tests/Path.js b/test/tests/Path.js index 851b78d1..aaf44178 100644 --- a/test/tests/Path.js +++ b/test/tests/Path.js @@ -70,7 +70,9 @@ test('path.remove()', function() { return path.segments.length; }, 2); - path.removeSegments(0, 2); + // TODO: shouldn't this remove two segments? The segments from index 0 till + // index 1? + path.removeSegments(0, 1); equals(function() { return path.segments.length; }, 0); @@ -82,6 +84,18 @@ test('path.remove()', function() { }, 0); }); +test('path.removeSegments()', function() { + var path = new Path(); + path.add(0, 0); + path.add(10, 0); + path.add(20, 0); + path.add(30, 0); + + path.removeSegments(); + equals(function() { + return path.segments.length; + }, 0); +}); test('Is the path deselected after setting a new list of segments?', function() { var path = new Path([0, 0]); From 9c88c003604b5638cd991b6ea7f6bf351109204e Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 20:08:46 +0200 Subject: [PATCH 11/14] Add failing test for Path#fullySelected. --- test/tests/Path.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/tests/Path.js b/test/tests/Path.js index aaf44178..97286645 100644 --- a/test/tests/Path.js +++ b/test/tests/Path.js @@ -122,3 +122,11 @@ test('Path#reverse', function() { equals(path.segments.toString(), '{ point: { x: 100, y: 130 }, handleIn: { x: -16.56854, y: 0 }, handleOut: { x: 16.56854, y: 0 } },{ point: { x: 130, y: 100 }, handleIn: { x: 0, y: 16.56854 }, handleOut: { x: 0, y: -16.56854 } },{ point: { x: 100, y: 70 }, handleIn: { x: 16.56854, y: 0 }, handleOut: { x: -16.56854, y: 0 } },{ point: { x: 70, y: 100 }, handleIn: { x: 0, y: -16.56854 }, handleOut: { x: 0, y: 16.56854 } }'); }); +test('Path#fullySelected', function() { + var path = new Path.Circle([100, 100], 10); + path.selected = true; + path.segments[1].selected = false; + equals(function() { + return path.fullySelected; + }, false); +}); \ No newline at end of file From aecee4189010813be0175bc11f7eb6675484a16b Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 21:26:36 +0200 Subject: [PATCH 12/14] Add failing Path#curveToPoints tests. --- test/tests/Path_Curves.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/tests/Path_Curves.js b/test/tests/Path_Curves.js index 92c714fe..8c5e3f72 100644 --- a/test/tests/Path_Curves.js +++ b/test/tests/Path_Curves.js @@ -23,3 +23,18 @@ test('path.curves Synchronisation', function() { equals(path.segments.toString(), "{ point: { x: 0, y: 100 } },{ point: { x: 100, y: 100 } }", "path.segments: path.add(new Point(100, 100));\npath.removeSegments(1, 2);"); equals(path.curves.toString(), "{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }", "path.curves: path.add(new Point(100, 100));\npath.removeSegments(1, 2);"); }); + +test('path.curvesToPoints(maxDistance)', function() { + var path = new Path.Circle(new Size(80, 50), 35); + + // Convert its curves to points, with a max distance of 20: + path.curvesToPoints(20); + + equals(function() { + return path.lastSegment.point.equals(path.firstSegment.point); + }, false, 'The points of the last and first segments should not be the same.'); + + equals(function() { + return path.lastSegment.point.toString() != path.segments[path.segments.length - 2].point.toString(); + }, true, 'The points of the last and before last segments should not be so close, that calling toString on them returns the same string value.'); +}); \ No newline at end of file From 59e4ae72306e303a912b27dd0c4daf51e2adde04 Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 21:28:18 +0200 Subject: [PATCH 13/14] Add to and improve Path documentation. --- src/path/Path.js | 214 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 7 deletions(-) diff --git a/src/path/Path.js b/src/path/Path.js index d7c75d23..8e0f1acd 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -162,7 +162,8 @@ var Path = this.Path = PathItem.extend({ }, /** - * Specifies whether the path is closed. + * Specifies whether the path is closed. If it is closed, Paper.js connects + * the first and last segments. * * @type Boolean * @bean @@ -170,9 +171,9 @@ var Path = this.Path = PathItem.extend({ * @example {@paperscript} * var myPath = new Path(); * myPath.strokeColor = 'black'; - * myPath.add(new Point(40, 90)); - * myPath.add(new Point(90, 40)); - * myPath.add(new Point(140, 90)); + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(100, 25)); + * myPath.add(new Point(150, 75)); * * // Close the path: * myPath.closed = true; @@ -289,12 +290,49 @@ var Path = this.Path = PathItem.extend({ // PORT: Add support for adding multiple segments at once to Scriptographer // DOCS: find a way to document the variable segment parameters of Path#add /** - * Adds one or more segments to the end of the segment list of this path. + * Adds one or more segments to the end of the {@link #segments} array of + * this path. * * @param {Segment|Point} segment the segment or point to be added. * @return {Segment} the added segment. This is not necessarily the same * object, e.g. if the segment to be added already belongs to another path. * @operator none + * + * @example {@paperscript} + * // Adding segments to a path using point objects: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add(new Point(30, 75)); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add(new Point(100, 20), new Point(170, 75)); + * + * @example {@paperscript} + * // Adding segments to a path using arrays containing number pairs: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add([30, 75]); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add([100, 20], [170, 75]); + * + * @example {@paperscript} + * // Adding segments to a path using objects: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add({x: 30, y: 75}); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add({x: 100, y: 20}, {x: 170, y: 75}); */ add: function(segment1 /*, segment2, ... */) { return arguments.length > 1 && typeof segment1 !== 'number' @@ -313,6 +351,33 @@ var Path = this.Path = PathItem.extend({ * @param {Segment|Point} segment the segment or point to be inserted. * @return {Segment} the added segment. This is not necessarily the same * object, e.g. if the segment to be added already belongs to another path. + * + * @example {@paperscript} + * // Inserting a segment: + * var myPath = new Path(); + * myPath.strokeColor = 'black'; + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(150, 75)); + * + * // Insert a new segment into myPath at index 1: + * myPath.insert(1, new Point(100, 25)); + * + * // Select the segment which we just inserted: + * myPath.segments[1].selected = true; + * + * @example {@paperscript} + * // Inserting multiple segments: + * var myPath = new Path(); + * myPath.strokeColor = 'black'; + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(150, 75)); + * + * // Insert two segments into myPath at index 1: + * myPath.insert(1, [80, 25], [120, 25]); + * + * // Select the segments which we just inserted: + * myPath.segments[1].selected = true; + * myPath.segments[2].selected = true; */ insert: function(index, segment1 /*, segment2, ... */) { return arguments.length > 2 && typeof segment1 !== 'number' @@ -342,11 +407,35 @@ var Path = this.Path = PathItem.extend({ * not necessarily the same objects, e.g. if the segment to be added already * belongs to another path. * - * @example + * @example {@paperscript} + * // Adding an array of Point objects: * var path = new Path(); * path.strokeColor = 'black'; - * var points = [new Point(10, 10), new Point(50, 50)]; + * var points = [new Point(30, 50), new Point(170, 50)]; * path.addSegments(points); + * + * @example {@paperscript} + * // Adding an array of [x, y] arrays: + * var path = new Path(); + * path.strokeColor = 'black'; + * var array = [[30, 75], [100, 20], [170, 75]]; + * path.addSegments(array); + * + * @example {@paperscript} + * // Adding segments from one path to another: + * + * var path = new Path(); + * path.strokeColor = 'black'; + * path.addSegments([[30, 75], [100, 20], [170, 75]]); + * + * var path2 = new Path(); + * path2.strokeColor = 'red'; + * + * // Add the second and third segments of path to path2: + * path2.add(path.segments[1], path.segments[2]); + * + * // Move path2 30pt to the right: + * path2.position.x += 30; */ addSegments: function(segments) { return this._add(Segment.readAll(segments)); @@ -374,6 +463,20 @@ var Path = this.Path = PathItem.extend({ * * @param {Number} index the index of the segment to be removed * @return {Segment} the removed segment + * + * @example {@paperscript} + * // Removing a segment from a path: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Point(80, 50), 35); + * path.strokeColor = 'black'; + * + * // Remove its second segment: + * path.removeSegment(1); + * + * // Select the path, so we can see its segments: + * path.selected = true; */ removeSegment: function(index) { var segments = this.removeSegments(index, index + 1); @@ -388,6 +491,20 @@ var Path = this.Path = PathItem.extend({ * @param {Number} from * @param {Number} to * @return {Array} an array containing the removed segments. + * + * @example {@paperscript} + * // Removing segments from a path: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Point(80, 50), 35); + * path.strokeColor = 'black'; + * + * // Remove the segments from index 1 till index 2: + * path.removeSegments(1, 2); + * + * // Select the path, so we can see its segments: + * path.selected = true; */ removeSegments: function(from, to) { from = from || 0; @@ -430,6 +547,40 @@ var Path = this.Path = PathItem.extend({ return removed; }, + /** + * Specifies whether an path is selected and will also return {@code true} + * if the path is partially selected, i.e. one or more of its segments is + * selected. + * + * Paper.js draws the visual outlines of selected items on top of your + * project. This can be useful for debugging, as it allows you to see the + * construction of paths, position of path curves, individual segment points + * and bounding boxes of symbol and raster items. + * + * @type Boolean + * @bean + * @see Project#selectedItems + * @see Segment#selected + * @see Point#selected + * + * @example {@paperscript} + * // Selecting an item: + * var path = new Path.Circle(new Size(80, 50), 35); + * path.selected = true; // Select the path + * + * @example {@paperscript} + * // A path is selected, if one or more of its segments is selected: + * var path = new Path.Circle(new Size(80, 50), 35); + * + * // Select the second segment of the path: + * path.segments[1].selected = true; + * + * // If the path is selected (which it is), set its fill color to red: + * if (path.selected) { + * path.fillColor = 'red'; + * } + * + */ isSelected: function() { return this._selectedSegmentCount > 0; }, @@ -450,6 +601,30 @@ var Path = this.Path = PathItem.extend({ * * @type Boolean * @bean + * + * @example {@paperscript} + * // A path is fully selected, if all of its segments are selected: + * var path = new Path.Circle(new Size(80, 50), 35); + * path.selected = true; + * + * var path2 = new Path.Circle(new Size(180, 50), 35); + * path2.selected = true; + * + * // Deselect the second segment of the second path: + * path2.segments[1].selected = false; + * + * // If the path is fully selected (which it is), + * // set its fill color to red: + * if (path.fullySelected) { + * path.fillColor = 'red'; + * } + * + * // If the second path is fully selected (which it isn't, since we just + * // deselected its second segment), + * // set its fill color to red: + * if (path2.fullySelected) { + * path2.fillColor = 'red'; + * } */ isFullySelected: function() { return this._selectedSegmentCount == this._segments.length; @@ -459,6 +634,31 @@ var Path = this.Path = PathItem.extend({ this.setSelected(selected); }, + /** + * Converts the curves in the path to straight lines. + * + * @param {Number} maxDistance the maximum distance between the points + * + * @example {@paperscript} + * // Straightening the curves of a circle: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Size(80, 50), 35); + * + * // Select the path, so we can inspect its segments: + * path.selected = true; + * + * // Create a copy of the path and move it 150 points to the right: + * var copy = path.clone(); + * copy.position.x += 150; + * + * // Convert its curves to points, with a max distance of 20: + * copy.curvesToPoints(20); + * + * // Select the copy, so we can inspect its segments: + * copy.selected = true; + */ curvesToPoints: function(maxDistance) { var flattener = new PathFlattener(this), pos = 0; From fe901fa96b3739b6d10c9d7008b49d5ea7f20ead Mon Sep 17 00:00:00 2001 From: Jonathan Puckey Date: Sun, 5 Jun 2011 21:28:18 +0200 Subject: [PATCH 14/14] Add to and improve Path documentation. --- src/path/Path.js | 214 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 7 deletions(-) diff --git a/src/path/Path.js b/src/path/Path.js index d7c75d23..8e0f1acd 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -162,7 +162,8 @@ var Path = this.Path = PathItem.extend({ }, /** - * Specifies whether the path is closed. + * Specifies whether the path is closed. If it is closed, Paper.js connects + * the first and last segments. * * @type Boolean * @bean @@ -170,9 +171,9 @@ var Path = this.Path = PathItem.extend({ * @example {@paperscript} * var myPath = new Path(); * myPath.strokeColor = 'black'; - * myPath.add(new Point(40, 90)); - * myPath.add(new Point(90, 40)); - * myPath.add(new Point(140, 90)); + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(100, 25)); + * myPath.add(new Point(150, 75)); * * // Close the path: * myPath.closed = true; @@ -289,12 +290,49 @@ var Path = this.Path = PathItem.extend({ // PORT: Add support for adding multiple segments at once to Scriptographer // DOCS: find a way to document the variable segment parameters of Path#add /** - * Adds one or more segments to the end of the segment list of this path. + * Adds one or more segments to the end of the {@link #segments} array of + * this path. * * @param {Segment|Point} segment the segment or point to be added. * @return {Segment} the added segment. This is not necessarily the same * object, e.g. if the segment to be added already belongs to another path. * @operator none + * + * @example {@paperscript} + * // Adding segments to a path using point objects: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add(new Point(30, 75)); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add(new Point(100, 20), new Point(170, 75)); + * + * @example {@paperscript} + * // Adding segments to a path using arrays containing number pairs: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add([30, 75]); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add([100, 20], [170, 75]); + * + * @example {@paperscript} + * // Adding segments to a path using objects: + * var path = new Path(); + * path.strokeColor = 'black'; + * + * // Add a segment at {x: 30, y: 75} + * path.add({x: 30, y: 75}); + * + * // Add two segments in one go at {x: 100, y: 20} + * // and {x: 170, y: 75}: + * path.add({x: 100, y: 20}, {x: 170, y: 75}); */ add: function(segment1 /*, segment2, ... */) { return arguments.length > 1 && typeof segment1 !== 'number' @@ -313,6 +351,33 @@ var Path = this.Path = PathItem.extend({ * @param {Segment|Point} segment the segment or point to be inserted. * @return {Segment} the added segment. This is not necessarily the same * object, e.g. if the segment to be added already belongs to another path. + * + * @example {@paperscript} + * // Inserting a segment: + * var myPath = new Path(); + * myPath.strokeColor = 'black'; + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(150, 75)); + * + * // Insert a new segment into myPath at index 1: + * myPath.insert(1, new Point(100, 25)); + * + * // Select the segment which we just inserted: + * myPath.segments[1].selected = true; + * + * @example {@paperscript} + * // Inserting multiple segments: + * var myPath = new Path(); + * myPath.strokeColor = 'black'; + * myPath.add(new Point(50, 75)); + * myPath.add(new Point(150, 75)); + * + * // Insert two segments into myPath at index 1: + * myPath.insert(1, [80, 25], [120, 25]); + * + * // Select the segments which we just inserted: + * myPath.segments[1].selected = true; + * myPath.segments[2].selected = true; */ insert: function(index, segment1 /*, segment2, ... */) { return arguments.length > 2 && typeof segment1 !== 'number' @@ -342,11 +407,35 @@ var Path = this.Path = PathItem.extend({ * not necessarily the same objects, e.g. if the segment to be added already * belongs to another path. * - * @example + * @example {@paperscript} + * // Adding an array of Point objects: * var path = new Path(); * path.strokeColor = 'black'; - * var points = [new Point(10, 10), new Point(50, 50)]; + * var points = [new Point(30, 50), new Point(170, 50)]; * path.addSegments(points); + * + * @example {@paperscript} + * // Adding an array of [x, y] arrays: + * var path = new Path(); + * path.strokeColor = 'black'; + * var array = [[30, 75], [100, 20], [170, 75]]; + * path.addSegments(array); + * + * @example {@paperscript} + * // Adding segments from one path to another: + * + * var path = new Path(); + * path.strokeColor = 'black'; + * path.addSegments([[30, 75], [100, 20], [170, 75]]); + * + * var path2 = new Path(); + * path2.strokeColor = 'red'; + * + * // Add the second and third segments of path to path2: + * path2.add(path.segments[1], path.segments[2]); + * + * // Move path2 30pt to the right: + * path2.position.x += 30; */ addSegments: function(segments) { return this._add(Segment.readAll(segments)); @@ -374,6 +463,20 @@ var Path = this.Path = PathItem.extend({ * * @param {Number} index the index of the segment to be removed * @return {Segment} the removed segment + * + * @example {@paperscript} + * // Removing a segment from a path: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Point(80, 50), 35); + * path.strokeColor = 'black'; + * + * // Remove its second segment: + * path.removeSegment(1); + * + * // Select the path, so we can see its segments: + * path.selected = true; */ removeSegment: function(index) { var segments = this.removeSegments(index, index + 1); @@ -388,6 +491,20 @@ var Path = this.Path = PathItem.extend({ * @param {Number} from * @param {Number} to * @return {Array} an array containing the removed segments. + * + * @example {@paperscript} + * // Removing segments from a path: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Point(80, 50), 35); + * path.strokeColor = 'black'; + * + * // Remove the segments from index 1 till index 2: + * path.removeSegments(1, 2); + * + * // Select the path, so we can see its segments: + * path.selected = true; */ removeSegments: function(from, to) { from = from || 0; @@ -430,6 +547,40 @@ var Path = this.Path = PathItem.extend({ return removed; }, + /** + * Specifies whether an path is selected and will also return {@code true} + * if the path is partially selected, i.e. one or more of its segments is + * selected. + * + * Paper.js draws the visual outlines of selected items on top of your + * project. This can be useful for debugging, as it allows you to see the + * construction of paths, position of path curves, individual segment points + * and bounding boxes of symbol and raster items. + * + * @type Boolean + * @bean + * @see Project#selectedItems + * @see Segment#selected + * @see Point#selected + * + * @example {@paperscript} + * // Selecting an item: + * var path = new Path.Circle(new Size(80, 50), 35); + * path.selected = true; // Select the path + * + * @example {@paperscript} + * // A path is selected, if one or more of its segments is selected: + * var path = new Path.Circle(new Size(80, 50), 35); + * + * // Select the second segment of the path: + * path.segments[1].selected = true; + * + * // If the path is selected (which it is), set its fill color to red: + * if (path.selected) { + * path.fillColor = 'red'; + * } + * + */ isSelected: function() { return this._selectedSegmentCount > 0; }, @@ -450,6 +601,30 @@ var Path = this.Path = PathItem.extend({ * * @type Boolean * @bean + * + * @example {@paperscript} + * // A path is fully selected, if all of its segments are selected: + * var path = new Path.Circle(new Size(80, 50), 35); + * path.selected = true; + * + * var path2 = new Path.Circle(new Size(180, 50), 35); + * path2.selected = true; + * + * // Deselect the second segment of the second path: + * path2.segments[1].selected = false; + * + * // If the path is fully selected (which it is), + * // set its fill color to red: + * if (path.fullySelected) { + * path.fillColor = 'red'; + * } + * + * // If the second path is fully selected (which it isn't, since we just + * // deselected its second segment), + * // set its fill color to red: + * if (path2.fullySelected) { + * path2.fillColor = 'red'; + * } */ isFullySelected: function() { return this._selectedSegmentCount == this._segments.length; @@ -459,6 +634,31 @@ var Path = this.Path = PathItem.extend({ this.setSelected(selected); }, + /** + * Converts the curves in the path to straight lines. + * + * @param {Number} maxDistance the maximum distance between the points + * + * @example {@paperscript} + * // Straightening the curves of a circle: + * + * // Create a circle shaped path at { x: 80, y: 50 } + * // with a radius of 35: + * var path = new Path.Circle(new Size(80, 50), 35); + * + * // Select the path, so we can inspect its segments: + * path.selected = true; + * + * // Create a copy of the path and move it 150 points to the right: + * var copy = path.clone(); + * copy.position.x += 150; + * + * // Convert its curves to points, with a max distance of 20: + * copy.curvesToPoints(20); + * + * // Select the copy, so we can inspect its segments: + * copy.selected = true; + */ curvesToPoints: function(maxDistance) { var flattener = new PathFlattener(this), pos = 0;