diff --git a/README.md b/README.md index 09a5e38c..d3a781f3 100644 --- a/README.md +++ b/README.md @@ -56,10 +56,11 @@ You will then find the built library inside the `dist` folder, named `paper.js`. commented Preprocessed but still formated and commented stripped Formated but without comments (default) - compressed No comments and no whitespaces - uglified Uses UglifyJS to further reduce file size + compressed Uses UglifyJS to reduce file size -In order for UglifyJS to work when building Paper.js, it needs to be located in a folder name `uglifyjs` on the same level as your `paper.js` project folder. Alternatively you can also adjust the path in `build/preprocess.sh` +In order for UglifyJS to work when building Paper.js, it needs to be located in a folder name `uglifyjs` on the same level as your `paper.js` project folder. Alternatively you can also adjust the path in `build/preprocess.sh`. You also need to make sure that node will find the uglifyjs library by making a symbolic link to it from `~/.node_libraries/uglify-js`, e.g. + + ln -s ~/Development/JavaScript/uglifyjs ~/.node_libraries/uglify-js ### Building the Documentation diff --git a/build/docs.sh b/build/docs.sh index 57f4098a..b55606a0 100755 --- a/build/docs.sh +++ b/build/docs.sh @@ -30,7 +30,7 @@ cd jsdoc-toolkit java -jar jsrun.jar app/run.js -c=conf/$MODE.conf -D="renderMode:$MODE" cd .. -if [ $MODE == "docs" ] +if [ $MODE = "docs" ] then # Build paper.js library for documentation ./preprocess.sh stripped ../src/paper.js ../dist/docs/resources/js/paper.js\ diff --git a/build/jsdoc-toolkit b/build/jsdoc-toolkit index 0bf4e2d0..17d8366c 160000 --- a/build/jsdoc-toolkit +++ b/build/jsdoc-toolkit @@ -1 +1 @@ -Subproject commit 0bf4e2d0a1b4f887fbe0058b3299fc26dded4501 +Subproject commit 17d8366c4f91ce9fa98e948755a63590a7871378 diff --git a/build/parse-js.sh b/build/parse-js.sh index cbc6358c..7410b68a 100755 --- a/build/parse-js.sh +++ b/build/parse-js.sh @@ -17,4 +17,4 @@ # through the seperate source files in the src directory. Very useful during # development of the library itself. -./preprocess.sh ../lib/parse-js.js ../lib/parse-js-min.js "" uglified +./preprocess.sh compressed ../lib/parse-js.js ../lib/parse-js-min.js '{}' diff --git a/dist/docs/classes/CharacterStyle.html b/dist/docs/classes/CharacterStyle.html index 7b2ea6e5..b1692846 100644 --- a/dist/docs/classes/CharacterStyle.html +++ b/dist/docs/classes/CharacterStyle.html @@ -1,6 +1,7 @@
+Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Extends CurveLocation
- - +A HitResult object contains information about the results of a hit +test. It is returned by item.hitTest(point) and +project.hitTest(point).
Describes the type of the hit result. For example, if you hit a segment +point, the type would be 'segment'.
+ +If the HitResult has a hitResult.type of 'bounds', this property +describes which corner of the bounding rectangle was hit.
+ + +If the HitResult has a type of 'stroke', this property gives more +information about the exact position that was hit on the path.
+ + +The segment of the curve which is closer to the described location.
+If the HitResult has a type of 'stroke', 'segment', 'handle-in' or +'handle-out', this property refers to the Segment that was hit or that +is closest to the hitResult.location on the curve.
The index of the curve within the path.curves list, if the -curve is part of a Path item.
- - -The length of the path from its beginning up to the location described -by this object.
- - -The length of the curve from its beginning up to the location described -by this object.
- - -The curve parameter, as used by various bezier curve calculations. It is -value between 0 (beginning of the curve) and 1 (end of -the curve).
- - -Creates a new CurveLocation object.
- -Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +- [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ] - [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ] - [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ] + [ x ] [ a b tx ] [ x ] [ a * x + b * y + tx ] + [ y ] = [ c d ty ] [ y ] = [ c * x + d * y + ty ] + [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
This class is optimized for speed and minimizes calculations based on its knowledge of the underlying matrix (as opposed to say simply performing @@ -39,18 +40,18 @@ matrix multiplication).
The scaling factor in the x-direction (a).
+ + +The scaling factor in the y-direction (d).
+ + +The translation in the x-direction (tx).
+ + +The translation in the y-direction (ty).
+ + +Returns the rotation angle of the matrix. If a non-uniform +rotation is applied as a result of a shear() or scale() command, +undefined is returned, as the resulting transformation cannot be +expressed in one rotation angle
Inverts the transformation of the matrix. If the matrix is not invertible +(in which case isSingular() returns true), null is +returned.
The PaperScope class represents the scope associated with a +Paper context. When working with PaperScript, these scopes are automatically +created for us, and through clever scoping the properties and methods of the +active scope seem to become part of the global scope.
+When working with normal JavaScript code, PaperScope objects need to +be manually created and handled.
+Paper classes can only be accessed through PaperScope objects. Thus +in PaperScript they are global, while in JavaScript, they are available on +the global paper object. For JavaScript you can use +paperScope.install(scope) to install the Paper classes and objects +on the global scope. Note that when working with more than one scope, this +still works for classes, but not for objects like paperScope.project, +since they are not updated in the injected scope if scopes are switched.
+The global paper object is simply a reference to the currently active +PaperScope.
+ +Creates a PaperScope object.
+ + + + +The version of Paper.js, as a float number.
+ + +Injects the paper scope into any other given scope. Can be used for +examle to inject the currently active PaperScope into the window's global +scope, to emulate PaperScript-style globally accessible Paper classes and +objects:
+ ++Example +
+ + +paper.install(window);+ +
Sets up an empty project for us. If a canvas is provided, it also creates +a View for it, both linked to this scope.
+ +Retrieves a PaperScope object with the given id or associated with +the passed canvas element.
+ +Iterates over all active scopes and calls the passed iterator +function for each of them.
+ +Copyright © 2011 Jürg Lehni & Jonathan Puckey. All Rights Reserved.
+ + + \ No newline at end of file diff --git a/dist/docs/classes/PaperScript.html b/dist/docs/classes/PaperScript.html new file mode 100644 index 00000000..9714c10d --- /dev/null +++ b/dist/docs/classes/PaperScript.html @@ -0,0 +1,137 @@ + + + + +Compiles PaperScript code into JavaScript code.
+ +Evaluates parsed PaperScript code in the passed PaperScope +object. It also installs handlers automatically for us.
+ +Copyright © 2011 Jürg Lehni & Jonathan Puckey. All Rights Reserved.
+ + + \ No newline at end of file diff --git a/dist/docs/classes/ParagraphStyle.html b/dist/docs/classes/ParagraphStyle.html index b6cffc2f..b0b4aa4d 100644 --- a/dist/docs/classes/ParagraphStyle.html +++ b/dist/docs/classes/ParagraphStyle.html @@ -1,6 +1,7 @@ +Returns the nearest location on the path to the specified point.
+ +Returns the nearest point on the path to the specified point.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +A Project object in Paper.js is what usually is refered to as the +
A Project object in Paper.js is what usually is referred to as the document: The top level object that holds all the items contained in the scene graph. As the term document is already taken in the browser context, it is called Project.
@@ -25,10 +26,10 @@ created items, give access to the selected items, and will in future versions offer ways to query for items in the scene graph defining specific requirements, and means to persist and load from different formats, such as SVG and PDF. -The currently active project can be accessed through the global -{@see _global_#project} variable.
-An array of all open projects is accessible through the global -{@see _global_#projects} variable.
+The currently active project can be accessed through the +paperScope.project variable.
+An array of all open projects is accessible through the +paperScope.projects variable.
Creates a Paper.js project.
When working with PaperScript, a project is automatically created for us -and the global {@see _global_#project} variable points to it.
+and the paperScope.project variable points to it. @@ -158,7 +159,7 @@ var path2 = new Path.Circle(new Point(175, 50), 20);The index of the project in the global projects array.
+The index of the project in the paperScope.projects list.
Removes this project from the global {@see _global_#projects} list.
+Removes this project from the paperScope.projects list.
@@ -472,6 +473,84 @@ in it. +Perform a hit test on the items contained within the project at the +location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+options.tolerance: Number - The tolerance of the hit test +in points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path +items, taking into account stroke width.
+options.segment: Boolean - Hit test for +segment.point of Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or +last segment points of open path items.
+options.bounds: Boolean - Hit test the corners and +side-centers of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the +rectangle.center of the bounding rectangle of items +(item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Perform a hit test on the item (and its children, if it is a +Group or Layer) at the location of the specified point.
+The optional options object allows you to control the specifics of the +hit test and may contain a combination of the following values:
+tolerance: Number - The tolerance of the hit test in +points.
+options.type: Only hit test again a certain item +type: PathItem, Raster, TextItem, etc.
+options.fill: Boolean - Hit test the fill of items.
+options.stroke: Boolean - Hit test the curves of path items, +taking into account stroke width.
+options.segment: Boolean - Hit test for segment.point of +Path items.
+options.handles: Boolean - Hit test for the handles +(segment.handleIn / segment.handleOut) of path segments.
+options.ends: Boolean - Only hit test for the first or last +segment points of open path items.
+options.bounds: Boolean - Hit test the corners and side-centers +of the bounding rectangle of items (item.bounds).
+options.center: Boolean - Hit test the rectangle.center +of the bounding rectangle of items (item.bounds).
+options.guide: Boolean - Hit test items that have +item.guide set to true.
+options.selected: Boolean - Only hit selected items.
+ +Initializes the tool's settings, so a new tool can be assigned to it
- -The item at the position of the mouse (if any).
+If the item is contained within one or more Group or +CompoundPath items, the most top level group or compound path +that it is contained within is returned.
+ + +The version of Paper.js, as a float number.
+A reference to the currently active PaperScope object.
The active view of the active project.
+The list of view of the active project.
@@ -203,7 +206,7 @@The reference to the tool object.
+The reference to the active tool.
- * [ x ] [ m00 m01 m02 ] [ x ] [ m00 * x + m01 * y + m02 ] - * [ y ] = [ m10 m11 m12 ] [ y ] = [ m10 * x + m11 * y + m12 ] - * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ] + * [ x ] [ a b tx ] [ x ] [ a * x + b * y + tx ] + * [ y ] = [ c d ty ] [ y ] = [ c * x + d * y + ty ] + * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ] ** * This class is optimized for speed and minimizes calculations based on its @@ -45,12 +45,12 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Creates a 2D affine transform. * - * @param {Number} m00 The m00 coordinate of the transform. - * @param {Number} m10 The m10 coordinate of the transform. - * @param {Number} m01 The m01 coordinate of the transform. - * @param {Number} m11 The m11 coordinate of the transform. - * @param {Number} m02 The m02 coordinate of the transform. - * @param {Number} m12 The m12 coordinate of the transform. + * @param {Number} a The scaleX coordinate of the transform + * @param {Number} c The shearY coordinate of the transform + * @param {Number} b The shearX coordinate of the transform + * @param {Number} d The scaleY coordinate of the transform + * @param {Number} tx The translateX coordinate of the transform + * @param {Number} ty The translateY coordinate of the transform */ initialize: function(arg) { var count = arguments.length, @@ -59,16 +59,15 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ this.set.apply(this, arguments); } else if (count == 1) { if (arg instanceof Matrix) { - this.set(arg._m00, arg._m10, arg._m01, - arg._m11, arg._m02, arg._m12); + this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty); } else if (Array.isArray(arg)) { this.set.apply(this, arg); } else { ok = false; } } else if (count == 0) { - this._m00 = this._m11 = 1; - this._m10 = this._m01 = this._m02 = this._m12 = 0; + this._a = this._d = 1; + this._c = this._b = this._tx = this._ty = 0; } else { ok = false; } @@ -80,28 +79,28 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * @return {Matrix} A copy of this transform. */ clone: function() { - return Matrix.create(this._m00, this._m10, this._m01, - this._m11, this._m02, this._m12); + return Matrix.create(this._a, this._c, this._b, this._d, + this._tx, this._ty); }, /** * Sets this transform to the matrix specified by the 6 values. * - * @param {Number} m00 The m00 coordinate of the transform. - * @param {Number} m10 The m10 coordinate of the transform. - * @param {Number} m01 The m01 coordinate of the transform. - * @param {Number} m11 The m11 coordinate of the transform. - * @param {Number} m02 The m02 coordinate of the transform. - * @param {Number} m12 The m12 coordinate of the transform. - * @return {Matrix} This affine transform. + * @param {Number} a The scaleX coordinate of the transform + * @param {Number} c The shearY coordinate of the transform + * @param {Number} b The shearX coordinate of the transform + * @param {Number} d The scaleY coordinate of the transform + * @param {Number} tx The translateX coordinate of the transform + * @param {Number} ty The translateY coordinate of the transform + * @return {Matrix} This affine transform */ - set: function(m00, m10, m01, m11, m02, m12) { - this._m00 = m00; - this._m10 = m10; - this._m01 = m01; - this._m11 = m11; - this._m02 = m02; - this._m12 = m12; + set: function(a, c, b, d, tx, ty) { + this._a = a; + this._c = c; + this._b = b; + this._d = d; + this._tx = tx; + this._ty = ty; return this; }, @@ -110,21 +109,19 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * * @name Matrix#scale * @function - * @param {Number} scale The scaling factor. - * @param {Point} [center] The center for the scaling - * transformation. - * @return {Matrix} This affine transform. + * @param {Number} scale The scaling factor + * @param {Point} [center] The center for the scaling transformation + * @return {Matrix} This affine transform */ /** * Concatentates this transform with a scaling transformation. * * @name Matrix#scale * @function - * @param {Number} hor The horizontal scaling factor. - * @param {Number} ver The vertical scaling factor. - * @param {Point} [center] The center for the scaling - * transformation. - * @return {Matrix} This affine transform. + * @param {Number} hor The horizontal scaling factor + * @param {Number} ver The vertical scaling factor + * @param {Point} [center] The center for the scaling transformation + * @return {Matrix} This affine transform */ scale: function(hor, ver /* | scale */, center) { if (arguments.length < 2 || typeof ver === 'object') { @@ -138,10 +135,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ } if (center) this.translate(center); - this._m00 *= hor; - this._m10 *= hor; - this._m01 *= ver; - this._m11 *= ver; + this._a *= hor; + this._c *= hor; + this._b *= ver; + this._d *= ver; if (center) this.translate(center.negate()); return this; @@ -152,23 +149,23 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * * @name Matrix#translate * @function - * @param {Point} point The vector to translate by. - * @return {Matrix} This affine transform. + * @param {Point} point The vector to translate by + * @return {Matrix} This affine transform */ /** * Concatentates this transform with a translate transformation. * * @name Matrix#translate * @function - * @param {Number} dx The distance to translate in the x direction. - * @param {Number} dy The distance to translate in the y direction. - * @return {Matrix} This affine transform. + * @param {Number} dx The distance to translate in the x direction + * @param {Number} dy The distance to translate in the y direction + * @return {Matrix} This affine transform */ translate: function(point) { point = Point.read(arguments); var x = point.x, y = point.y; - this._m02 += x * this._m00 + y * this._m01; - this._m12 += x * this._m10 + y * this._m11; + this._tx += x * this._a + y * this._b; + this._ty += x * this._c + y * this._d; return this; }, @@ -178,9 +175,9 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * * @name Matrix#rotate * @function - * @param {Number} angle The angle of rotation measured in degrees. - * @param {Point} center The anchor point to rotate around. - * @return {Matrix} This affine transform. + * @param {Number} angle The angle of rotation measured in degrees + * @param {Point} center The anchor point to rotate around + * @return {Matrix} This affine transform */ /** * Concatentates this transform with a rotation transformation around an @@ -188,10 +185,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * * @name Matrix#rotate * @function - * @param {Number} angle The angle of rotation measured in degrees. - * @param {Number} x The x coordinate of the anchor point. - * @param {Number} y The y coordinate of the anchor point. - * @return {Matrix} This affine transform. + * @param {Number} angle The angle of rotation measured in degrees + * @param {Number} x The x coordinate of the anchor point + * @param {Number} y The y coordinate of the anchor point + * @return {Matrix} This affine transform */ rotate: function(angle, center) { return this.concatenate( @@ -203,19 +200,19 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * * @name Matrix#shear * @function - * @param {Point} point The shear factor in x and y direction. - * @param {Point} [center] The center for the shear transformation. - * @return {Matrix} This affine transform. + * @param {Point} point The shear factor in x and y direction + * @param {Point} [center] The center for the shear transformation + * @return {Matrix} This affine transform */ /** * Concatentates this transform with a shear transformation. * * @name Matrix#shear * @function - * @param {Number} hor The horizontal shear factor. - * @param {Number} ver The vertical shear factor. - * @param {Point} [center] The center for the shear transformation. - * @return {Matrix} This affine transform. + * @param {Number} hor The horizontal shear factor + * @param {Number} ver The vertical shear factor + * @param {Point} [center] The center for the shear transformation + * @return {Matrix} This affine transform */ shear: function(hor, ver, center) { // See #scale() for explanation of this: @@ -227,12 +224,12 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ } if (center) this.translate(center); - var m00 = this._m00; - var m10 = this._m10; - this._m00 += ver * this._m01; - this._m10 += ver * this._m11; - this._m01 += hor * m00; - this._m11 += hor * m10; + var a = this._a, + c = this._c; + this._a += ver * this._b; + this._c += ver * this._d; + this._b += hor * a; + this._d += hor * c; if (center) this.translate(center.negate()); return this; @@ -243,96 +240,104 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ */ toString: function() { var format = Base.formatNumber; - return '[[' + [format(this._m00), format(this._m01), - format(this._m02)].join(', ') + '], [' - + [format(this._m10), format(this._m11), - format(this._m12)].join(', ') + ']]'; + return '[[' + [format(this._a), format(this._b), + format(this._tx)].join(', ') + '], [' + + [format(this._c), format(this._d), + format(this._ty)].join(', ') + ']]'; }, /** - * The scaling factor in the x-direction (m00). + * The scaling factor in the x-direction ({@code a}). * * @name Matrix#scaleX * @type Number */ /** - * The scaling factor in the y-direction (m11). + * The scaling factor in the y-direction ({@code d}). * * @name Matrix#scaleY * @type Number */ /** - * The translation in the x-direction (m02). - * - * @name Matrix#translateX - * @type Number - */ - - /** - * The translation in the y-direction (m12). - * - * @name Matrix#translateY - * @type Number - */ - - /** - * @return {Number} The shear factor in the x-direction (m01). + * @return {Number} The shear factor in the x-direction ({@code b}). * * @name Matrix#shearX * @type Number */ /** - * @return {Number} The shear factor in the y-direction (m10). + * @return {Number} The shear factor in the y-direction ({@code c}). * * @name Matrix#shearY * @type Number */ + /** + * The translation in the x-direction ({@code tx}). + * + * @name Matrix#translateX + * @type Number + */ + + /** + * The translation in the y-direction ({@code ty}). + * + * @name Matrix#translateY + * @type Number + */ + + /** + * The transform values as an array, in the same sequence as they are passed + * to {@link #initialize(a, c, b, d, tx, ty)}. + * + * @type Number[] + * @bean + */ + getValues: function() { + return [ this._a, this._c, this._b, this._d, this._tx, this._ty ]; + }, + /** * Concatenates an affine transform to this transform. * - * @param {Matrix} mx The transform to concatenate. - * @return {Matrix} This affine transform. + * @param {Matrix} mx The transform to concatenate + * @return {Matrix} This affine transform */ concatenate: function(mx) { - var m0 = this._m00, - m1 = this._m01; - this._m00 = mx._m00 * m0 + mx._m10 * m1; - this._m01 = mx._m01 * m0 + mx._m11 * m1; - this._m02 += mx._m02 * m0 + mx._m12 * m1; - - m0 = this._m10; - m1 = this._m11; - this._m10 = mx._m00 * m0 + mx._m10 * m1; - this._m11 = mx._m01 * m0 + mx._m11 * m1; - this._m12 += mx._m02 * m0 + mx._m12 * m1; + var a = this._a, + b = this._b, + c = this._c, + d = this._d; + this._a = mx._a * a + mx._c * b; + this._b = mx._b * a + mx._d * b; + this._tx += mx._tx * a + mx._ty * b; + this._c = mx._a * c + mx._c * d; + this._d = mx._b * c + mx._d * d; + this._ty += mx._tx * c + mx._ty * d; return this; }, /** * Pre-concatenates an affine transform to this transform. * - * @param {Matrix} mx The transform to preconcatenate. - * @return {Matrix} This affine transform. + * @param {Matrix} mx The transform to preconcatenate + * @return {Matrix} This affine transform */ preConcatenate: function(mx) { - var m0 = this._m00, - m1 = this._m10; - this._m00 = mx._m00 * m0 + mx._m01 * m1; - this._m10 = mx._m10 * m0 + mx._m11 * m1; - - m0 = this._m01; - m1 = this._m11; - this._m01 = mx._m00 * m0 + mx._m01 * m1; - this._m11 = mx._m10 * m0 + mx._m11 * m1; - - m0 = this._m02; - m1 = this._m12; - this._m02 = mx._m00 * m0 + mx._m01 * m1 + mx._m02; - this._m12 = mx._m10 * m0 + mx._m11 * m1 + mx._m12; + var a = this._a, + b = this._b, + c = this._c, + d = this._d, + tx = this._tx, + ty = this._ty; + this._a = mx._a * a + mx._b * c; + this._c = mx._c * a + mx._d * c; + this._b = mx._a * b + mx._b * d; + this._d = mx._c * b + mx._d * d; + this._tx = mx._a * tx + mx._b * ty + mx._tx; + this._ty = mx._c * tx + mx._d * ty + mx._ty; return this; }, @@ -341,16 +346,15 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * the result. If an array is transformed, the the result is stored into a * destination array. * - * @param {Point} point The point to be transformed. - * + * @param {Point} point The point to be transformed * @param {Number[]} src The array containing the source points - * as x, y value pairs. - * @param {Number} srcOff The offset to the first point to be transformed. + * as x, y value pairs + * @param {Number} srcOff The offset to the first point to be transformed * @param {Number[]} dst The array into which to store the transformed - * point pairs. + * point pairs * @param {Number} dstOff The offset of the location of the first - * transformed point in the destination array. - * @param {Number} numPts The number of points to tranform. + * transformed point in the destination array + * @param {Number} numPts The number of points to tranform */ transform: function(/* point | */ src, srcOff, dst, dstOff, numPts) { return arguments.length < 5 @@ -369,8 +373,8 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ if (!dest) dest = new Point(Point.dont); return dest.set( - x * this._m00 + y * this._m01 + this._m02, - x * this._m10 + y * this._m11 + this._m12, + x * this._a + y * this._b + this._tx, + x * this._c + y * this._d + this._ty, dontNotify ); }, @@ -381,8 +385,8 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ while (i < srcEnd) { var x = src[i++]; var y = src[i++]; - dst[j++] = x * this._m00 + y * this._m01 + this._m02; - dst[j++] = x * this._m10 + y * this._m11 + this._m12; + dst[j++] = x * this._a + y * this._b + this._tx; + dst[j++] = x * this._c + y * this._d + this._ty; } return dst; }, @@ -418,60 +422,61 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ }, /** - * @return {Number} The determinant of this transform. + * @return {Number} The determinant of this transform */ getDeterminant: function() { - return this._m00 * this._m11 - this._m01 * this._m10; + return this._a * this._d - this._b * this._c; }, getTranslation: function() { - return new Point(this._m02, this._m12); + return new Point(this._tx, this._ty); }, getScaling: function() { - var hor = Math.sqrt(this._m00 * this._m00 + this._m10 * this._m10), - ver = Math.sqrt(this._m01 * this._m01 + this._m11 * this._m11); - return new Point(this._m00 < 0 ? -hor : hor, this._m01 < 0 ? -ver : ver); + var hor = Math.sqrt(this._a * this._a + this._c * this._c), + ver = Math.sqrt(this._b * this._b + this._d * this._d); + return new Point(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); }, /** - * @return {Number} The rotation angle of the matrix. If a non-uniform + * Returns the rotation angle of the matrix. If a non-uniform * rotation is applied as a result of a shear() or scale() command, * undefined is returned, as the resulting transformation cannot be - * expressed in one rotation angle. + * expressed in one rotation angle + * @return {Number} The rotation angle of the matrix */ getRotation: function() { - var angle1 = -Math.atan2(this._m01, this._m11), - angle2 = Math.atan2(this._m10, this._m00); + var angle1 = -Math.atan2(this._b, this._d), + angle2 = Math.atan2(this._c, this._a); return Math.abs(angle1 - angle2) < Numerical.TOLERANCE ? angle1 * 180 / Math.PI : undefined; }, /** - * @return {Boolean} Whether this transform is the identity transform. + * @return {Boolean} Whether this transform is the identity transform */ isIdentity: function() { - return this._m00 == 1 && this._m10 == 0 && this._m01 == 0 && - this._m11 == 1 && this._m02 == 0 && this._m12 == 0; + return this._a == 1 && this._c == 0 && this._b == 0 && this._d == 1 + && this._tx == 0 && this._ty == 0; }, /** * Returns whether the transform is invertible. A transform is not * invertible if the determinant is 0 or any value is non-finite or NaN. * - * @return {Boolean} Whether the transform is invertible. + * @return {Boolean} Whether the transform is invertible */ isInvertible: function() { var det = this.getDeterminant(); - return isFinite(det) && det != 0 && isFinite(this._m02) - && isFinite(this._m12); + return isFinite(det) && det != 0 && isFinite(this._tx) + && isFinite(this._ty); }, /** * Checks whether the matrix is singular or not. Singular matrices cannot be * inverted. * - * @return {Boolean} Whether the matrix is singular. + * @return {Boolean} Whether the matrix is singular */ isSingular: function() { return !this.isInvertible(); @@ -483,33 +488,33 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ * returned. * * @return {Matrix} The inverted matrix, or {@code null }, if the matrix is - * singular. + * singular */ createInverse: function() { var det = this.getDeterminant(); - if (isFinite(det) && det != 0 && isFinite(this._m02) - && isFinite(this._m12)) { + if (isFinite(det) && det != 0 && isFinite(this._tx) + && isFinite(this._ty)) { return Matrix.create( - this._m11 / det, - -this._m10 / det, - -this._m01 / det, - this._m00 / det, - (this._m01 * this._m12 - this._m11 * this._m02) / det, - (this._m10 * this._m02 - this._m00 * this._m12) / det); + this._d / det, + -this._c / det, + -this._b / det, + this._a / det, + (this._b * this._ty - this._d * this._tx) / det, + (this._c * this._tx - this._a * this._ty) / det); } return null; }, createShiftless: function() { - return Matrix.create(this._m00, this._m10, this._m01, this._m11, 0, 0); + return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); }, /** * Sets this transform to a scaling transformation. * - * @param {Number} hor The horizontal scaling factor. - * @param {Number} ver The vertical scaling factor. - * @return {Matrix} This affine transform. + * @param {Number} hor The horizontal scaling factor + * @param {Number} ver The vertical scaling factor + * @return {Matrix} This affine transform */ setToScale: function(hor, ver) { return this.set(hor, 0, 0, ver, 0, 0); @@ -518,9 +523,9 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Sets this transform to a translation transformation. * - * @param {Number} dx The distance to translate in the x direction. - * @param {Number} dy The distance to translate in the y direction. - * @return {Matrix} This affine transform. + * @param {Number} dx The distance to translate in the x direction + * @param {Number} dy The distance to translate in the y direction + * @return {Matrix} This affine transform */ setToTranslation: function(delta) { delta = Point.read(arguments); @@ -530,9 +535,9 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Sets this transform to a shearing transformation. * - * @param {Number} hor The horizontal shear factor. - * @param {Number} ver The vertical shear factor. - * @return {Matrix} This affine transform. + * @param {Number} hor The horizontal shear factor + * @param {Number} ver The vertical shear factor + * @return {Matrix} This affine transform */ setToShear: function(hor, ver) { return this.set(1, ver, hor, 1, 0, 0); @@ -541,10 +546,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Sets this transform to a rotation transformation. * - * @param {Number} angle The angle of rotation measured in degrees. - * @param {Number} x The x coordinate of the anchor point. - * @param {Number} y The y coordinate of the anchor point. - * @return {Matrix} This affine transform. + * @param {Number} angle The angle of rotation measured in degrees + * @param {Number} x The x coordinate of the anchor point + * @param {Number} y The y coordinate of the anchor point + * @return {Matrix} This affine transform */ setToRotation: function(angle, center) { center = Point.read(arguments, 1); @@ -566,25 +571,23 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ */ applyToContext: function(ctx, reset) { ctx[reset ? 'setTransform' : 'transform']( - this._m00, this._m10, this._m01, - this._m11, this._m02, this._m12 - ); + this._a, this._c, this._b, this._d, this._tx, this._ty); return this; }, statics: /** @lends Matrix */{ // See Point.create() - create: function(m00, m10, m01, m11, m02, m12) { - return new Matrix(Matrix.dont).set(m00, m10, m01, m11, m02, m12); + create: function(a, c, b, d, tx, ty) { + return new Matrix(Matrix.dont).set(a, c, b, d, tx, ty); }, /** * Creates a transform representing a scaling transformation. * - * @param {Number} hor The horizontal scaling factor. - * @param {Number} ver The vertical scaling factor. + * @param {Number} hor The horizontal scaling factor + * @param {Number} ver The vertical scaling factor * @return {Matrix} A transform representing a scaling - * transformation. + * transformation */ getScaleInstance: function(hor, ver) { var mx = new Matrix(); @@ -594,10 +597,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Creates a transform representing a translation transformation. * - * @param {Number} dx The distance to translate in the x direction. - * @param {Number} dy The distance to translate in the y direction. + * @param {Number} dx The distance to translate in the x direction + * @param {Number} dy The distance to translate in the y direction * @return {Matrix} A transform representing a translation - * transformation. + * transformation */ getTranslateInstance: function(delta) { var mx = new Matrix(); @@ -607,9 +610,9 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Creates a transform representing a shearing transformation. * - * @param {Number} hor The horizontal shear factor. - * @param {Number} ver The vertical shear factor. - * @return {Matrix} A transform representing a shearing transformation. + * @param {Number} hor The horizontal shear factor + * @param {Number} ver The vertical shear factor + * @return {Matrix} A transform representing a shearing transformation */ getShearInstance: function(hor, ver, center) { var mx = new Matrix(); @@ -619,10 +622,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ /** * Creates a transform representing a rotation transformation. * - * @param {Number} angle The angle of rotation measured in degrees. - * @param {Number} x The x coordinate of the anchor point. - * @param {Number} y The y coordinate of the anchor point. - * @return {Matrix} A transform representing a rotation transformation. + * @param {Number} angle The angle of rotation measured in degrees + * @param {Number} x The x coordinate of the anchor point + * @param {Number} y The y coordinate of the anchor point + * @return {Matrix} A transform representing a rotation transformation */ getRotateInstance: function(angle, center) { var mx = new Matrix(); @@ -631,12 +634,12 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ } }, new function() { return Base.each({ - scaleX: '_m00', - scaleY: '_m11', - translateX: '_m02', - translateY: '_m12', - shearX: '_m01', - shearY: '_m10' + scaleX: '_a', + scaleY: '_d', + translateX: '_tx', + translateY: '_ty', + shearX: '_b', + shearY: '_c' }, function(prop, name) { name = Base.capitalize(name); this['get' + name] = function() { diff --git a/src/basic/Point.js b/src/basic/Point.js index f01c8fbd..b8d0dc1a 100644 --- a/src/basic/Point.js +++ b/src/basic/Point.js @@ -390,7 +390,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{ * is not modified! * * @param {Matrix} matrix - * @return {Point} the transformed point + * @return {Point} The transformed point */ transform: function(matrix) { return matrix ? matrix._transformPoint(this) : this; @@ -402,13 +402,16 @@ var Point = this.Point = Base.extend(/** @lends Point# */{ * Returns the distance between the point and another point. * * @param {Point} point + * @param {Boolean} squared Controls whether the distance should remain + * squared, or its square root should be calculated. * @return {Number} */ - getDistance: function(point) { + getDistance: function(point, squared) { point = Point.read(arguments); var x = point.x - this.x, - y = point.y - this.y; - return Math.sqrt(x * x + y * y); + y = point.y - this.y, + d = x * x + y * y; + return squared ? d : Math.sqrt(d); }, /** @@ -421,7 +424,11 @@ var Point = this.Point = Base.extend(/** @lends Point# */{ * @bean */ getLength: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); + // Supports a hidden parameter 'squared', which controls whether the + // squared length should be returned. Hide it so it produces a bean + // property called #length. + var l = this.x * this.x + this.y * this.y; + return arguments[0] ? l : Math.sqrt(l); }, setLength: function(length) { @@ -453,8 +460,8 @@ var Point = this.Point = Base.extend(/** @lends Point# */{ * {@code length} parameter defines the length to normalize to. * The object itself is not modified! * - * @param {Number} [length=1] the length of the normalized vector - * @return {Point} the normalized vector of the vector that is represented + * @param {Number} [length=1] The length of the normalized vector + * @return {Point} The normalized vector of the vector that is represented * by this point's coordinates. */ normalize: function(length) { diff --git a/src/browser/DomElement.js b/src/browser/DomElement.js index 913d00ac..b78da03e 100644 --- a/src/browser/DomElement.js +++ b/src/browser/DomElement.js @@ -14,96 +14,72 @@ * All rights reserved. */ -var DomElement = new function() { - function cumulateOffset(el, name, parent, test) { - var left = name + 'Left', - top = name + 'Top', - x = 0, - y = 0, - style; - // If we're asked to calculate positioned offset, stop at any parent - // element that has relative or absolute position. - while (el && el.style && (!test || !test.test( - style = DomElement.getComputedStyle(el, 'position')))) { - x += el[left] || 0; - y += el[top] || 0; - el = el[parent]; +/** + * @name DomElement + * @namespace + * @private + */ +var DomElement = { + getBounds: function(el, viewport) { + var rect = el.getBoundingClientRect(), + doc = el.ownerDocument, + body = doc.body, + docEl = doc.documentElement, + x = rect.left - (docEl.clientLeft || body.clientLeft || 0), + y = rect.top - (docEl.clientTop || body.clientTop || 0); + if (!viewport) { + var win = DomElement.getViewport(doc); + x += win.pageXOffset || docEl.scrollLeft || body.scrollLeft; + y += win.pageYOffset || docEl.scrollTop || body.scrollTop; } - return { - offset: Point.create(x, y), - element: el, - style: style - }; + return new Rectangle(x, y, rect.width, rect.height); + }, + + getOffset: function(el, viewport) { + return this.getBounds(el, viewport).getPoint(); + }, + + getSize: function(el) { + return this.getBounds(el, true).getSize(); + }, + + /** + * Checks if element is invisibile (display: none, ...) + */ + isInvisible: function(el) { + return this.getSize(el).equals([0, 0]); + }, + + /** + * Checks if element is visibile in current viewport + */ + isVisible: function(el) { + // See if the viewport bounds intersect with the windows rectangle + // which always starts at 0, 0 + return !this.isInvisible(el) && this.getViewportBounds(el).intersects( + this.getBounds(el, true)); + }, + + getViewport: function(doc) { + return doc.defaultView || doc.parentWindow; + }, + + getViewportBounds: function(el) { + var doc = el.ownerDocument, + view = this.getViewport(doc), + body = doc.getElementsByTagName( + doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; + return Rectangle.create(0, 0, + view.innerWidth || body.clientWidth, + view.innerHeight || body.clientHeight + ); + }, + + getComputedStyle: function(el, name) { + if (el.currentStyle) + return el.currentStyle[Base.camelize(name)]; + var style = this.getViewport(el.ownerDocument) + .getComputedStyle(el, null); + return style ? style.getPropertyValue(Base.hyphenate(name)) : null; } - - function getScrollOffset(el, test) { - return cumulateOffset(el, 'scroll', 'parentNode', test).offset; - } - - return { - getOffset: function(el, positioned, viewport) { - var res = cumulateOffset(el, 'offset', 'offsetParent', - positioned ? /^(relative|absolute|fixed)$/ : /^fixed$/); - // We need to handle fixed positioned elements seperately if we're - // asked to calculate offsets within the page (= not within - // viewport), by adding their scroll offset to the result. - if (res.style == 'fixed' && !viewport) - return res.offset.add(getScrollOffset(res.element)); - // Otherwise remove scrolling from the calculated offset if we asked - // for viewport coordinates - return viewport - ? res.offset.subtract(getScrollOffset(el, /^fixed$/)) - : res.offset; - }, - - getSize: function(el) { - return Size.create(el.offsetWidth, el.offsetHeight); - }, - - getBounds: function(el, positioned, viewport) { - return new Rectangle(this.getOffset(el, positioned, viewport), - this.getSize(el)); - }, - - /** - * Checks if element is invisibile (display: none, ...) - */ - isInvisible: function(el) { - return this.getSize(el).equals([0, 0]); - }, - - /** - * Checks if element is visibile in current viewport - */ - isVisible: function(el) { - // See if the viewport bounds intersect with the windows rectangle - // which always starts at 0, 0 - return !this.isInvisible(el) - && new Rectangle([0, 0], this.getViewportSize(el)) - .intersects(this.getBounds(el, false, true)); - }, - - getViewport: function(doc) { - return doc.defaultView || doc.parentWindow; - }, - - getViewportSize: function(el) { - var doc = el.ownerDocument, - view = this.getViewport(doc), - body = doc.getElementsByTagName( - doc.compatMode === 'CSS1Compat' ? 'html' : 'body')[0]; - return Size.create( - view.innerWidth || body.clientWidth, - view.innerHeight || body.clientHeight - ); - }, - - getComputedStyle: function(el, name) { - if (el.currentStyle) - return el.currentStyle[Base.camelize(name)]; - var style = this.getViewport(el.ownerDocument) - .getComputedStyle(el, null); - return style ? style.getPropertyValue(Base.hyphenate(name)) : null; - } - }; }; diff --git a/src/browser/DomEvent.js b/src/browser/DomEvent.js index 771c3ac6..4e142cfc 100644 --- a/src/browser/DomEvent.js +++ b/src/browser/DomEvent.js @@ -14,6 +14,11 @@ * All rights reserved. */ +/** + * @name DomEvent + * @namespace + * @private + */ var DomEvent = { add: function(el, events) { for (var type in events) { @@ -60,8 +65,8 @@ var DomEvent = { getOffset: function(event, target) { // Remove target offsets from page coordinates - return DomEvent.getPoint(event).subtract( - DomElement.getOffset(target || DomEvent.getTarget(event), true)); + return DomEvent.getPoint(event).subtract(DomElement.getOffset( + target || DomEvent.getTarget(event))); }, preventDefault: function(event) { diff --git a/src/color/Color.js b/src/color/Color.js index 2274b38c..6e296653 100644 --- a/src/color/Color.js +++ b/src/color/Color.js @@ -746,8 +746,8 @@ var HSLColor = this.HSLColor = Color.extend(/** @lends HSLColor# */{ * var circle = new Path.Circle(new Point(80, 50), 30); * * // Create an HSLColor with a hue of 90 degrees, a saturation - * // 100% and a lightness of 100%: - * circle.fillColor = new HSLColor(90, 1, 1); + * // 100% and a lightness of 50%: + * circle.fillColor = new HSLColor(90, 1, 0.5); */ _colorType: 'hsl' diff --git a/src/core/PaperScope.js b/src/core/PaperScope.js index 0a8f43b7..c3798cf2 100644 --- a/src/core/PaperScope.js +++ b/src/core/PaperScope.js @@ -39,31 +39,25 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{ /** - * Creates a PaperScope object and an empty {@link Project} for it. If a - * canvas is provided, it also creates a {@link View} for it. - * Both project and view are linked to this scope. + * Creates a PaperScope object. * * @name PaperScope#initialize * @function - * @param {HTMLCanvasElement} canvas The canvas this scope should be - * associated with. */ - initialize: function(canvas, script) { + initialize: function(script) { // script is only used internally, when creating scopes for PaperScript. // Whenever a PaperScope is created, it automatically becomes the active // one. paper = this; - this.views = []; this.view = null; + this.views = []; + this.project = null; this.projects = []; - // Since the global paper variable points to this PaperScope, the - // created project and view are automatically associated with it. - this.project = new Project(); this.tool = null; this.tools = []; - var obj = script || canvas; - this._id = obj && obj.getAttribute('id') - || script && script.src + // Assign an id to this canvas that's either extracted from the script + // or automatically generated. + this._id = script && (script.getAttribute('id') || script.src) || ('paperscope-' + (PaperScope._id++)); // Make sure the script tag also has this id now. If it already had an // id, we're not changing it, since it's the first option we're @@ -71,10 +65,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{ if (script) script.setAttribute('id', this._id); PaperScope._scopes[this._id] = this; - if (canvas) { - // Create a view for the canvas. - this.view = new View(canvas); - } }, /** @@ -136,11 +126,43 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{ * paper.install(window); */ install: function(scope) { - // Use scope as side-car (= 'this' inside iterator), and have it - // returned at the end. - return Base.each(this, function(value, key) { - this[key] = value; - }, scope); + // Define project, view and tool as getters that redirect to these + // values on the PaperScope, so they are kept up to date + var that = this; + Base.each(['project', 'view', 'tool'], function(key) { + Base.define(scope, key, { + configurable: true, + writable: true, + get: function() { + return that[key]; + } + }); + }); + // Copy over all fields from this scope to the destination. + // Do not use Base.each, since we also want to enumerate over + // fields on PaperScope.prototype, e.g. all classes + for (var key in this) { + if (!/^(version|_id|load)/.test(key) && !(key in scope)) + scope[key] = this[key]; + } + }, + + /** + * Sets up an empty project for us. If a canvas is provided, it also creates + * a {@link View} for it, both linked to this scope. + * + * @param {HTMLCanvasElement} canvas The canvas this scope should be + * associated with. + */ + setup: function(canvas) { + // Create an empty project for the scope. + // Make sure this is the active scope, so the created project and view + // are automatically associated with it. + paper = this; + this.project = new Project(); + // Create a view for the canvas. + if (canvas) + this.view = new View(canvas); }, clear: function() { diff --git a/src/core/PaperScript.js b/src/core/PaperScript.js index 2f879558..d9b91dda 100644 --- a/src/core/PaperScript.js +++ b/src/core/PaperScript.js @@ -100,7 +100,7 @@ var PaperScript = this.PaperScript = new function() { // Use parse-js to translate the code into a AST structure which is then // walked and parsed for operators to overload. The resulting AST is // translated back to code and evaluated. - var ast = parse_js.parse(code, true), + var ast = parse_js.parse(code), walker = parse_js.ast_walker(), walk = walker.walk; @@ -144,8 +144,7 @@ var PaperScript = this.PaperScript = new function() { /** * Evaluates parsed PaperScript code in the passed {@link PaperScope} - * object. It also handles canvas setup, tool creation and handlers - * automatically for us. + * object. It also installs handlers automatically for us. * * @name PaperScript.evaluate * @function @@ -194,12 +193,9 @@ var PaperScript = this.PaperScript = new function() { } if (view) { view.onResize = onResize; - if (onFrame) { - view.setOnFrame(onFrame); - } else { - // Automatically draw view at the end. - view.draw(); - } + view.setOnFrame(onFrame); + // Automatically draw view at the end. + view.draw(); } }).call(scope); } @@ -240,7 +236,8 @@ var PaperScript = this.PaperScript = new function() { // so a project is created for it now. var canvas = PaperScript.getAttribute(script, 'canvas'); canvas = canvas && document.getElementById(canvas); - var scope = new PaperScope(canvas, script); + var scope = new PaperScope(script); + scope.setup(canvas); if (script.src) { // If we're loading from a source, request that first and then // run later. diff --git a/src/core/initialize.js b/src/core/initialize.js index 38b59a39..10a96b6d 100644 --- a/src/core/initialize.js +++ b/src/core/initialize.js @@ -19,13 +19,19 @@ // that allow us to use their names. // Setting Function#name is not possible, as that is read-only. Base.each(this, function(val, key) { - if (val && val.prototype instanceof Base) + if (val && val.prototype instanceof Base) { val._name = key; +/*#*/ if (options.version == 'dev') { + // If we're in dev mode, also export all classes through PaperScope, to + // mimick scoping behavior of the built library. + PaperScope.prototype[key] = val; +/*#*/ } // options.version == 'dev' + } }); /*#*/ if (options.version == 'dev') { -// We're already leaking into the global scope, so let's just assign the global -// paper object with a prepare scope. See paper.js for the non-dev version of -// this code. +// See paper.js for the non-dev version of this code. We cannot handle dev there +// due to the seperate loading of all source files, which are only availabe +// after the execution of paper.js paper = new PaperScope(); /*#*/ } // options.version == 'dev' diff --git a/src/item/HitResult.js b/src/item/HitResult.js index b7904628..50c5240e 100644 --- a/src/item/HitResult.js +++ b/src/item/HitResult.js @@ -17,9 +17,9 @@ /** * @name HitResult * - * @class - * - * @extends CurveLocation + * @class A HitResult object contains information about the results of a hit + * test. It is returned by {@link Item#hitTest(point)} and + * {@link Project#hitTest(point)}. */ HitResult = Base.extend(/** @lends HitResult# */{ initialize: function(type, item, values) { @@ -34,6 +34,61 @@ HitResult = Base.extend(/** @lends HitResult# */{ } }, + /** + * Describes the type of the hit result. For example, if you hit a segment + * point, the type would be 'segment'. + * + * @property + * @name HitResult#type + * @type String('segment', 'handle-in', 'handle-out', 'stroke', 'fill', + * 'bounds', 'center') + */ + + /** + * If the HitResult has a {@link HitResult#type} of 'bounds', this property + * describes which corner of the bounding rectangle was hit. + * + * @property + * @name HitResult#name + * @type String('top-left', 'top-right', 'bottom-left', 'bottom-right', + * 'left-center', 'top-center', 'right-center', 'bottom-center') + */ + + /** + * The item that was hit. + * + * @property + * @name HitResult#item + * @type Item + */ + + /** + * If the HitResult has a type of 'stroke', this property gives more + * information about the exact position that was hit on the path. + * + * @property + * @name HitResult#location + * @type CurveLocation + */ + + /** + * If the HitResult has a type of 'stroke', 'segment', 'handle-in' or + * 'handle-out', this property refers to the Segment that was hit or that + * is closest to the hitResult.location on the curve. + * + * @property + * @name HitResult#segment + * @type Segment + */ + + /** + * The hit point. + * + * @property + * @name HitResult#point + * @type Point + */ + statics: { /** * Merges default options into options hash for #hitTest() calls, and diff --git a/src/item/Item.js b/src/item/Item.js index 938bc79a..75b73eef 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -682,6 +682,45 @@ var Item = this.Item = Base.extend(/** @lends Item# */{ return raster; }, + + + /** + * Perform a hit test on the item (and its children, if it is a + * {@link Group} or {@link Layer}) at the location of the specified point. + * + * The optional options object allows you to control the specifics of the + * hit test and may contain a combination of the following values: + * tolerance: {@code Number} - The tolerance of the hit test in + * points. + * options.type: Only hit test again a certain item + * type: {@link PathItem}, {@link Raster}, {@link TextItem}, etc. + * options.fill: {@code Boolean} - Hit test the fill of items. + * options.stroke: {@code Boolean} - Hit test the curves of path + * items, taking into account stroke width. + * options.segment: {@code Boolean} - Hit test for + * {@link Segment#point} of {@link Path} items. + * options.handles: {@code Boolean} - Hit test for the handles + * ({@link Segment#handleIn} / {@link Segment#handleOut}) of path segments. + * options.ends: {@code Boolean} - Only hit test for the first or + * last segment points of open path items. + * options.bounds: {@code Boolean} - Hit test the corners and + * side-centers of the bounding rectangle of items ({@link Item#bounds}). + * options.center: {@code Boolean} - Hit test the + * {@link Rectangle#center} of the bounding rectangle of items + * ({@link Item#bounds}). + * options.guide: {@code Boolean} - Hit test items that have + * {@link Item#guide} set to {@code true}. + * options.selected: {@code Boolean} - Only hit selected items. + * + * @name Item#hitTest + * @function + * @param {Point} point The point where the hit test should be performed + * @param {Object} [options={ fill: true, stroke: true, segments: true, + * tolerance: 2 }] + * @return {HitResult} A hit result object that contains more + * information about what exactly was hit or {@code null} if nothing was + * hit. + */ hitTest: function(point, options, matrix) { options = HitResult.getOptions(point, options); point = options.point; diff --git a/src/paper.js b/src/paper.js index 14668b21..ce46aefe 100644 --- a/src/paper.js +++ b/src/paper.js @@ -134,6 +134,9 @@ var paper = new function() { // the first PaperScope and return it, all in one statement. // The version for 'dev' of this happens in core/initialize.js, since it depends // on sequentiality of include() loading. +// Mark this object as enumerable, so all the injected classes can be enumerated +// again in PaperScope#install(). +this.enumerable = true; return new (PaperScope.inject(this)); /*#*/ } // options.version != 'dev' }; diff --git a/src/path/Curve.js b/src/path/Curve.js index 1beb164e..74b560a0 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -760,8 +760,15 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{ return [0.5 * (w[0].x + w[5].x)]; // Compute intersection of chord from first control point to last // with x-axis. - if (isFlatEnough(w)) - return [xAxis.intersect(new Line(w[0], w[5], true)).x]; + if (isFlatEnough(w)) { + var line = new Line(w[0], w[5], true); + // Compare the line's squared length with EPSILON. If we're + // below, #intersect() will return null because of division + // by near-zero. + return [ line.vector.getLength(true) < Numerical.EPSILON + ? line.point.x + : xAxis.intersect(line).x ]; + } } // Otherwise, solve recursively after @@ -840,19 +847,20 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{ // Also look at beginning and end of curve (t = 0 / 1) var roots = findRoots(w, 0).concat([0, 1]); var minDist = Infinity, - minPoint, - minRoot; + minT, + minPoint; // There are always roots, since we add [0, 1] above. for (var i = 0; i < roots.length; i++) { var pt = this.getPoint(roots[i]), - dist = point.getDistance(pt); + dist = point.getDistance(pt, true); + // We're comparing squared distances if (dist < minDist) { minDist = dist; - minRoot = roots[i]; + minT = roots[i]; minPoint = pt; } } - return new CurveLocation(this, minRoot, minPoint, minDist); + return new CurveLocation(this, minT, minPoint, Math.sqrt(minDist)); }, getNearestPoint: function(point, matrix) { diff --git a/src/path/Path.js b/src/path/Path.js index 1638b5b3..adacd97c 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1174,6 +1174,15 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ return loc && loc.getNormal(); }, + /** + * Returns the nearest location on the path to the specified point. + * + * @name Path#getNearestLocation + * @function + * @param point {Point} The point for which we search the nearest location + * @return {CurveLocation} The location on the path that's the closest to + * the specified point + */ getNearestLocation: function(point, matrix) { var curves = this.getCurves(), minDist = Infinity, @@ -1188,6 +1197,15 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ return minLoc; }, + /** + * Returns the nearest point on the path to the specified point. + * + * @name Path#getNearestPoint + * @function + * @param point {Point} The point for which we search the nearest point + * @return {Point} The point on the path that's the closest to the specified + * point + */ getNearestPoint: function(point, matrix) { return this.getNearestLocation(point, matrix).getPoint(); }, diff --git a/src/project/Project.js b/src/project/Project.js index 53764300..ea141b06 100644 --- a/src/project/Project.js +++ b/src/project/Project.js @@ -181,6 +181,41 @@ var Project = this.Project = Base.extend(/** @lends Project# */{ this._selectedItems[i].setSelected(false); }, + /** + * Perform a hit test on the items contained within the project at the + * location of the specified point. + * + * The optional options object allows you to control the specifics of the + * hit test and may contain a combination of the following values: + * options.tolerance: {@code Number} - The tolerance of the hit test + * in points. + * options.type: Only hit test again a certain item + * type: {@link PathItem}, {@link Raster}, {@link TextItem}, etc. + * options.fill: {@code Boolean} - Hit test the fill of items. + * options.stroke: {@code Boolean} - Hit test the curves of path + * items, taking into account stroke width. + * options.segment: {@code Boolean} - Hit test for + * {@link Segment#point} of {@link Path} items. + * options.handles: {@code Boolean} - Hit test for the handles + * ({@link Segment#handleIn} / {@link Segment#handleOut}) of path segments. + * options.ends: {@code Boolean} - Only hit test for the first or + * last segment points of open path items. + * options.bounds: {@code Boolean} - Hit test the corners and + * side-centers of the bounding rectangle of items ({@link Item#bounds}). + * options.center: {@code Boolean} - Hit test the + * {@link Rectangle#center} of the bounding rectangle of items + * ({@link Item#bounds}). + * options.guide: {@code Boolean} - Hit test items that have + * {@link Item#guide} set to {@code true}. + * options.selected: {@code Boolean} - Only hit selected items. + * + * @param {Point} point The point where the hit test should be performed + * @param {Object} [options={ fill: true, stroke: true, segments: true, + * tolerance: true }] + * @return {HitResult} A hit result object that contains more + * information about what exactly was hit or {@code null} if nothing was + * hit. + */ hitTest: function(point, options) { options = HitResult.getOptions(point, options); point = options.point;