From ce73aaf4abf886859ce2c8be810b96565221d2c3 Mon Sep 17 00:00:00 2001 From: rfried Date: Fri, 20 Jul 2018 19:42:07 -0500 Subject: [PATCH] paper 11.5 comprehensive update (#27356) * Updating Matrix class to match 11.5 documentation and implementation. * Updating Point class to reflect 11.5 documentation and implementation. * Updating Rectangle class to reflect 11.5 documentation and implementation. * Updating Size class to reflect 11.5 documentation and implementation. * Updating PaperScope class to reflect 11.5 documentation and implementation. * Update Item class to better reflect 11.5 documentation and implementation. * Fixing up optional object property syntax in a couple places (',' should have been ';') * Updating Shaep class to better reflect 11.5 documentation and implementation. * Updating Raster class to better reflect 11.5 documentation and implementation. * Updating PathItem class to better reflect 11.5 documentation and implementation. Removed methods from Path that were inherited from PathItem. * Updating Path class to better reflect 11.5 documentation and implementation. * Updating CompoundPath class to better reflect 11.5 documentation and implementation. * Updating Segment class to better reflect 11.5 documentation and implementation. * Updating Curve class to better reflect 11.5 documentation and implementation. * Updating CurveLocation class to better reflect 11.5 documentation and implementation. * Updating Project class to better reflect 11.5 documentation and implementation. * Updating Symbol to better reflect 11.5 documentation and implementation. * Updating Style class to better reflect 11.5 documentation and implementation. * Updating GradientStop class to better reflect 11.5 documentation. * Updating Color class to better reflect 11.5 documentation and implementation. * Updating View class to better reflect 11.5 documentation and implementation. * Updating the event classes to better reflect 11.5 documentation and implementation. * Updating TextItem to better reflect 11.5 documentation and implementation. * More accurate return type guidance for event handlers. Small fix to resolve lint error (object[] changed to any[]). * Added name to 'Definitions by' section in header. * Adding an IHitTestOptions interface to improve the intellisense on a 14-property object capable of being paritally defined. Now users can create an object which includes any number of the 14 properties and get some guidance on what each property does. It's syntactic sugar and I'll allow that it may just be unecessary. * More hittest tests * Adding project to the hittest tests * After some testing I like the IHitTestOptions approach much better. It provides CTRL+SPACE intellisense with descriptions. It also allows any previous code that sent an object with at least 1 property to pass the test. As such I've removed the object literal as it increases future maintainence. * Updating hittests to make sure the right returns are coming from the hittest functions * test documentation * Adding the Example 'Boolean Operations' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Candy Crash' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * From reviewing the example Sadie Likes To Draw and looking through the implementation... it looks like the property "fully selected" is actually available on the parent Item and not first available on Path as indicated in the documentation. * Adding the Example 'SatieLikedToDraw' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Chain' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Tadpoles' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Nyan Rainbow' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Fixing a namespacing issue resolving the Rectangle class in the Path.Rectangle and Path.Ellipse constructors * Adding the Example 'Rounded Rectangles' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * The gradient components of a Color are sometimes undefined. Also origin and destination were missing from the documentation and definition. They are accessible for gradient colors. * Adding the Example 'Radial Rainbows' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Item's appendTop and appendBottom methods were hiding in the documentation. They aren't listed in the main Item class, they're listed as inherited by all its children. * Adding the Example 'Meta Balls' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Voronoi' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Future Splash' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Smoothing' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Spiral Raster' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Division Raster' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding equals and clone methods to Segment class. * Adding the Example 'Q-bertify' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Path Intersections' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Path Simplification' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Example 'Hit Testing' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Adding the Gradient constructor that is missing from the documentation. * Adding the Example 'Bouncing Balls' rewritten as typescript to the tests. This hopefully mimics what a user might have done to adapt the examples and ensure that all the example interfaces are implemented correctly. * Reading through the code and examples shows that there are a few more options for constructing the GradientStop class than documented officially. * Accidentally inserted a redundant declaration * More options for the Gradient class constructor. * Adding type-specific clones to all children of Item. This allows for user code to better reflect the clone operation without having to cast things all the time. * new constructor, addition, and insertiong parameter options for Paths in order to enable more streamlined code which better matches examples from the code reference. Namely the ability to shorthand a point/segment as [x,y] arrays. Fixing a weird type warning by adding yet another on/off event overload. * Added all of the example code found as paperscript inside the API documentation. Piece of code had to be rewritten to conform to typing strictness and I did my best to match the feel and brevity of the code. As possible I translated these shorthand notations into further improvements into the type definition. This included things like Point/Segment array shorthand for Path creation. To some degree I just applied my opinion on what users might prefer while still being guided by a type system. There are probably further tweaks we can make in this vein but I found the changes sufficient to make the example code require little porting effort. * I just realized that I have two github accounts. Before I have too many commits to my name I wanted to merge accounts and as a result I need to update my profile link in the 'Definitions by' header. --- types/paper/index.d.ts | 2049 ++++- types/paper/paper-tests.ts | 15230 ++++++++++++++++++++++++++++++++++- 2 files changed, 16846 insertions(+), 433 deletions(-) diff --git a/types/paper/index.d.ts b/types/paper/index.d.ts index e942fcec2e..ff75266725 100644 --- a/types/paper/index.d.ts +++ b/types/paper/index.d.ts @@ -3,6 +3,7 @@ // Definitions by: Clark Stevenson , // Jon Lucas , // Sebastian Lopez +// Ryan Friedman // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped type NativeMouseEvent = MouseEvent; @@ -90,6 +91,18 @@ declare module paper { */ constructor(a: number, c: number, b: number, d: number, tx: number, ty: number); + /** + * Creates a 2D affine transformation matrix + * @param array - the matrix values to initialize this matrix with + */ + constructor(values: number[]); + + /** + * Creates a 2D affine transformation matrix + * @param matrix - the matrix to copy the values from + */ + constructor(matrix: Matrix); + /** * The value that affects the transformation along the x axis when scaling or rotating, positioned at (0, 0) in the transformation matrix. */ @@ -124,25 +137,30 @@ declare module paper { * The transform values as an array, in the same sequence as they are passed to initialize(a, c,b,d,tx,ty). * Read only. */ - values: number; + readonly values: number[]; /** * The translation of the matrix as a vector. * Read only. */ - translation: Point; + readonly translation: Point; /** * The scaling values of the matrix, if it can be decomposed. * Read only. */ - scaling: Point; + readonly scaling: Point; /** * The rotation angle of the matrix, if it can be decomposed. * Read only. */ - rotation: number; + readonly rotation: number; + + /** + * Sets this transform to the matrix defaults + */ + set(): Matrix; /** * Sets this transform to the matrix specified by the 6 values. @@ -155,6 +173,18 @@ declare module paper { */ set(a: number, c: number, b: number, d: number, tx: number, ty: number): Matrix; + /** + * Sets a 2D affine transformation matrix + * @param array - the matrix values to set this matrix with + */ + set(values: number[]): Matrix; + + /** + * Sets a 2D affine transformation matrix + * @param matrix - the matrix to set the values from + */ + set(matrix: Matrix): Matrix; + /** * Returns a copy of this transform */ @@ -180,7 +210,7 @@ declare module paper { * Attempts to apply the matrix to the content of item that it belongs to, meaning its transformation is baked into the item's content or children. * @param recursively - controls whether to apply transformations recursively on children */ - apply(): boolean; + apply(recursively: boolean): boolean; /** * Concatenates this transform with a translate transformation. @@ -215,7 +245,7 @@ declare module paper { * @param angle - the angle of rotation measured in degrees * @param center - the anchor point to rotate around */ - rotate(angle: number, center?: Point): Matrix; + rotate(angle: number, center: Point): Matrix; /** * Concatenates this transform with a rotation transformation around an anchor point. @@ -273,6 +303,30 @@ declare module paper { */ chain(mx: Matrix): Matrix; + /** + * Prepends the specified matrix to this matrix. This is the equivalent of multiplying (specified matrix) * (this matrix). + * @param mx - the transform to concatenate + */ + append(mx: Matrix): Matrix; + + /** + * Pre-concatenates the given affine transform to this transform. + * @param mx - the transform to preconcatenate + */ + prepend(mx: Matrix): Matrix; + + /** + * Returns a new matrix as the result of appending the specified matrix to this matrix. This is the equivalent of multiplying (this matrix) * (specified matrix). + * @param mx - the transform to concatenate + */ + appended(mx: Matrix): Matrix; + + /** + * Returns a new matrix as the result of prepending the specified matrix to this matrix. This is the equivalent of multiplying (specified matrix) s* (this matrix). + * @param mx - the transform to concatenate + */ + prepended(mx: Matrix): Matrix; + /** * Returns whether this transform is the identity transform */ @@ -312,9 +366,14 @@ declare module paper { * Attempts to decompose the affine transformation described by this matrix into scaling, rotation and shearing, and returns an object with these properties if it succeeded, null otherwise. */ decompose(): any; + + /** + * Inverts the matrix, causing it to perform the opposite transformation. If the matrix is not invertible (in which case isSingular() returns true), null is returned. + */ + invert(): Matrix; /** - * Creates the inversion of the transformation of the matrix and returns it as a new insteance. If the matrix is not invertible (in which case isSingular() returns true), null is returned. + * Creates the inversion of the transformation of the matrix and returns it as a new instance. If the matrix is not invertible (in which case isSingular() returns true), null is returned. */ inverted(): Matrix; @@ -412,13 +471,44 @@ declare module paper { * Angles between 0 and 90 degrees are in quadrant 1. Angles between 90 and 180 degrees are in quadrant 2, angles between 180 and 270 degrees are in quadrant 3 and angles between 270 and 360 degrees are in quadrant 4. * Read only. */ - quadrant: number; + readonly quadrant: number; /** * This property is only present if the point is an anchor or control point of a Segment or a Curve. In this case, it returns true it is selected, false otherwise */ selected: boolean; + /** + * Sets the Point object with the given x and y coordinates. + * @param x - the x coordinate + * @param y - the y coordinate + */ + set(x: number, y: number): Point; + + /** + * Sets the Point object using the numbers in the given array as coordinates. + * @param array - an array of numbers to use as coordinates + */ + set(values: number[]): Point; + + /** + * Sets the Point object using the properties in the given object. + * @param object - the object describing the point's properties + */ + set(object: any): Point; + + /** + * Sets the Point object using the width and height values of the given Size object. + * @param size - the size width and height to use + */ + set(size: Size): Point; + + /** + * Sets the Point object using the coordinates of the given Point object. + * @param point - the point to copy + */ + set(point: Point): Point; + /** * Checks whether the coordinates of the point are equal to that of the supplied point. * @param point - the point to check against @@ -516,7 +606,14 @@ declare module paper { /** * Checks if this point has an undefined value for at least one of its coordinates. */ - isNan(): boolean; + isNaN(): boolean; + + /** + * Checks if the vector is within the specified quadrant. Note that if the vector lies on the boundary between two quadrants, true will be returned for both quadrants. + * @param quadrant + * @returns true if either x or y are not a number, false otherwise + */ + isInQuadrant(quadrant: number): boolean; /** * Returns the dot product of the point and another point. @@ -563,6 +660,7 @@ declare module paper { */ add(point: Point): Point; add(point: number[]): Point; + add(point: number): Point; /* * Returns a new point @@ -570,6 +668,7 @@ declare module paper { */ subtract(point: Point): Point; subtract(point: number[]): Point; + subtract(point: number): Point; /* * Returns the new multiplied point @@ -587,6 +686,14 @@ declare module paper { divide(point: number[]): Point; divide(point: number): Point; + /** + * The modulo operator returns the integer remainders of dividing the point by the supplied value as a new point + * @param point - The point you want to divide with + */ + modulo(point: Point): Point; + modulo(point: number[]): Point; + modulo(point: number): Point; + } /** * A Rectangle specifies an area that is enclosed by it's top-left point (x, y), its width, and its height. It should not be confused with a rectangular path, it is not an item. @@ -727,7 +834,7 @@ declare module paper { * The area of the rectangle in square points. * Read only. */ - area: number; + readonly area: number; /** * Specifies whether an item's bounds are selected and will also mark the item as selected. @@ -735,6 +842,41 @@ declare module paper { */ selected: boolean; + /** + * Sets the Rectangle object. + * @param point - the top-left point of the rectangle + * @param size - the size of the rectangle + */ + set(point: Point, size: Size): Rectangle; + + /** + * Sets the Rectangle object. + * @param object - an object containing properties to be set on the rectangle. + */ + set(object: any): Rectangle; + + /** + * Sets the Rectangle object. + * @param x - the left coordinate + * @param y - the top coordinate + * @param width - the width + * @param height - the height + */ + set(x: number, y: number, width: number, height: number): Rectangle; + + /** + * Sets the Rectangle object from the passed points. These do not necessarily need to be the top left and bottom right corners, the constructor figures out how to fit a rectangle between them. + * @param from - The first point defining the rectangle + * @param to - The second point defining the rectangle + */ + set(from: Point, to: Point): Rectangle; + + /** + * Sets the Rectangle object from the passed rectangle object. + * @param rt - the rectangle to copy from + */ + set(rt: Rectangle): Rectangle; + /** * Returns a copy of the rectangle. */ @@ -771,8 +913,10 @@ declare module paper { /** * Tests if the interior of this rectangle intersects the interior of another rectangle. Rectangles just touching each other are considered as non-intersecting. * @param rect - the specified rectangle + * @param epsilon - the epsilon against which to compare the rectangle’s dimensions. default 0 + * @returns true if the rectangle and the specified rectangle intersect each other, false */ - intersects(rect: Rectangle): boolean; + intersects(rect: Rectangle, epsilon?: number): boolean; /** * Returns a new rectangle representing the intersection of this rectangle with the specified rectangle. @@ -887,9 +1031,9 @@ declare module paper { height: number; /** - * WARNING - This seems undocumented/incorrect + * Checks whether the width and height of the size are equal to those of the supplied size. */ - equals(): boolean; + equals(size: Size): boolean; /** * Returns a copy of the size. @@ -909,7 +1053,7 @@ declare module paper { /** * Checks if the width or the height of the size are NaN. */ - isNan(): boolean; + isNaN(): boolean; /** * Returns a new size with rounded width and height values. The object itself is not modified! @@ -937,6 +1081,7 @@ declare module paper { */ add(size: Size): Size; add(size: number[]): Size; + add(size: number): Size; /* * Returns a new size @@ -944,6 +1089,7 @@ declare module paper { */ subtract(size: Size): Size; subtract(size: number[]): Size; + subtract(size: number): Size; /* * Returns the new multiplied size @@ -961,6 +1107,14 @@ declare module paper { divide(size: number[]): Size; divide(size: number): Size; + /** + * Returns the new modulo size + * @param size - The size you want to modulo with + */ + modulo(size: Size): Size; + modulo(size: number[]): Size; + modulo(size: number): Size; + } export interface IFrameEvent { @@ -1018,7 +1172,7 @@ declare module paper { * The reference to the active project's view. * Read Only. */ - view: View; + readonly view: View; /** * The reference to the active tool. @@ -1030,6 +1184,15 @@ declare module paper { */ tools: Tool[]; + /** + * Compiles the PaperScript code into a compiled function and executes it. The compiled function receives all properties of this PaperScope as arguments, to emulate a global scope with unaffected performance. It also installs global view and tool handlers automatically on the respective objects. + * @param code - the PaperScript code + * @param options [optional] - the compilation options + * @param options.url - the url of the source, for source-map debugging + * @param options.source - the source to be used for the source- mapping, in case the code that’s passed in has already been mingled. + */ + execute(code: string, option?:{url?:string; source?:string; }): void; + /** * 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 * Please note: Using this method may override native constructors (e.g. Path, RGBColor). This may cause problems when using Paper.js in conjunction with other libraries that rely on these constructors. Keep the library scoped if you encounter issues caused by this. @@ -1050,10 +1213,83 @@ declare module paper { /** * Retrieves a PaperScope object with the given scope id. - * @param id - + * @param id - scope id to retrieve */ static get(id: string): PaperScope; + } + export interface IHitTestOptions{ + + /** + * the tolerance of the hit-test in points. Can also be controlled through paperScope.settings.hitTolerance + */ + tolerance?: number; + + /** + * only hit-test again a certain item class and its sub-classes: Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, PointText, etc. + */ + class?: string; + + /** + * a match function to be called for each found hit result: Return true to return the result, false to keep searching + */ + match?: (hit: HitResult) => boolean; + + /** + * hit-test the fill of items. + */ + fill?: boolean; + + /** + * hit-test the stroke of path items, taking into account the setting of stroke color and width. + */ + stroke?: boolean; + + /** + * hit-test for segment.point of Path items. + */ + segments?: boolean; + + /** + * hit-test the curves of path items, without taking the stroke color or width into account. + */ + curves?: boolean; + + /** + * hit-test for the handles. (segment.handleIn / segment.handleOut) of path segments. + */ + handles?: boolean; + + /** + * only hit-test for the first or last segment points of open path items. + */ + ends?: boolean; + + /** + * hit-test the item.position of of items, which depends on the setting of item.pivot. + */ + position?: boolean; + + /** + * hit-test the rectangle.center of the bounding rectangle of items (item.bounds). + */ + center?: boolean; + + /** + * hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). + */ + bounds?: boolean; + + /** + * hit-test items that have Item#guide set to true. + */ + guides?: boolean; + + /** + * only hit selected items. + */ + selected?: boolean; + } /** * The Item type allows you to access and modify the items in Paper.js projects. Its functionality is inherited by different project item types such as Path, CompoundPath, Group, Layer and Raster. They each add a layer of functionality that is unique to their type, but share the underlying properties and functions that they inherit from Item. @@ -1079,7 +1315,7 @@ declare module paper { * The unique id of the item. * Read Only. */ - id: number; + readonly id: number; /** * The class name of the item as a string. @@ -1117,7 +1353,12 @@ declare module paper { * Specifies whether the item is selected. This will also return true for Group items if they are partially selected, e.g. groups containing selected or partially selected paths. * 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. */ - selected: boolean; + selected: boolean; + + /** + * Specifies whether the item and all children are selected. + */ + fullySelected: boolean; /** * Specifies whether the item defines a clip mask. This can only be set on paths, compound paths, and text frame objects, and only if the item is already contained within a clipping group. @@ -1173,7 +1414,12 @@ declare module paper { * The item's global transformation matrix in relation to the global project coordinate space. Note that the view's transformations resulting from zooming and panning are not factored in. * Read Only. */ - globalMatrix: Matrix; + readonly globalMatrix: Matrix; + + /** + * The item’s global matrix in relation to the view coordinate space. This means that the view’s transformations resulting from zooming and panning are factored in. + */ + readonly viewMatrix: Matrix; /** * Controls whether the transformations applied to the item (e.g. through transform(matrix), rotate(angle), scale(scale), etc.) are stored in its matrix property, or whether they are directly applied to its contents or children (passed on to the segments in Path items, the children of Group items, etc.). @@ -1184,19 +1430,19 @@ declare module paper { * The project that this item belongs to. * Read only. */ - project: Project; + readonly project: Project; /** * The view that this item belongs to. * Read Only. */ - view: View; + readonly view: View; /** * The layer that this item is contained within. * Read Only. */ - layer: Layer; + readonly layer: Layer; /** * The item that this item is contained within. @@ -1212,30 +1458,30 @@ declare module paper { /** * The first item contained within this item. This is a shortcut for accessing item.children[0]. */ - firstChild: Item; + readonly firstChild: Item; /** * The last item contained within this item.This is a shortcut for accessing item.children[item.children.length - 1]. */ - lastChild: Item; + readonly lastChild: Item; /** * The next item on the same level as this item. * Read Only. */ - nextSibling: Item; + readonly nextSibling: Item; /** * The previous item on the same level as this item. * Read Only. */ - previousSibling: Item; + readonly previousSibling: Item; /** * The index of this item within the list of its parent's children. * Read only. */ - index: number; + readonly index: number; /** * The color of the stroke. @@ -1291,10 +1537,29 @@ declare module paper { fillColor: Color | string; /** - * The fill rule. + * The fill-rule with which the shape gets filled. Please note that only modern browsers support fill-rules other than 'nonzero'. + * Values - 'nonzero', 'evenodd' + * Default - 'nonzero' */ fillRule: string; + /** + * The shadow color. + */ + shadowColor: Color | string; + + /** + * The shadow’s blur radius. + * Default - 0 + */ + shadowBlur: number; + + /** + * The shadow’s offset. + * Default - 0 + */ + shadowOffset: number; + /** * The color the item is highlighted with when selected. If the item does not specify its own color, the color defined by its layer is used instead. */ @@ -1308,45 +1573,53 @@ declare module paper { /** * The function to be called when the mouse button is pushed down on the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseDown: (event: MouseEvent) => void; + onMouseDown: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse position changes while the mouse is being dragged. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseDrag: (event: MouseEvent) => void; + onMouseDrag: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse button is released over the item. * The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseUp: (event: MouseEvent) => void; + onMouseUp: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse clicks on the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onClick: (event: MouseEvent) => void; + onClick: (event: MouseEvent) => void | boolean; /** - * The function to be called when the mouse double clicks on the item. The function receives a MouseEvent object which contains information about the mouse event. + * The function to be called when the mouse double clicks on the item. The function receives a MouseEvent object which contains information about the mouse event. * + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onDoubleClick: (event: MouseEvent) => void; + onDoubleClick: (event: MouseEvent) => void | boolean; /** * The function to be called repeatedly when the mouse moves on top of the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseMove: (event: MouseEvent) => void; + onMouseMove: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse moves over the item. This function will only be called again, once the mouse moved outside of the item first. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseEnter: (event: MouseEvent) => void; + onMouseEnter: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse moves out of the item. * The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseLeave: (event: MouseEvent) => void; + onMouseLeave: (event: MouseEvent) => void | boolean; /** * Sets those properties of the passed object literal on this item to the values defined in the object literal, if the item has property of the given name (or a setter defined for it). @@ -1355,23 +1628,31 @@ declare module paper { /** * Clones the item within the same project and places the copy above the item. - * @param options [optional] - object with 2 parameters - * insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true - * deep: specifies whether the item’s children should also be cloned — default: true + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true */ - clone(options?: { insert?: boolean, deep?: boolean }): Item; + clone(options?: { insert?: boolean; deep?: boolean; }): Item; /** - * When passed a project, copies the item to the project, or duplicates it within the same project. When passed an item, copies the item into the specified item. - * @param item - the item or project to copy the item to + * Copies the content of the specified item over to this item. + * @param source - the item to copy the content from */ - copyTo(item: Item): Item; + copyContent(source: Item): void; + + /** + * Copies all attributes of the specified item over to this item. This includes its style, visibility, matrix, pivot, blend-mode, opacity, selection state, data, name, etc. + * @param source - the item to copy the attributes from + * @param excludeMatrix - whether to exclude the transformation matrix when copying all attributes + */ + copyAttributes(source: Item, excludeMatrix: boolean): void; /** * Rasterizes the item into a newly created Raster object. The item itself is not removed after rasterization. * @param resolution [optional] - the resolution of the raster in pixels per inch (DPI). If not specified, the value of view.resolution is used. default: view.resolution + * @param insert [optional] - specifies whether the raster should be inserted into the scene graph. When set to true, it is inserted above the original — default: true */ - rasterize(resolution?: number): Raster; + rasterize(resolution?: number, insert?: boolean): Raster; /** * Checks whether the item's geometry contains the given point. @@ -1392,42 +1673,46 @@ declare module paper { intersects(item: Item): boolean; /** - * Perform a hit-test on the items contained within the project at the location of the specified point. + * Performs a hit-test on the item and its children (if it is a Group or Layer) at the location of the specified point, returning the first found hit. * The options object allows you to control the specifics of the hit-test and may contain a combination of the following values: * @param point - the point where the hit-test should be performed * @param options.tolerance -the tolerance of the hit-test in points. Can also be controlled through paperScope.settings.hitTolerance * @param options.class - only hit-test again a certain item class and its sub-classes: Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, PointText, etc. + * @param options.match -a match function to be called for each found hit result: Return true to return the result, false to keep searching * @param options.fill - hit-test the fill of items. * @param options.stroke - hit-test the stroke of path items, taking into account the setting of stroke color and width. * @param options.segments - hit-test for segment.point of Path items. * @param options.curves - hit-test the curves of path items, without taking the stroke color or width into account. * @param options.handles - hit-test for the handles. (segment.handleIn / segment.handleOut) of path segments. * @param options.ends - only hit-test for the first or last segment points of open path items. - * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). + * @param options.position - hit-test the item.position of of items, which depends on the setting of item.pivot. * @param options.center - hit-test the rectangle.center of the bounding rectangle of items (item.bounds). + * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). * @param options.guides - hit-test items that have Item#guide set to true. * @param options.selected - only hit selected items. */ - hitTest(point: Point, options?: { tolerance?: number; class?: string; fill?: boolean; stroke?: boolean; segments?: boolean; curves?: boolean; handles?: boolean; ends?: boolean; bounds?: boolean; center?: boolean; guides?: boolean; selected?: boolean; match?: (hit: HitResult) => boolean; }): HitResult; + hitTest(point: Point, options?: IHitTestOptions): HitResult; /** - * Perform a hit-test on the items contained within the project at the location of the specified point, returning all found hits. + * Performs a hit-test on the item and its children (if it is a Group or Layer) at the location of the specified point, returning all found hits. * The options object allows you to control the specifics of the hit-test and may contain a combination of the following values: * @param point - the point where the hit-test should be performed * @param options.tolerance -the tolerance of the hit-test in points. Can also be controlled through paperScope.settings.hitTolerance * @param options.class - only hit-test again a certain item class and its sub-classes: Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, PointText, etc. + * @param options.match -a match function to be called for each found hit result: Return true to return the result, false to keep searching * @param options.fill - hit-test the fill of items. * @param options.stroke - hit-test the stroke of path items, taking into account the setting of stroke color and width. * @param options.segments - hit-test for segment.point of Path items. * @param options.curves - hit-test the curves of path items, without taking the stroke color or width into account. * @param options.handles - hit-test for the handles. (segment.handleIn / segment.handleOut) of path segments. * @param options.ends - only hit-test for the first or last segment points of open path items. - * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). + * @param options.position - hit-test the item.position of of items, which depends on the setting of item.pivot. * @param options.center - hit-test the rectangle.center of the bounding rectangle of items (item.bounds). + * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). * @param options.guides - hit-test items that have Item#guide set to true. * @param options.selected - only hit selected items. - */ - hitTestAll(point: Point, options?: { tolerance?: number; class?: string; fill?: boolean; stroke?: boolean; segments?: boolean; curves?: boolean; handles?: boolean; ends?: boolean; bounds?: boolean; center?: boolean; guides?: boolean; selected?: boolean; match?: (hit: HitResult) => boolean; }): HitResult[]; + * */ + hitTestAll(point: Point, options?: IHitTestOptions): HitResult[]; /** * Checks whether the item matches the criteria described by the given object, by iterating over all of its properties and matching against their values through matches(name, compare). @@ -1448,6 +1733,9 @@ declare module paper { * Fetch the descendants (children or children of children) of this item that match the properties in the specified object. * Extended matching is possible by providing a compare function or regular expression. Matching points, colors only work as a comparison of the full object, not partial matching (e.g. only providing the x- coordinate to match all points with that x-value). Partial matching does work for item.data. * Matching items against a rectangular area is also possible, by setting either match.inside or match.overlapping to a rectangle describing the area in which the items either have to be fully or partly contained. + * @param match.recursive - whether to loop recursively through all children, or stop at the current level — default: true + * @param match.match - a match function to be called for each item, allowing the definition of more flexible item checks that are not bound to properties. If no other match properties are defined, this function can also be passed instead of the options object + * @param match.class - the constructor function of the item type to match against * @param match.inside - the rectangle in which the items need to be fully contained. * @param match.overlapping - the rectangle with which the items need to at least partly overlap. */ @@ -1466,7 +1754,7 @@ declare module paper { * @param options.asString - whether the JSON is returned as a Object or a String. * @param options.precision - the amount of fractional digits in numbers used in JSON data. */ - exportJSON(options?: { asString?: boolean; precision?: number }): string; + exportJSON(options?: { asString?: boolean; precision?: number; }): string; /** * Imports (deserializes) the stored JSON data into the project. @@ -1476,22 +1764,37 @@ declare module paper { /** * Exports the project with all its layers and child items as an SVG DOM, all contained in one top level SVG group node. - * @param options [optional] the export options, default: { asString: false, precision: 5, matchShapes: false } + * @param options [optional] the export options, default: { asString: false, precision: 5, matchShapes: false, bounds: 'view', matrix: paper.view.matrix, embedImages: true } * @param options.asString - whether a SVG node or a String is to be returned. * @param options.precision - the amount of fractional digits in numbers used in SVG data. * @param options.matchShapes - whether path items should tried to be converted to shape items, if their geometries can be made to match + * @param options.bounds - the bounds of the area to export, either as a string (‘view’, content’), or a Rectangle object: 'view' uses the view bounds, 'content' uses the stroke bounds of all content. + * @param options.matrix - the matrix with which to transform the exported content: If options.bounds is set to 'view', paper.view.matrix is used, for all other settings of options.bounds the identity matrix is used. + * @param options.embedImages: whether raster images should be embedded as base64 data inlined in the xlink:href attribute, or kept as a link to their external URL. */ - exportSVG(options?: { asString?: boolean; precision?: number; matchShapes?: boolean }): SVGElement; + exportSVG(options?: { asString?: boolean; precision?: number; matchShapes?: boolean; bounds?: string | Rectangle; matrix?: Matrix; embedImages?: boolean; }): SVGElement; /** * Converts the provided SVG content into Paper.js items and adds them to the active layer of this project. * Note that the project is not cleared first. You can call project.clear() to do so. * @param svg - the SVG content to import - * @param options [optional] - the import options, default: { expandShapes: false } + * @param options [optional] - the import options, default: { expandShapes: false, insert: true, applyMatrix: paperScope.settings.applyMatrix } * @param options.expandShapes - whether imported shape items should be expanded to path items. + * @param options.onLoad - the callback function to call once the SVG content is loaded from the given URL receiving two arguments: the converted item and the original svg data as a string. Only required when loading from external resources. + * @param options.onError - the callback function to call if an error occurs during loading. Only required when loading from external resources. + * @param options.insert: Boolean — whether the imported items should be added to the item that importSVG() is called on. + * @param options.applyMatrix Boolean — whether the imported items should have their transformation matrices applied to their contents or not. */ - importSVG(svg: SVGElement | string, options?: any): Item; + importSVG(svg: SVGElement | string, options?: { expandShapes?: boolean; onLoad?: (item: Item, svg: string) => void; onError?: (message: string, status: number) => void; insert?: true; applyMatrix?: Matrix; }): Item; + /** + * Converts the provided SVG content into Paper.js items and adds them to the active layer of this project. + * Note that the project is not cleared first. You can call project.clear() to do so. + * @param svg - the SVG content to import + * @param onLoad [optional] - the callback function to call once the SVG content is loaded from the given URL receiving two arguments: the converted item and the original svg data as a string. Only required when loading from external resources. + */ + importSVG(svg: SVGElement | string, onLoad?: (item: Item, svg: string) => void): Item; + /** * Adds the specified item as a child of this item at the end of the its children list. You can use this function for groups, compound paths and layers. * @param item - the item to add as a child @@ -1530,6 +1833,18 @@ declare module paper { */ insertBelow(item: Item): Item; + /** + * Inserts the specified item as a child of this item by appending it to the list of children and moving it above all other children. You can use this function for groups, compound paths and layers. + * @param item - the item to be appended as a child + */ + appendTop(item: Item): Item; + + /** + * Inserts the specified item as a child of this item by appending it to the list of children and moving it below all other children. You can use this function for groups, compound paths and layers. + * @param item - the item to be appended as a child + */ + appendBelow(item: Item): Item; + /** * Moves this item above the specified item. Returns true if the item * was moved. @@ -1555,9 +1870,22 @@ declare module paper { bringToFront(): void; /** - * If this is a group, layer or compound-path with only one child-item, the child-item is moved outside and the parent is erased. Otherwise, the item itself is returned unmodified. + * Adds it to the specified owner, which can be either a Item or a Project. + * @param owner - the item or project to add the item to */ - reduce(): Item; + addTo(owner: Project | Layer | Group | CompoundPath): Item; + + /** + * Clones the item and adds it to the specified owner, which can be either a Item or a Project. + * @param owner - the item or project to copy the item to + */ + copyTo(owner: Project | Layer | Group | CompoundPath): Item; + + /** + * If this is a group, layer or compound-path with only one child-item, the child-item is moved outside and the parent is erased. Otherwise, the item itself is returned unmodified. + * @param options [optional] + */ + reduce(options?: any): Item; /** * Removes the item and all its children from the project. The item is not destroyed and can be inserted again after removal. @@ -1577,10 +1905,10 @@ declare module paper { /** * Removes the children from the specified from index to the to index from the parent's children array. - * @param from - the beginning index, inclusive - * @param to [optional] - the ending index, exclusive, default: children.length + * @param start - the beginning index, inclusive + * @param end [optional] - the ending index, exclusive, default: children.length */ - removeChildren(from: number, to?: number): Item[]; + removeChildren(start: number, end?: number): Item[]; /** * Reverses the order of the item's children @@ -1760,44 +2088,54 @@ declare module paper { */ fitBounds(rectangle: Rectangle, fill?: boolean): void; - //I cannot use function: Function as it is a reserved keyword - /** - * Attach an event handler to the tool. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type - * @param function - The function to be called when the event occurs + * Attach an event handler to the item. + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be called when the event occurs */ - on(type: string, callback: (event: ToolEvent) => void): Tool; - + on(type: string, callback: (event: MouseEvent) => void | boolean): Item; /** - * Attach one or more event handlers to the tool. - * @param param - an object literal containing one or more of the following properties: mousedown, mouseup, mousedrag, mousemove, keydown, keyup + * Attach an event handler to the item. + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be called when the event occurs */ - on(param: any): Tool; + on(type: string, callback: (event: IFrameEvent) => void | boolean): Item; /** - * Detach an event handler from the tool. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * Attach one or more event handlers to the item. + * @param object - an object containing one or more of the following properties: frame, mousedown, mouseup, mousedrag, click, doubleclick, mousemove, mouseenter, mouseleave + */ + on(object: { frame?: (event: IFrameEvent) => void; mousedown?: (event: MouseEvent) => void | boolean; mouseup?: (event: MouseEvent) => void | boolean; mousedrag?: (event: MouseEvent) => void | boolean; click?: (event: MouseEvent) => void | boolean; doubleclick?: (event: MouseEvent) => void | boolean; mousemove?: (event: MouseEvent) => void | boolean; mouseenter?: (event: MouseEvent) => void | boolean; mouseleave?: (event: MouseEvent) => void | boolean; }): Item; + + /** + * Detach an event handler from the item. + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ * @param function - The function to be detached */ - off(type: string, callback: (event: ToolEvent) => void): Tool; + off(type: string, callback: (event: MouseEvent) => void | boolean): Item; + /** + * Detach an event handler from the item. + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param function - The function to be detached + */ + off(type: string, callback: (event: IFrameEvent) => void | boolean): Item; /** * Detach one or more event handlers from the tool. - * @param param - an object literal containing one or more of the following properties: mousedown, mouseup, mousedrag, mousemove, keydown, keyup + * @param object - an object containing one or more of the following properties: frame, mousedown, mouseup, mousedrag, click, doubleclick, mousemove, mouseenter, mouseleave */ - off(param: any): Tool; + off(object: { frame?: (event: IFrameEvent) => void; mousedown?: (event: MouseEvent) => void | boolean; mouseup?: (event: MouseEvent) => void | boolean; mousedrag?: (event: MouseEvent) => void | boolean; click?: (event: MouseEvent) => void | boolean; doubleclick?: (event: MouseEvent) => void | boolean; mousemove?: (event: MouseEvent) => void | boolean; mouseenter?: (event: MouseEvent) => void | boolean; mouseleave?: (event: MouseEvent) => void | boolean; }): Item; /** * Emit an event on the tool. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ * @param event - an object literal containing properties describing the event. */ emit(type: string, event: any): boolean; /** * Check if the tool has one or more event handlers of the specified type. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ */ responds(type: string): boolean;//I cannot use function: Function as it is a reserved keyword @@ -1806,49 +2144,49 @@ declare module paper { * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type * @param function - The function to be called when the event occurs */ - on(type: string, callback: () => void): Item; + on(type: string, callback: (event: Event | MouseEvent) => void | boolean): Item; /** * Attaches one or more event handlers to the item. - * @param param - an object literal containing one or more of the following properties: mousedown, mouseup, mousedrag, mousemove, keydown, keyup + * @param param - an object containing one or more of the following properties: frame, mousedown, mouseup, mousedrag, click, doubleclick, mousemove, mouseenter, mouseleave */ on(param: any): Item; /** * Detach an event handler from the item. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ * @param function - The function to be detached */ - off(type: string, callback: (event: ToolEvent) => void): Item; + off(type: string, callback: (event: Event | MouseEvent) => void | boolean): Item; /** * Detach one or more event handlers to the item. - * @param param - an object literal containing one or more of the following properties: mousedown, mouseup, mousedrag, mousemove, keydown, keyup + * @param param - an object containing one or more of the following properties: frame, mousedown, mouseup, mousedrag, click, doubleclick, mousemove, mouseenter, mouseleave */ off(param: any): Item; /** * Emit an event on the item. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ * @param event - an object literal containing properties describing the event. */ emit(type: string, event: any): boolean; /** * Check if the item has one or more event handlers of the specified type.. - * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type + * @param type - the type of event: ‘frame’, mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ */ responds(type: string): boolean; /** * Removes the item when the events specified in the passed object literal occur. - * @param object - The object literal can contain the following values - * @param object.move - Remove the item when the next tool.onMouseMove event is fired - * @param object.drag - Remove the item when the next tool.onMouseDrag event is fired - * @param object.down - Remove the item when the next tool.onMouseDown event is fired - * @param object.up - Remove the item when the next tool.onMouseUp event is fired + * @param options - The object literal can contain the following values + * @param options.move - Remove the item when the next tool.onMouseMove event is fired + * @param options.drag - Remove the item when the next tool.onMouseDrag event is fired + * @param options.down - Remove the item when the next tool.onMouseDown event is fired + * @param options.up - Remove the item when the next tool.onMouseUp event is fired */ - removeOn(object: { move?: boolean; drag?: boolean; down?: boolean; up?: boolean; }): void; + removeOn(options: { move?: boolean; drag?: boolean; down?: boolean; up?: boolean; }): void; /** * Removes the item when the next tool.onMouseMove event is fired. @@ -1888,6 +2226,14 @@ declare module paper { */ constructor(object?: any); + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Group; + /** * Specifies whether the group item is to be clipped. * When setting to true, the first child in the group is automatically defined as the clipping mask. @@ -1988,6 +2334,20 @@ declare module paper { */ radius: number | Size; + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Shape; + + /** + * Creates a new path item with same geometry as this shape item, and inherits all settings from it, similar to item.clone(). + * @param insert - specifies whether the new path should be inserted into the scene graph. When set to true, it is inserted above the shape item — optional, default: true + */ + toPath(insert?: boolean): Shape; + } /** * The Raster item represents an image in a Paper.js project. @@ -2017,11 +2377,16 @@ declare module paper { */ height: number; + /** + * The loading state of the raster image. + */ + readonly loaded: boolean; + /** * The resolution of the raster at its current size, in PPI (pixels per inch). * Read Only. */ - resolution: Size; + readonly resolution: Size; /** * The HTMLImageElement of the raster, if one is associated. @@ -2043,6 +2408,29 @@ declare module paper { */ source: HTMLImageElement | HTMLCanvasElement | string; + /** + * The crossOrigin value to be used when loading the image resource, in order to support CORS. Note that this needs to be set before setting the source property in order to always work (e.g. when the image is cached in the browser). + */ + crossOrigin: string; + + /** + * The event handler function to be called when the underlying image has finished loading and is ready to be used. This is also triggered when the image is already loaded, or when a canvas is used instead of an image. + */ + onLoad: any; + + /** + * The event handler function to be called when there is an error loading the underlying image. + */ + onError: any; + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Raster; + /** * Extracts a part of the Raster's content as a sub image, and returns it as a Canvas object. * @param rect - the boundaries of the sub image in pixel coordinates @@ -2114,7 +2502,6 @@ declare module paper { getImageData(rect: Rectangle): ImageData; /** - * * * @param data * @param point @@ -2138,6 +2525,14 @@ declare module paper { */ symbol: Symbol; + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): PlacedSymbol; + } /** * A HitResult object contains information about the results of a hit test. It is returned by item.hitTest(point) and project.hitTest(point). @@ -2187,22 +2582,175 @@ declare module paper { */ export class PathItem extends Item { + /** + * Creates a path item from the given SVG path-data, determining if the data describes a plain path or a compound-path with multiple sub-paths. + * @param pathData - the SVG path-data to parse + */ + static create(pathData: string): Path | CompoundPath; + + /** + * Creates a path item from the given segments array, determining if the array describes a plain path or a compound-path with multiple sub-paths. + * @param segments - the segments array to parse + */ + static create(segments: number[] | any[]): Path | CompoundPath; + + /** + * Creates a path item from the given object, determining if the contained information describes a plain path or a compound-path with multiple sub-paths. + * @param object - an object containing the properties describing the item to be created + */ + static create(object: any): Path | CompoundPath; + + /** + * Returns a point that is guaranteed to be inside the path. + */ + readonly interiorPoint: Point; + + /** + * Specifies whether the path as a whole is oriented clock-wise, by looking at the path’s area. Note that self-intersecting paths and sub-paths of different orientation can result in areas that cancel each other out. + */ + clockwise: boolean; + /** * The path's geometry, formatted as SVG style path data. */ pathData: string; /** - * Returns all intersections between two PathItem items as an array of CurveLocation objects. CompoundPath items are also supported. - * @param path - the other item to find the intersections with - * @param sorted [optional] - specifies whether the returned CurveLocation objects should be sorted by path and offset, default: false + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true */ - getIntersections(path: PathItem, sorted?: boolean): CurveLocation[]; + clone(options?: { insert?: boolean; deep?: boolean; }): PathItem; /** - * Smooth bezier curves without changing the amount of segments or their points, by only smoothing and adjusting their handle points, for both open ended and closed paths. + * Merges the geometry of the specified path from this path's geometry and returns the result as a new path item. + * @param path - the path to unite with + * @param options [optional] - the boolean operation options. default { insert: true } + * @param options.insert - whether the resulting item should be inserted back into the scene graph, above both paths involved in the operation. */ - smooth(): void; + unite(path: PathItem, options?: { insert?: boolean; }): PathItem; + + /** + * Intersects the geometry of the specified path with this path's geometry and returns the result as a new path item. + * @param path - the path to intersect with + * @param options [optional] - the boolean operation options. default { insert: true, trace: true } + * @param options.insert - whether the resulting item should be inserted back into the scene graph, above both paths involved in the operation. + * @param options.trace - whether the tracing method is used, treating both paths as areas when determining which parts of the paths are to be kept in the result, or whether the first path is only to be split at intersections, keeping the parts of the curves that intersect with the area of the second path. + */ + intersect(path: PathItem, options?: { insert?: boolean; trace?: boolean; }): PathItem; + + /** + * Subtracts the geometry of the specified path from this path's geometry and returns the result as a new path item. + * @param path - the path to subtract + * @param options [optional] - the boolean operation options. default { insert: true, trace: true } + * @param options.insert - whether the resulting item should be inserted back into the scene graph, above both paths involved in the operation. + * @param options.trace - whether the tracing method is used, treating both paths as areas when determining which parts of the paths are to be kept in the result, or whether the first path is only to be split at intersections, keeping the parts of the curves that intersect with the area of the second path. + */ + subtract(path: PathItem, options?: { insert?: boolean; trace?: boolean; }): PathItem; + + /** + * Excludes the intersection of the geometry of the specified path with this path's geometry and returns the result as a new group item. + * @param path - the path to exclude the intersection of + * @param options [optional] - the boolean operation options. default { insert: true } + * @param options.insert - whether the resulting item should be inserted back into the scene graph, above both paths involved in the operation. + */ + exclude(path: PathItem, options?: { insert?: boolean; }): PathItem; + + /** + * Splits the geometry of this path along the geometry of the specified path returns the result as a new group item. + * @param path - the path to divide by + * @param options [optional] - the boolean operation options. default { insert: true, trace: true } + * @param options.insert - whether the resulting item should be inserted back into the scene graph, above both paths involved in the operation. + * @param options.trace - whether the tracing method is used, treating both paths as areas when determining which parts of the paths are to be kept in the result, or whether the first path is only to be split at intersections, keeping the parts of the curves that intersect with the area of the second path. + */ + divide(path: PathItem, options?: { insert?: boolean; trace?: boolean; }): PathItem; + + /** + * Fixes the orientation of the sub-paths of a compound-path, assuming that non of its sub-paths intersect, by reorienting them so that they are of different winding direction than their containing paths, except for disjoint sub-paths, i.e. islands, which are oriented so that they have the same winding direction as the the biggest path. + * @param nonZero [optional] - controls if the non-zero fill-rule is to be applied, by counting the winding of each nested path and discarding sub-paths that do not contribute to the final result. default: false + * @param clockwise [optional] - if provided, the orientation of the root paths will be set to the orientation specified by clockwise, otherwise the orientation of the largest root child is used. + */ + reorient(nonZero?: boolean, clockwise?: boolean): PathItem; + + /** + * Returns all intersections between two PathItem items as an array of CurveLocation objects. CompoundPath items are also supported. + * @param path - the other item to find the intersections with + * @param include [optional] - a callback function that can be used to filter out undesired locations right while they are collected. When defined, it shall return true to include a location, false otherwise. — optional + */ + getIntersections(path: PathItem, include?: (location: CurveLocation) => boolean): CurveLocation[]; + + /** + * Returns all crossings between two PathItem items as an array of CurveLocation objects. CompoundPath items are also supported. Crossings are intersections where the paths actually are crossing each other, as opposed to simply touching. + * @param path - the other item to find the crossings with + */ + getCrossings(path: PathItem): CurveLocation[]; + + /** + * Returns the nearest location on the path item to the specified point. + * @param point - the point for which we search the nearest location + */ + getNearestLocation(point: Point): CurveLocation; + + /** + * Returns the nearest point on the path item to the specified point. + * @param point - the point for which we search the nearest point + */ + getNearestPoint(point: Point): Point; + + /** + * Reverses the orientation of the path item. When called on CompoundPath items, each of the nested paths is reversed. On Path items, the sequence of path.segments is reversed. + */ + reverse(): void; + + /** + * Flattens the curves in path items to a sequence of straight lines, by subdividing them enough times until the specified maximum error is met. + * @param flatness [optional] - the maximum error between the flattened lines and the original curves. default: 0.25 + */ + flatten(flatness?: number): void; + + /** + * Smooths the path item without changing the amount of segments in the path or moving the segments’ locations, by smoothing and adjusting the angle and length of the segments’ handles based on the position and distance of neighboring segments. + * Smoothing works both for open paths and closed paths, and can be applied to the full path, as well as a sub-range of it. If a range is defined using the options.from and options.to properties, only the curve handles inside that range are touched. If one or both limits of the range are specified in negative indices, the indices are wrapped around the end of the curve. That way, a smoothing range in a close path can even wrap around the connection between the last and the first segment. + * Four different smoothing methods are available: + * 'continuous' smooths the path item by adjusting its curve handles so that the first and second derivatives of all involved curves are continuous across their boundaries. + * This method tends to result in the smoothest results, but does not allow for further parametrization of the handles. + * 'asymmetric' is based on the same principle as 'continuous' but uses different factors so that the result is asymmetric. This used to the only method available until v0.10.0, and is currently still the default when no method is specified, for reasons of backward compatibility. It will eventually be removed. + * 'catmull-rom' uses the Catmull-Rom spline to smooth the segment. + * The optionally passed factor controls the knot parametrization of the algorithm: + * 0.0: the standard, uniform Catmull-Rom spline + * 0.5: the centripetal Catmull-Rom spline, guaranteeing no self-intersections + * 1.0: the chordal Catmull-Rom spline + * 'geometric' use a simple heuristic and empiric geometric method to smooth the segment’s handles. The handles were weighted, meaning that big differences in distances between the segments will lead to probably undesired results. + * The optionally passed factor defines the tension parameter (0…1), controlling the amount of smoothing as a factor by which to scale each handle. + * @param options [optional] - default { type:'asymmetric', factor: 0.5 for 'catmull-rom', 0.4 for 'geometric' } + * @param options.type - the type of smoothing method: ‘continuous’, ‘asymmetric’, ‘catmull-rom’, ‘geometric’ — default: ‘asymmetric’ + * @param options.factor - the factor parameterizing the smoothing method — default: 0.5 for 'catmull-rom', 0.4 for 'geometric' + * @param options.from - the segment or curve at which to start smoothing, if not the full path shall be smoothed (inclusive). This can either be a segment index, or a segment or curve object that is part of the path. If the passed number is negative, the index is wrapped around the end of the path. + * @param options.to - the segment or curve to which the handles of the path shall be processed (inclusive). This can either be a segment index, or a segment or curve object that is part of the path. If the passed number is negative, the index is wrapped around the end of the path. + */ + smooth(options?: { type?: string; factor?: number; from?: number | Segment | Curve; to?: number | Segment | Curve; }): void; + + /** + * Fits a sequence of as few curves as possible through the path’s anchor points, ignoring the path items’s curve-handles, with an allowed maximum error. When called on CompoundPath items, each of the nested paths is simplified. On Path items, the path.segments array is processed and replaced by the resulting sequence of fitted curves. + * This method can be used to process and simplify the point data received from a mouse or touch device. + * @param tolerance [optional] - the allowed maximum error when fitting the curves through the segment points. default: 2.5 + */ + simplify(tolerance?: number): boolean; + + /** + * Interpolates between the two specified path items and uses the result as the geometry for this path item. The number of children and segments in the two paths involved in the operation should be the same. + * @param from - the path item defining the geometry when factor is 0 + * @param to - the path item defining the geometry when factor is 1 + * @param factor - the interpolation coefficient, typically between 0 and 1, but extrapolation is possible too + */ + interpolate(from: PathItem, to: PathItem, factor: number): void; + + /** + * Compares the geometry of two paths to see if they describe the same shape, detecting cases where paths start in different segments or even use different amounts of curves to describe the same shape, as long as their orientation is the same, and their segments and handles really result in the same visual appearance of curves. + * @param path - the path to compare this path’s geometry with + */ + compare(path: PathItem): boolean; /** * On a normal empty Path, the point is simply added as the path's first segment. If called on a CompoundPath, a new Path is created as a child and the point is added as its first segment. @@ -2215,6 +2763,28 @@ declare module paper { * @param point - the end point of the line */ lineTo(point: Point): void; + + /** + * Draws an arc from the position of the last segment point in the path that goes through the specified through point, to the specified to point by adding one or more segments to the path. + * @param through - the point where the arc should pass through + * @param to - the point where the arc should end + */ + arcTo(through: Point, to: Point): void; + + /** + * 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 to - the point where the arc should end + * @param clockwise [optional] - specifies whether the arc should be drawn in clockwise direction. default: true + */ + arcTo(to: Point, clockwise?: boolean): void; + + /** + * Draws a curve from the position of the last segment point in the path that goes through the specified through point, to the specified to point by adding one segment to the path. + * @param through - the point through which the curve should go + * @param to - the point where the curve should end + * @param time [optional] - the curve-time parameter at which the through point is to be located. default: 0.5 + */ + curveTo(through: Point, to: Point, time?: number): void; /** * Adds a cubic bezier curve to the path, defined by two handles and a to point. @@ -2231,33 +2801,11 @@ declare module paper { */ quadraticCurveTo(handle: Point, to: Point): void; - /** - * Draws a curve from the position of the last segment point in the path that goes through the specified through point, to the specified to point by adding one segment to the path. - * @param through - the point through which the curve should go - * @param to - the point where the curve should end - * @param parameter [optional] - default: 0.5 - */ - curveTo(through: Point, to: Point, parameter?: number): void; - - /** - * Draws an arc from the position of the last segment point in the path that goes through the specified through point, to the specified to point by adding one or more segments to the path. - * @param through - the point where the arc should pass through - * @param to - the point where the arc should end - */ - arcTo(through: Point, to: Point): void; - - /** - * 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 to - the point where the arc should end - * @param closewise [optional] - specifies whether the arc should be drawn in clockwise direction. optional, default: true - */ - arcTo(to: Point, clockwise?: boolean): void; - /** * Closes the path. When closed, Paper.js connects the first and last segment of the path with an additional curve. - * @param join - controls whether the method should attempt to merge the first segment with the last if they lie in the same location. + * @param tolerance [optional] - the maximum distance allowed when merging the first and last locations in the newly closed path. default: 0 */ - closePath(join: boolean): void; + closePath(tolerance?: number): void; /** * If called on a CompoundPath, a new Path is created as a child and a point is added as its first segment relative to the position of the last segment of the current path. @@ -2267,76 +2815,47 @@ declare module paper { /** * Adds a segment relative to the last segment point of the path. - * @param to - the vector which is added to the position of the last segment of the path, to get to the position of the new segment. + * @param point - the vector which is added to the position of the last segment of the path, to get to the position of the new segment. */ - lineBy(to: Point): void; + lineBy(point: Point): void; /** - * - * @param through - - * @param to - - * @param parameter [optional] - default 0.5 - */ - curveBy(through: Point, to: Point, parameter?: number): void; - - /** - * - * @param handle1 - - * @param handle2 - - * @param to - - */ - cubicCurveBy(handle1: Point, handle2: Point, to: Point): void; - - /** - * - * @param handle - - * @param to - - */ - quadraticCurveBy(handle: Point, to: Point): void; - - /** - * - * @param through - - * @param to - + * Adds an arc from the position of the last segment in the path, passing through the specified through vector, to the specified to vector, all specified relatively to it by these given vectors, by adding one or more segments to the path. + * @param through - the vector where the arc should pass through + * @param to - the vector where the arc should end */ arcBy(through: Point, to: Point): void; /** - * - * @param to - - * @param clockwise [optional] - default: true + * Adds an arc from the position of the last segment in the path to the to vector specified relatively to it, by adding one or more segments to the path. + * @param to - the vector where the arc should end + * @param clockwise [optional] - specifies whether the arc should be drawn in clockwise direction. default: true */ arcBy(to: Point, clockwise?: boolean): void; /** - * Merges the geometry of the specified path from this path's geometry and returns the result as a new path item. - * @param path - the path to unite with + * Adds a curve from the last segment in the path through the specified through vector, to the specified to vector, all specified relatively to it by these given vectors, by adding one segment to the path. + * @param through - the vector through which the curve should pass + * @param to - the destination vector of the newly added curve + * @param time [optional] - the curve-time parameter at which the through point is to be located. default: 0.5 */ - unite(path: PathItem): PathItem; + curveBy(through: Point, to: Point, time?: number): void; /** - * Intersects the geometry of the specified path with this path's geometry and returns the result as a new path item. - * @param path - the path to intersect with + * Adds a cubic bezier curve to the path, from the last segment to the to the specified to vector, with the curve itself defined by two specified handles. + * @param handle1 - the location of the first handle of the newly added curve + * @param handle2 - the location of the second handle of the newly added curve + * @param to - the destination point of the newly added curve */ - intersect(path: PathItem): PathItem; + cubicCurveBy(handle1: Point, handle2: Point, to: Point): void; /** - * Subtracts the geometry of the specified path from this path's geometry and returns the result as a new path item. - * @param - the path to subtract + * Adds a quadratic bezier curve to the path, from the last segment to the specified destination point, with the curve itself defined by the specified handle. + * Note that Paper.js only stores cubic curves, so the handle is actually converted. + * @param handle - the handle of the newly added quadratic curve out of which the values for segment.handleOut of the resulting cubic curve’s first segment and segment.handleIn of its second segment are calculated + * @param to - the destination point of the newly added curve */ - subtract(path: PathItem): PathItem; - - /** - * Excludes the intersection of the geometry of the specified path with this path's geometry and returns the result as a new group item. - * @param - the path to exclude the intersection of - */ - exclude(path: PathItem): PathItem; - - /** - * Splits the geometry of this path along the geometry of the specified path returns the result as a new group item. - * @param - the path to divide by - */ - divide(path: PathItem): PathItem; + quadraticCurveBy(handle: Point, to: Point): void; } /** @@ -2348,7 +2867,7 @@ declare module paper { * Creates a new path item and places it at the top of the active layer. * @param segments [optional] - An array of segments (or points to be converted to segments) that will be added to the path */ - constructor(segments?: Segment[] | Point[]); + constructor(segments?: Segment[] | Point[] | number[][]); /** * Creates a new path item from an object description and places it at the top of the active layer. @@ -2362,6 +2881,14 @@ declare module paper { */ constructor(pathData?: string); + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Path; + /** * The segments contained within the path. * Array of Segment objects @@ -2372,31 +2899,32 @@ declare module paper { * The first Segment contained within the path. * Read only. */ - firstSegment: Segment; + readonly firstSegment: Segment; /** * The last Segment contained within the path * Read only. */ - lastSegment: Segment; + readonly lastSegment: Segment; /** * The curves contained within the path. * Array of Curve objects + * Read only. */ - curves: Curve[]; + readonly curves: Curve[]; /** * The first Curve contained within the path. * Read only. */ - firstCurve: Curve; + readonly firstCurve: Curve; /** * The last Curve contained within the path. * Read only. */ - lastCurve: Curve; + readonly lastCurve: Curve; /** * Specifies whether the path is closed. If it is closed, Paper.js connects the first and last segments. @@ -2407,70 +2935,54 @@ declare module paper { * The approximate length of the path in points. * Read only. */ - length: number; + readonly length: number; /** * The area of the path in square points. Self-intersecting paths can contain sub-areas that cancel each other out. * Read only. */ - area: number; + readonly area: number; /** - * Specifies whether the path and all its segments are selected. Cannot be true on an empty path. - */ - fullySelected: boolean; - - /** - * Specifies whether the path is oriented clock-wise. - */ - clockwise: boolean; - - /** - * Returns a point that is guaranteed to be inside the path. - * Read only. - */ - interiorPoint: Point; - - /** - * Adds one or more segments to the end of the segments array of this path. + * Adds one segment to the end of the segments array of this path. * @param segment - the segment or point to be added. * Returns the added segment. This is not necessarily the same object, e.g. if the segment to be added already belongs to another path. */ - add(segment: Segment | Point): Segment; + add(segment: Segment | Point | number[]): Segment; /** - * Inserts one or more segments at a given index in the list of this path's segments. + * Inserts one segment at a given index in the list of this path's segments. * @param index - the index at which to insert the segment. * @param segment - the segment or point to be inserted. * Returns the added segment. This is not necessarily the same object, e.g. if the segment to be added already belongs to another path. */ - insert(index: number, segment: Segment | Point): Segment; + insert(index: number, segment: Segment | Point | number[]): Segment; /** * Adds an array of segments (or types that can be converted to segments) to the end of the segments array. * @param segments - Array of Segment objects - * Returns an array of the added segments. These segments are not necessarily the same objects, e.g. if the segment to be added already belongs to another path. + * @returns an array of the added segments. These segments are not necessarily the same objects, e.g. if the segment to be added already belongs to another path. */ - addSegments(segments: Segment[]): Segment[]; + addSegments(segments: Segment[] | Point[] | number[][]): Segment[]; /** * Inserts an array of segments at a given index in the path's segments array. * @param index - the index at which to insert the segments. * @param segments - the segments to be inserted. - * Returns an array of the added segments. These segments are not necessarily the same objects, e.g. if the segment to be added already belongs to another path. + * @returns an array of the added segments. These segments are not necessarily the same objects, e.g. if the segment to be added already belongs to another path. */ - insertSegments(index: number, segments: Segment[]): Segment[]; + insertSegments(index: number, segments: Segment[] | Point[] | number[][]): Segment[]; /** * Removes the segment at the specified index of the path's segments array. * @param index - the index of the segment to be removed - * Returns the removed segment + * @returns the removed segment */ removeSegment(index: number): Segment; /** * Removes all segments from the path's segments array. - * Returns an array containing the removed segments + * @returns an array containing the removed segments */ removeSegments(): Segment[]; @@ -2478,55 +2990,76 @@ declare module paper { * Removes the segments from the specified from index to the to index from the path's segments array. * @param from - the beginning index, inclusive * @param to [optional = segments.length] - the ending index - * Returns an array containing the removed segments + * @returns an array containing the removed segments */ removeSegments(from: number, to?: number): Segment[]; /** - * Converts the curves in a path to straight lines with an even distribution of points. The distance between the produced segments is as close as possible to the value specified by the maxDistance parameter. - * @param maxDistance - the maximum distance between the points + * Checks if any of the curves in the path have curve handles set. */ - flatten(maxDistance: number): void; + hasHandles(): boolean; /** - * Smooths a path by simplifying it. The path.segments array is analyzed and replaced by a more optimal set of segments, reducing memory usage and speeding up drawing. - * @param tolerance [optional = 2.5] - + * Clears the path’s handles by setting their coordinates to zero, turning the path into a polygon (or a polyline if it isn’t closed). */ - simplify(tolerance?: number): void; + clearHandles(): void; + + /** + * Divides the path on the curve at the given location into two curves, by inserting a new segment at the given location. + * @param location - the curve location at which to divide the existing curve by inserting a new segment + * @returns the newly inserted segment if the location is valid, {code null} otherwise + */ + divideAt(location: CurveLocation): Path; + + /** + * Divides the path on the curve at the given offset into two curves, by inserting a new segment at the given location. + * @param offset - the offset at which to divide the existing curve by inserting a new segment + * @returns the newly inserted segment if the location is valid, {code null} otherwise + */ + divideAt(offset: number): Path; /** * Splits the path at the given offset. After splitting, the path will be open. If the path was open already, splitting will result in two paths. * @param offset - the offset at which to split the path as a number between 0 and path.length - * Returns the newly created path after splitting, if any + * @returns the newly created path after splitting, if any */ split(offset: number): Path; /** * Splits the path at the given curve location. After splitting, the path will be open. If the path was open already, splitting will result in two paths. * @param location - the curve location at which to split the path - * Returns the newly created path after splitting, if any + * @returns the newly created path after splitting, if any */ split(location: CurveLocation): Path; /** * Splits the path at the given curve index and parameter. After splitting, the path will be open. If the path was open already, splitting will result in two paths. * @param index - the index of the curve in the path.curves array at which to split - * @param parameter - the parameter at which the curve will be split - * Returns the newly created path after splitting, if any + * @param offset - the offset at which to split the path as a number between 0 and path.length + * @returns the newly created path after splitting, if any */ - split(index: number, parameter: number): Path; - - /** - * Reverses the orientation of the path, by reversing all its segments. - */ - reverse(): void; + split(index: number, offset: number): Path; /** * Joins the path with the specified path, which will be removed in the process. * @param path - the path to join this path with - * Returns the joined path + * @param tolerance [optional] - the tolerance with which to decide if two segments are to be considered the same location when joining. default: 0 + * @returns the joined path */ - join(path: Path): Path; + join(path: Path, tolerance?: number): Path; + + /** + * Reduces the path by removing curves that have a length of 0, and unnecessary segments between two collinear flat curves. + * @param options [optional] - options for reducing the path. default { simplify: false } + * @param options.simplify - whether to be slightly tolerant of length when reducing the path. It not set the tolerance will be 1e-7 instead of 0. + */ + reducePath(options?: { simplify?: boolean; }): void; + + /** + * Attempts to create a new shape item with same geometry as this path item, and inherits all settings from it, similar to item.clone(). + * @param insert [optional] - specifies whether the new shape should be inserted into the scene graph. When set to true, it is inserted above the path item. default: true + */ + toShape(insert?: boolean): Shape; /** * Returns the curve location of the specified point if it lies on the path, null otherwise. @@ -2542,46 +3075,53 @@ declare module paper { /** * Returns the curve location of the specified offset on the path. - * @param offset - the offset on the path, where 0 is at the beginning of the path and path.length at the end. - * @param isParameter [optional=false] - + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - */ - getLocationAt(offset: number, isParameter?: boolean): CurveLocation; + getLocationAt(offset: number, isTime?: boolean): CurveLocation; /** * Calculates the point on the path at the given offset. Returns the point at the given offset - * @param offset - the offset on the path, where 0 is at the beginning of the path and path.length at the end. - * @param isParameter [optional=false] - + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - */ - getPointAt(offset: number, isPatameter?: boolean): Point; + getPointAt(offset: number, isTime?: boolean): Point; /** * Calculates the tangent vector of the path at the given offset. Returns the tangent vector at the given offset - * @param offset - the offset on the path, where 0 is at the beginning of the path and path.length at the end. - * @param isParameter [optional=false] - + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - */ - getTangentAt(offset: number, isPatameter?: boolean): Point; + getTangentAt(offset: number, isTime?: boolean): Point; /** * Calculates the normal vector of the path at the given offset. Returns the normal vector at the given offset - * @param offset - the offset on the path, where 0 is at the beginning of the path and path.length at the end. - * @param isParameter [optional=false] - + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - */ - getNormalAt(offset: number, isParameter?: boolean): Point; + getNormalAt(offset: number, isTime?: boolean): Point; + + /** + * Calculates the weighted tangent vector of the path at the given offset. + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - + */ + getWeightedTangentAt(offset: number, isTime?: boolean): Point; + + /** + * Calculates the weighted normal vector of the path at the given offset. + * @param offset - the offset or time on the path, where 0 is at the beginning of the path and path.length at the end. + * @param isTime [optional=false] - + */ + getWeightedNormalAt(offset: number, isTime?: boolean): Point; /** * Calculates the curvature of the path at the given offset. Curvatures indicate how sharply a path changes direction. A straight line has zero curvature, where as a circle has a constant curvature. The path's radius at the given offset is the reciprocal value of its curvature. * @param offset - the offset on the path, where 0 is at the beginning of the path and path.length at the end. - * @param isParameter [optional=false] - - * @param point - the point for which we search the nearest location + * @param isTime [optional=false] - + * @param point [optional] - the point for which we search the nearest location */ - getCurvatureAt(offset: number, isParameter?: boolean, point?: Point): number; - - /** - * Returns the nearest point on the path to the specified point. - * @param point - the point for which we search the nearest point - */ - getNearestPoint(point: Point): Point; - + getCurvatureAt(offset: number, isTime?: boolean, point?: Point): number; } module Path { @@ -2598,6 +3138,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Line; } export class Circle extends Path { @@ -2613,6 +3161,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Circle; } export class Rectangle extends Path { @@ -2621,7 +3177,7 @@ declare module paper { * @param rectangle - the rectangle object describing the geometry of the rectangular path to be created. * @param radius [optional] - the size of the rounded corners default: null */ - constructor(rectangle: Rectangle, radius?: number); + constructor(rectangle: paper.Rectangle, radius?: number); /** * Creates a rectangular path item from a point and a size object. @@ -2642,6 +3198,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Rectangle; } export class Ellipse extends Path { @@ -2649,13 +3213,22 @@ declare module paper { * Creates an elliptical path item. * @param rectangle - the rectangle circumscribing the ellipse */ - constructor(rectangle: Rectangle); + constructor(rectangle: paper.Rectangle); /** * Creates an elliptical path item from the properties described by an object literal. * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Ellipse; } export class Arc extends Path { @@ -2672,6 +3245,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Arc; } export class RegularPolygon extends Path { @@ -2688,6 +3269,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): RegularPolygon; } export class Star extends Path { @@ -2705,6 +3294,14 @@ declare module paper { * @param object - an object literal containing properties describing the path's attributes */ constructor(object: any); + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): Star; } } @@ -2724,53 +3321,61 @@ declare module paper { * @param pathData - the SVG path-data that describes the geometry of this path. */ constructor(pathData: string); - + /** - * Specifies whether the compound path is oriented clock-wise. + * Specifies whether the path is closed. If it is closed, Paper.js connects the first and last segments. */ - clockwise: boolean; + closed: boolean; /** * The first Segment contained within the path. * Read Only */ - firstSegment: Segment; + readonly firstSegment: Segment; /** * The last Segment contained within the path. * Read Only */ - lastSegment: Segment; + readonly lastSegment: Segment; /** * All the curves contained within the compound-path, from all its child Path items. * Read Only */ - curves: Curve[]; + readonly curves: Curve[]; /** * The first Curve contained within the path. * Read Only */ - firstCurve: Curve; + readonly firstCurve: Curve; /** * The last Curve contained within the path. * Read only. */ - lastCurve: Curve; + readonly lastCurve: Curve; /** * The area of the path in square points. Self-intersecting paths can contain sub-areas that cancel each other out. * Read Only. */ - area: number; + readonly area: number; /** - * Reverses the orientation of all nested paths. + * The approximate length of the path in points. + * Read only. */ - reverse(): void; - + readonly length: number; + + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): CompoundPath; } /** * The Segment object represents the points of a path through which its Curve objects pass. The segments of a path can be accessed through its path.segments array. @@ -2807,11 +3412,6 @@ declare module paper { */ handleOut: Point; - /** - * Specifies whether the segment has no handles defined, meaning it connects two straight lines. - */ - linear: boolean; - /** * Specifies whether the point of the segment is selected. */ @@ -2821,48 +3421,83 @@ declare module paper { * The index of the segment in the path.segments array that the segment belongs to. * Read Only */ - index: number; + readonly index: number; /** * The path that the segment belongs to. * Read Only */ - path: Path; + readonly path: Path; /** * The curve that the segment belongs to. For the last segment of an open path, the previous segment is returned. * Read only. */ - curve: Curve; + readonly curve: Curve; /** * The curve location that describes this segment's position ont the path. * Read Only. */ - location: CurveLocation; + readonly location: CurveLocation; /** * The next segment in the path.segments array that the segment belongs to. If the segments belongs to a closed path, the first segment is returned for the last segment of the path. * Read Only. */ - next: Segment; + readonly next: Segment; /** * The previous segment in the path.segments array that the segment belongs to. If the segments belongs to a closed path, the last segment is returned for the first segment of the path. * Read Only. */ - previous: Segment; + readonly previous: Segment; /** - * Returns true if the the two segments are the beginning of two lines and if these two lines are running parallel. - * @param segment + * Checks if the segment has any curve handles set. */ - isColinear(segment: Segment): boolean; + hasHandles(): boolean; /** - * Returns true if the segment at the given index is the beginning of an orthogonal arc segment. The code looks at the length of the handles and their relation to the distance to the imaginary corner point. If the relation is kappa, then it's an arc. + * Checks if the segment connects two curves smoothly, meaning that its two handles are collinear and segment does not form a corner. */ - isArc(): boolean; + isSmooth(): boolean; + + /** + * Clears the segment’s handles by setting their coordinates to zero, turning the segment into a corner. + */ + clearHandles(): void; + + /** + * Smooths the bezier curves that pass through this segment by taking into account the segment’s position and distance to the neighboring segments and changing the direction and length of the segment’s handles accordingly without moving the segment itself. + * Two different smoothing methods are available: + * 'catmull-rom' uses the Catmull-Rom spline to smooth the segment. + * The optionally passed factor controls the knot parametrization of the algorithm: + * 0.0: the standard, uniform Catmull-Rom spline + * 0.5: the centripetal Catmull-Rom spline, guaranteeing no self-intersections + * 1.0: the chordal Catmull-Rom spline + * 'geometric' use a simple heuristic and empiric geometric method to smooth the segment’s handles. The handles were weighted, meaning that big differences in distances between the segments will lead to probably undesired results. + * The optionally passed factor defines the tension parameter (0…1), controlling the amount of smoothing as a factor by which to scale each handle. + * @param options [optional] - the smoothing options. default { type: 'catmull-rom', factor: 0.5 for 'catmull-rom', 0.4 for 'geometric'} + * @param options.type - the type of smoothing method: ‘catmull-rom’, ‘geometric’ + * @param options.factor - the factor parameterizing the smoothing method — default: 0.5 for 'catmull-rom', 0.4 for 'geometric' + */ + smooth(options?:{ type?: string; factor?: number; }): void; + + /** + * Checks if the this is the first segment in the path.segments array. + */ + isFirst(): boolean; + + /** + * Checks if the this is the last segment in the path.segments array. + */ + isLast(): boolean; + + /** + * Returns the reversed the segment, without modifying the segment itself. + */ + reversed(): Segment; /** * Returns the reversed the segment, without modifying the segment itself. @@ -2874,6 +3509,17 @@ declare module paper { */ remove(): boolean; + /** + * Checks whether the segment is equal to that of the supplied segment. + * @param segment - the segment to check against + */ + equals(segment: Segment): boolean; + + /** + * Returns a copy of the segment. + */ + clone(): Segment; + /** * A string representation of the segment */ @@ -2885,6 +3531,14 @@ declare module paper { */ transform(matrix: Matrix): void; + /** + * Interpolates between the two specified segments and sets the point and handles of this segment accordingly. + * @param from - the segment defining the geometry when factor is 0 + * @param to - the segment defining the geometry when factor is 1 + * @param factor - the interpolation coefficient, typically between 0 and 1, but extrapolation is possible too + */ + interpolate(from: Segment, to: Segment, factor: number): void; + } /** * The Curve object represents the parts of a path that are connected by two following Segment objects. The curves of a path can be accessed through its path.curves array. @@ -2932,48 +3586,68 @@ declare module paper { * The first segment of the curve. * Read Only. */ - segment1: Segment; + readonly segment1: Segment; /** * The second segment of the curve. * Read only. */ - segment2: Segment; + readonly segment2: Segment; /** * The path that the curve belongs to. * Read only. */ - path: Path; + readonly path: Path; /** * The index of the curve in the path.curves array. * Read Only. */ - index: number; + readonly index: number; /** * The next curve in the path.curves array that the curve belongs to. * Read Only */ - next: Curve; + readonly next: Curve; /** * The previous curve in the path.curves array that the curve belongs to. * Read Only. */ - previous: Curve; + readonly previous: Curve; /** * Specifies whether the points and handles of the curve are selected. */ selected: boolean; + /** + * An array of 8 float values, describing this curve’s geometry in four absolute x/y pairs (point1, handle1, handle2, point2). This format is used internally for efficient processing of curve geometries, e.g. when calculating intersections or bounds. + * Note that the handles are converted to absolute coordinates. + * Read only. + */ + readonly values: number[]; + + /** + * An array of 4 point objects, describing this curve’s geometry in absolute coordinates (point1, handle1, handle2, point2). + * Note that the handles are converted to absolute coordinates. + * Read only. + */ + readonly points: Point[]; + /** * The approximated length of the curve in points. * Read Only. */ - length: number; + readonly length: number; + + /** + * The area that the curve’s geometry is covering. + * Read only. + */ + readonly area: number; /** * The bounding rectangle of the curve excluding stroke width. @@ -2991,21 +3665,67 @@ declare module paper { handleBounds: Rectangle; /** - * Checks if this curve is linear, meaning it does not define any curve handle. + * Returns a copy of the curve. */ - isLinear(): boolean; + clone(): Curve; /** - * TODO? + * Returns a string representation of the curve */ - //isHorizontal(): boolean; + toString(): string; + + /** + * Determines the type of cubic Bézier curve via discriminant classification, as well as the curve-time parameters of the associated points of inflection, loops, cusps, etc. + * Returns the curve classification information as an object + * type - the type of Bézier curve, possible values are: ‘line’, ‘quadratic’, ‘serpentine’, ‘cusp’, ‘loop’, ‘arch’ + * roots - the curve-time parameters of the associated points of inflection for serpentine curves, loops, cusps, etc + */ + classify(): { type: string, roots: number[] }; + + /** + * Removes the curve from the path that it belongs to, by removing its second segment and merging its handle with the first segment. + */ + remove(): boolean; + + /** + * Checks if the this is the first curve in the path.curves array. + */ + isFirst(): boolean; + + /** + * Checks if the this is the last curve in the path.curves array. + */ + isLast(): boolean; + + /** + * Creates a new curve as a sub-curve from this curve, its range defined by the given curve-time parameters. If from is larger than to, then the resulting curve will have its direction reversed. + * @param from - the curve-time parameter at which the sub-curve starts + * @param to - the curve-time parameter at which the sub-curve ends + */ + getPart(from: number, to: number): Curve; /** * Divides the curve into two curves at the given offset. The curve itself is modified and becomes the first part, the second part is returned as a new curve. If the modified curve belongs to a path item, the second part is also added to the path. - * @param offset [optional] - the offset on the curve at which to split, or the curve time parameter if isParameter is true default: 0.5 - * @param isParameter [optional] - pass true if offset is a curve time parameter. default: false + * @param offset [optional] - the offset on the curve at which to split, or the curve time parameter if isParameter is true. default: 0.5 + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false + * @returns the second part of the divided curve if the location is valid, {code null} otherwise */ - divide(offset?: number, isParameter?: boolean): Curve; + divide(offset?: number, isTime?: boolean): Curve; + + /** + * Divides the curve into two curves at the given offset or location. The curve itself is modified and becomes the first part, the second part is returned as a new curve. If the curve belongs to a path item, a new segment is inserted into the path at the given location, and the second part becomes a part of the path as well. + * @param location - the offset or location on the curve at which to divide + * @returns the second part of the divided curve if the location is valid, {code null} otherwise + */ + divideAt(location: number | CurveLocation): Curve; + + /** + * Divides the curve into two curves at the given offset or location. The curve itself is modified and becomes the first part, the second part is returned as a new curve. If the curve belongs to a path item, a new segment is inserted into the path at the given location, and the second part becomes a part of the path as well. + * @param time - the curve-time parameter on the curve at which to divide + * @param setHandles - whether to set handles on the new curves. default is the output of hasHandles(). + * @returns the second part of the divided curve if the location is valid, {code null} otherwise + */ + divideAtTime(time: number, setHandles?:boolean): Curve; /** * Splits the path this curve belongs to at the given offset. After splitting, the path will be open. If the path was open already, splitting will result in two paths. @@ -3014,46 +3734,100 @@ declare module paper { */ split(offset?: number, isParameter?: boolean): Path; + /** + * Splits the path this curve belongs to at the given offset. After splitting, the path will be open. If the path was open already, splitting will result in two paths. + * @param location - the offset or location on the curve at which to split + * @returns the newly created path after splitting, if any + */ + splitAt(location: number | CurveLocation): Path; + + /** + * Splits the path this curve belongs to at the given offset. After splitting, the path will be open. If the path was open already, splitting will result in two paths. + * @param time - the curve-time parameter on the curve at which to split + */ + splitAtTime(time: number): Path; + /** * Returns a reversed version of the curve, without modifying the curve itself. */ - reverse(): Curve; + reversed(): Curve; + + /** + * Clears the curve’s handles by setting their coordinates to zero, turning the curve into a straight line. + */ + clearHandles(): void; /** - * Removes the curve from the path that it belongs to, by merging its two path segments. - * returns true if the curve was removed, false otherwise + * Checks if this curve has any curve handles set. */ - remove(): boolean; + hasHandles(): boolean; /** - * Returns a copy of the curve. + * Checks if this curve has any length. + * @param epsilon [optional] - the epsilon against which to compare the curve’s length. default: 0 */ - clone(): Curve; + hasLength(epsilon?: number): boolean; /** - * returns a string representation of the curve + * Checks if this curve appears as a straight line. This can mean that it has no handles defined, or that the handles run collinear with the line that connects the curve’s start and end point, not falling outside of the line. */ - toString(): string; + isStraight(): boolean; + + /** + * Checks if this curve is linear, meaning it does not define any curve handle. + */ + isLinear(): boolean; + + /** + * Checks if the the two curves describe straight lines that are collinear, meaning they run in parallel. + * @param curve - the other curve to check against + */ + isCollinear(curve: Curve): boolean; + + /** + * Checks if the curve is a straight horizontal line. + */ + isHorizontal(): boolean; + + /** + * Checks if the curve is a straight vertical line. + */ + isVertical(): boolean; /** * Calculates the curve time parameter of the specified offset on the path, relative to the provided start parameter. If offset is a negative value, the parameter is searched to the left of the start parameter. If no start parameter is provided, a default of 0 for positive values of offset and 1 for negative values of offset. - * @param offset - - * @param start [optional] - + * @param offset - the offset at which to find the curve-time, in curve length units + * @param start [optional] - the curve-time in relation to which the offset is determined + * @deprecated use getTimeAt instead */ - getParameterAt(offset: Point, start?: number): number; + getParameterAt(offset: number, start?: number): number; /** * Returns the curve time parameter of the specified point if it lies on the curve, null otherwise. * @param point - the point on the curve. + * @deprecated use getTimeOf instead */ getParameterOf(point: Point): number; /** * Calculates the curve location at the specified offset or curve time parameter. * @param offset - the offset on the curve, or the curve time parameter if isParameter is true - * @param isParameter [optional] - pass true if offset is a curve time parameter. default: false + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false */ - getLocationAt(offset: number, isParameter?: boolean): CurveLocation; + getLocationAt(offset: number, isTime?: boolean): CurveLocation; + + /** + * Calculates the curve-time parameter of the specified offset on the path, relative to the provided start parameter. If offset is a negative value, the parameter is searched to the left of the start parameter. If no start parameter is provided, a default of 0 for positive values of offset and 1 for negative values of offset. + * @param offset - the offset at which to find the curve-time, in curve length units + * @param start [optional] - the curve-time in relation to which the offset is determined + */ + getTimeAt(offset: number, start?: number): number; + + /** + * Calculates the curve offset at the specified curve-time parameter on the curve. + * @param time - the curve-time parameter on the curve + */ + getOffsetAtTime(time: number): number; /** * Returns the curve location of the specified point if it lies on the curve, null otherwise. @@ -3067,33 +3841,71 @@ declare module paper { */ getOffsetOf(point: Point): number; + /** + * Returns the curve-time parameter of the specified point if it lies on the curve, null otherwise. Note that if there is more than one possible solution in a self-intersecting curve, the first found result is returned. + * @param point - the point on the curve + */ + getTimeOf(point: Point): number; + + /** + * Returns the nearest location on the curve to the specified point. + * @param point - the point for which we search the nearest location + */ + getNearestLocation(point: Point): CurveLocation; + + /** + * Returns the nearest point on the curve to the specified point. + * @param point - the point for which we search the nearest point + */ + getNearestPoint(point: Point): Point; + /** * Calculates the point on the curve at the given offset. * @param offset - the offset on the curve, or the curve time parameter if isParameter is true - * @param isParameter [optional] - pass true if offset is a curve time parameter. default: false + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false */ - getPointAt(offset: number, isParameter?: boolean): Point; + getPointAt(offset: number, isTime?: boolean): Point; /** * Calculates the tangent vector of the curve at the given offset. * @param offset - the offset on the curve, or the curve time parameter if isParameter is true - * @param isParameter [optional] - pass true if offset is a curve time parameter. default: false + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false */ - getTangentAt(offset: number, isParameter?: boolean): Point; + getTangentAt(offset: number, isTime?: boolean): Point; /** * Calculates the normal vector of the curve at the given offset. * @param offset - the offset on the curve, or the curve time parameter if isParameter is true - * @param isParameter [optional] - pass true if offset is a curve time parameter. default: false + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false */ - getNormalAt(offset: number, isParameter?: boolean): Point; + getNormalAt(offset: number, isTime?: boolean): Point; + + /** + * Calculates the weighted tangent vector of the curve at the given offset. + * @param offset - the offset on the curve, or the curve time parameter if isParameter is true + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false + */ + getWeightedTangentAt(offset: number, isTime?: boolean): Point; + + /** + * Calculates the weighted normal vector of the curve at the given offset. + * @param offset - the offset on the curve, or the curve time parameter if isParameter is true + * @param isTime [optional] - pass true if offset is a curve time parameter. default: false + */ + getWeightedNormalAt(offset: number, isTime?: boolean): Point; /** * Calculates the curvature of the curve at the given offset. Curvatures indicate how sharply a curve changes direction. A straight line has zero curvature, where as a circle has a constant curvature. The curve's radius at the given offset is the reciprocal value of its curvature. * @param offset - the offset on the curve, or the curve time parameter if isParameter is true - * @param isParameter - pass true if offset is a curve time parameter. default: false + * @param isTime - pass true if offset is a curve time parameter. default: false */ - getCurvatureAt(offset: number, isParameter?: boolean): Point; + getCurvatureAt(offset: number, isTime?: boolean): Point; + + /** + * Returns all intersections between two Curve objects as an array of CurveLocation objects. + * @param curve - the other curve to find the intersections with (if the curve itself or null is passed, the self intersection of the curve is returned, if it exists) + */ + getIntersections(curve: Curve): CurveLocation[]; } /** @@ -3105,73 +3917,98 @@ declare module paper { /** * Creates a new CurveLocation object. * @param curve - - * @param parameter - - * @param point - + * @param time - + * @param point [optional] */ - constructor(curve: Curve, parameter: number, point: Point); + constructor(curve: Curve, time: number, point?: Point); /** * The segment of the curve which is closer to the described location. * Read Only */ - segment: Segment; + readonly segment: Segment; /** * The curve that this location belongs to. * Read Only */ - curve: Curve; - - /** - * The curve location on the intersecting curve, if this location is the result of a call to pathItem.getIntersections(path) / Curve#getIntersections(curve). - * Read Only - */ - intersection: CurveLocation; + readonly curve: Curve; /** * The path this curve belongs to, if any. * Read Only */ - path: Path; + readonly path: Path; /** * The index of the curve within the path.curves list, if the curve is part of a Path item. * Read Only. */ - index: number; + readonly index: number; + + /** + * 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). + * Read only. + * @deprecated use time instead + */ + readonly parameter: number; + + /** + * The curve-time parameter, as used by various bezier curve calculations. It is value between 0 (beginning of the curve) and 1 (end of the curve). + * Read Only. + */ + readonly time: number; + + /** + * The point which is defined by the curve and time. + * Read Only. + */ + readonly point: Point; /** * The length of the path from its beginning up to the location described by this object. If the curve is not part of a path, then the length within the curve is returned instead. * Read only. */ - offset: number; + readonly offset: number; /** * The length of the curve from its beginning up to the location described by this object. * Read Only. */ - curveOffset: number; + readonly curveOffset: number; /** - * 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). - * Read only. + * The curve location on the intersecting curve, if this location is the result of a call to pathItem.getIntersections(path) / Curve#getIntersections(curve). + * Read Only. */ - parameter: number; + readonly intersection: CurveLocation; /** - * The point which is defined by the curve and parameter. + * The tangential vector to the curve at the given location. * Read only. */ - point: Point; + readonly tangent: Point; + + /** + * The normal vector to the curve at the given location. + * Read only. + */ + readonly normal: Point; + + /** + * The curvature of the curve at the given location. + * Read only. + */ + readonly curvature: number; /** * The distance from the queried point to the returned location. * Read Only. */ - distance: number; + readonly distance: number; /** - * Checks whether tow CurveLocation objects are describing the same location on a path, by applying the same tolerances as elsewhere when dealing with curve time parameters. + * Checks whether two CurveLocation objects are describing the same location on a path, by applying the same tolerances as elsewhere when dealing with curve time parameters. * @param location CurveLocation */ equals(location: CurveLocation): boolean; @@ -3181,6 +4018,21 @@ declare module paper { */ toString(): string; + /** + * Checks if the location is an intersection with another curve and is merely touching the other curve, as opposed to crossing it. + */ + isTouching(): boolean; + + /** + * Checks if the location is an intersection with another curve and is crossing the other curve, as opposed to just touching it. + */ + isCrossing(): boolean; + + /** + * Checks if the location is an intersection with another curve and is part of an overlap between the two involved paths. + */ + hasOverlap(): boolean; + } /** * 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. @@ -3200,7 +4052,7 @@ declare module paper { * The reference to the project's view. * Read only. */ - view: View; + readonly view: View; /** * The currently active path style. All selected items and newly created items will be styled with this style. @@ -3211,23 +4063,30 @@ declare module paper { * The index of the project in the paperScope.projects list. * Read Only */ - index: number; + readonly index: number; /** * The layers contained within the project. + * Read Only. */ - layers: Layer[]; + readonly layers: Layer[]; /** * The layer which is currently active. New items will be created on this layer by default. * Read Only. */ - activeLayer: Layer; + readonly activeLayer: Layer; /** * The symbols contained within the project. */ - symbols: Symbol[]; + readonly symbols: Symbol[]; + + /** + * The selected items contained within the project. + * Read only. + */ + readonly selectedItems: Item[]; /** * Activates this project, so all newly created items will be placed in it. @@ -3270,28 +4129,56 @@ declare module paper { insertLayer(index: number, layer: Layer): Layer; /** - * Perform a hit-test on the items contained within the project at the location of the specified point. + * Perform a hit-test on the items and its children within the project at the location of the specified point. * The options object allows you to control the specifics of the hit-test and may contain a combination of the following values: * @param point - the point where the hit-test should be performed * @param options.tolerance -the tolerance of the hit-test in points. Can also be controlled through paperScope.settings.hitTolerance * @param options.class - only hit-test again a certain item class and its sub-classes: Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, PointText, etc. + * @param options.match -a match function to be called for each found hit result: Return true to return the result, false to keep searching * @param options.fill - hit-test the fill of items. * @param options.stroke - hit-test the stroke of path items, taking into account the setting of stroke color and width. * @param options.segments - hit-test for segment.point of Path items. * @param options.curves - hit-test the curves of path items, without taking the stroke color or width into account. * @param options.handles - hit-test for the handles. (segment.handleIn / segment.handleOut) of path segments. * @param options.ends - only hit-test for the first or last segment points of open path items. - * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). + * @param options.position - hit-test the item.position of of items, which depends on the setting of item.pivot. * @param options.center - hit-test the rectangle.center of the bounding rectangle of items (item.bounds). + * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). * @param options.guides - hit-test items that have Item#guide set to true. * @param options.selected - only hit selected items. */ - hitTest(point: Point, options?: { tolerance?: number; class?: string; fill?: boolean; stroke?: boolean; segments?: boolean; curves?: boolean; handles?: boolean; ends?: boolean; bounds?: boolean; center?: boolean; guides?: boolean; selected?: boolean; }): HitResult; + hitTest(point: Point, options?: IHitTestOptions): HitResult; + + /** + * Performs a hit-test on the item and its children (if it is a Group or Layer) at the location of the specified point, returning all found hits. + * The options object allows you to control the specifics of the hit-test and may contain a combination of the following values: + * @param point - the point where the hit-test should be performed + * @param options.tolerance -the tolerance of the hit-test in points. Can also be controlled through paperScope.settings.hitTolerance + * @param options.class - only hit-test again a certain item class and its sub-classes: Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, PointText, etc. + * @param options.match -a match function to be called for each found hit result: Return true to return the result, false to keep searching + * @param options.fill - hit-test the fill of items. + * @param options.stroke - hit-test the stroke of path items, taking into account the setting of stroke color and width. + * @param options.segments - hit-test for segment.point of Path items. + * @param options.curves - hit-test the curves of path items, without taking the stroke color or width into account. + * @param options.handles - hit-test for the handles. (segment.handleIn / segment.handleOut) of path segments. + * @param options.ends - only hit-test for the first or last segment points of open path items. + * @param options.position - hit-test the item.position of of items, which depends on the setting of item.pivot. + * @param options.center - hit-test the rectangle.center of the bounding rectangle of items (item.bounds). + * @param options.bounds - hit-test the corners and side-centers of the bounding rectangle of items (item.bounds). + * @param options.guides - hit-test items that have Item#guide set to true. + * @param options.selected - only hit selected items. + * */ + hitTestAll(point: Point, options?: IHitTestOptions): HitResult[]; /** * Fetch items contained within the project whose properties match the criteria in the specified object. * Extended matching is possible by providing a compare function or regular expression. Matching points, colors only work as a comparison of the full object, not partial matching (e.g. only providing the x- coordinate to match all points with that x-value). Partial matching does work for item.data. * Matching items against a rectangular area is also possible, by setting either match.inside or match.overlapping to a rectangle describing the area in which the items either have to be fully or partly contained. + * @param match.recursive - whether to loop recursively through all children, or stop at the current level — default: true + * @param match.match - a match function to be called for each item, allowing the definition of more flexible item checks that are not bound to properties. If no other match properties are defined, this function can also be passed instead of the options object + * @param match.class - the constructor function of the item type to match against + * @param match.inside - the rectangle in which the items need to be fully contained. + * @param match.overlapping - the rectangle with which the items need to at least partly overlap. */ getItems(match: any): Item[]; @@ -3317,22 +4204,37 @@ declare module paper { /** * Exports the project with all its layers and child items as an SVG DOM, all contained in one top level SVG group node. - * @param options [optional] the export options, default: { asString: false, precision: 5, matchShapes: false } + * @param options [optional] the export options, default: { asString: false, precision: 5, matchShapes: false, bounds: 'view', matrix: paper.view.matrix, embedImages: true } * @param options.asString - whether a SVG node or a String is to be returned. * @param options.precision - the amount of fractional digits in numbers used in SVG data. * @param options.matchShapes - whether path items should tried to be converted to shape items, if their geometries can be made to match + * @param options.bounds - the bounds of the area to export, either as a string (‘view’, content’), or a Rectangle object: 'view' uses the view bounds, 'content' uses the stroke bounds of all content. + * @param options.matrix - the matrix with which to transform the exported content: If options.bounds is set to 'view', paper.view.matrix is used, for all other settings of options.bounds the identity matrix is used. + * @param options.embedImages: whether raster images should be embedded as base64 data inlined in the xlink:href attribute, or kept as a link to their external URL. */ - exportSVG(options?: { asString?: boolean; precision?: number; matchShapes?: boolean }): SVGElement; + exportSVG(options?: { asString?: boolean; precision?: number; matchShapes?: boolean; bounds?: string | Rectangle; matrix?: Matrix; embedImages?: boolean; }): SVGElement; /** * Converts the provided SVG content into Paper.js items and adds them to the active layer of this project. * Note that the project is not cleared first. You can call project.clear() to do so. * @param svg - the SVG content to import - * @param options [optional] - the import options, default: { expandShapes: false } + * @param options [optional] - the import options, default: { expandShapes: false, insert: true, applyMatrix: paperScope.settings.applyMatrix } * @param options.expandShapes - whether imported shape items should be expanded to path items. + * @param options.onLoad - the callback function to call once the SVG content is loaded from the given URL receiving two arguments: the converted item and the original svg data as a string. Only required when loading from external resources. + * @param options.onError - the callback function to call if an error occurs during loading. Only required when loading from external resources. + * @param options.insert: Boolean — whether the imported items should be added to the item that importSVG() is called on. + * @param options.applyMatrix Boolean — whether the imported items should have their transformation matrices applied to their contents or not. */ - importSVG(svg: SVGElement | string, options?: any): Item; + importSVG(svg: SVGElement | string, options?: { expandShapes?: boolean; onLoad?: (item: Item, svg: string) => void; onError?: (message: string, status: number) => void; insert?: true; applyMatrix?: Matrix; }): Item; + /** + * Converts the provided SVG content into Paper.js items and adds them to the active layer of this project. + * Note that the project is not cleared first. You can call project.clear() to do so. + * @param svg - the SVG content to import + * @param onLoad [optional] - the callback function to call once the SVG content is loaded from the given URL receiving two arguments: the converted item and the original svg data as a string. Only required when loading from external resources. + */ + importSVG(svg: SVGElement | string, onLoad?: (item: Item, svg: string) => void): Item; + } /** * Symbols allow you to place multiple instances of an item in your project. This can save memory, since all instances of a symbol simply refer to the original item and it can speed up moving around complex objects, since internal properties such as segment lists and gradient positions don't need to be updated with every transformation. @@ -3350,7 +4252,7 @@ declare module paper { * The project that this symbol belongs to. * Read Only. */ - project: Project; + readonly project: Project; /** * The symbol definition. @@ -3368,6 +4270,12 @@ declare module paper { */ clone(): Symbol; + /** + * Checks whether the symbol’s definition is equal to the supplied symbol. + * @param symbol Symbol + */ + equals(symbol: Symbol): boolean; + } /** * Style is used for changing the visual styles of items contained within a Paper.js project and is returned by item.style and project.currentStyle. @@ -3380,7 +4288,7 @@ declare module paper { * The view that this style belongs to. * Read only. */ - view?: View; + readonly view?: View; /** * The color of the stroke. @@ -3389,38 +4297,45 @@ declare module paper { /** * The width of the stroke. + * Default: 1 */ strokeWidth?: number; /** * The shape to be used at the beginning and end of open Path items, when they have a stroke. - * String('round', 'square', 'butt' + * Values: 'round', 'square', 'butt' + * Default: 'butt' */ strokeCap?: string; /** * The shape to be used at the segments and corners of Path items when they have a stroke. - * String('miter', 'round', 'bevel') + * Values: 'miter', 'round', 'bevel' + * Default: 'miter' */ strokeJoin?: string; /** * Specifies whether the stroke is to be drawn taking the current affine transformation into account (the default behavior), or whether it should appear as a non-scaling stroke. + * Default: true */ strokeScaling?: boolean; /** * The dash offset of the stroke. + * Default: 0 */ dashOffset?: number; /** * Specifies an array containing the dash and gap lengths of the stroke. + * Default: [] */ dashArray?: number[]; /** * The miter limit of the stroke. When two line segments meet at a sharp angle and miter joins have been specified for strokeJoin, it is possible for the miter to extend far beyond the strokeWidth of the path. The miterLimit imposes a limit on the ratio of the miter length to the strokeWidth. + * Default: 10 */ miterLimit?: number; @@ -3429,6 +4344,13 @@ declare module paper { */ fillColor?: Color | string; + /** + * The fill-rule with which the shape gets filled. Please note that only modern browsers support fill-rules other than 'nonzero'. + * Values: 'nonzero', 'evenodd' + * Default: 'nonzero' + */ + fillRule?: string; + /** * The shadow color. */ @@ -3436,11 +4358,13 @@ declare module paper { /** * The shadow's blur radius. + * Default: 0 */ shadowBlur?: number; /** * The shadow's offset. + * Default: 0 */ shadowOffset?: Point; @@ -3450,27 +4374,33 @@ declare module paper { selectedColor?: Color | string; /** - * The font-family to be used in text content. default 'sans-serif' + * The font-family to be used in text content. + * Default: 'sans-serif' */ fontFamily?: string; /** * The font-weight to be used in text content. + * Default: 'normal' */ fontWeight?: string | number; /** * The font size of text content, as {@Number} in pixels, or as {@String} with optional units 'px', 'pt' and 'em'. + * Default: 10 */ fontSize?: string | number; /** * The text leading of text content. + * Default: fontSize * 1.2 */ leading?: number | string; /** - * The justification of text paragraphs. default "left" + * The justification of text paragraphs. + * Values: 'left', 'right', 'center' + * Default: 'left' */ justification?: string; @@ -3570,10 +4500,10 @@ declare module paper { constructor(color: Gradient, origin: Point, destination: Point, highlight?: Point); /** - * Creates a RGB Color object. - * @param hex - the RGB color in hex, i.e. #000000 + * Creates a RGB Color object from CSS string + * @param css - the RGB color in hex, i.e. #000000, rbga, i.e. rgba(0,0,0,0) or named color. */ - constructor(hex: string); + constructor(css: string); /** * The type of the color as a string. @@ -3585,7 +4515,7 @@ declare module paper { * The color components that define the color, including the alpha value if defined. * Read Only. */ - components: number; + readonly components: number; /** * The color's alpha value as a number between 0 and 1. @@ -3635,14 +4565,61 @@ declare module paper { lightness: number; /** - * The gradient object describing the type of gradient and the stops. + * The gradient object describing the type of gradient and the stops. Only defined if the color was constructed as a gradient. */ - gradient: Gradient; + gradient?: Gradient; + + /** + * The starting point of the gradient. Only defined if the color was constructed as a gradient. + */ + origin?: Point; + + /** + * The ending point of the gradient. Only defined if the color was constructed as a gradient. + */ + destination?: Point; /** - * The highlight point of the gradient. + * The highlight point of the gradient. Only defined if the color was constructed as a gradient. */ - highlight: Point; + highlight?: Point; + + /** + * Sets color to a RGB Color object. + * @param red - the amount of red in the color as a value between 0 and 1 + * @param green - the amount of green in the color as a value between 0 and 1 + * @param blue - the amount of blue in the color as a value between 0 and 1 + * @param alpha [optional] - the alpha of the color as a value between 0 and 1 + */ + set(red: number, green: number, blue: number, alpha?: number): void; + + /** + * Sets color to a gray Color object. + * @param gray - the amount of gray in the color as a value between 0 and 1 + * @param alpha [optional] - the alpha of the color as a value between 0 and 1 + */ + set(gray: number, alpha?: number): void; + + /** + * Sets color to a HSB, HSL or gradient Color object from the properties of the provided object: + * @param object - an object describing the components and properties of the color. + */ + set(object: IHSBColor | IHSLColor | IGradientColor): void; + + /** + * Sets color to a gradient Color object. + * @param gradient - + * @param origin - + * @param destination - + * @param highlight [optional] - + */ + set(color: Gradient, origin: Point, destination: Point, highlight?: Point): void; + + /** + * Sets color to a RGB Color object from CSS string + * @param css - the RGB color in hex, i.e. #000000, rbga, i.e. rgba(0,0,0,0) or named color. + */ + set(css: string): void; /** * Converts the color another type. @@ -3683,12 +4660,73 @@ declare module paper { */ transform(matrix: Matrix): void; + /** + * Returns the addition of the supplied value to both coordinates of the color as a new color. The object itself is not modified! + * @param number - the number to add + */ + add(number: number): Color; + + /** + * Returns the addition of the supplied color to the color as a new color. The object itself is not modified! + * @param color - the color to add + */ + add(color: Color): Color; + + /** + * Returns the subtraction of the supplied value to both coordinates of the color as a new color. The object itself is not modified! + * @param number - the number to subtract + */ + subtract(number: number): Color; + + /** + * Returns the subtraction of the supplied color to the color as a new color. The object itself is not modified! + * @param color - the color to subtract + */ + subtract(color: Color): Color; + + /** + * Returns the multiplication of the supplied value to both coordinates of the color as a new color. The object itself is not modified! + * @param number - the number to multiply + */ + multiply(number: number): Color; + + /** + * Returns the multiplication of the supplied color to the color as a new color. The object itself is not modified! + * @param color - the color to multiply + */ + multiply(color: Color): Color; + + /** + * Returns the division of the supplied value to both coordinates of the color as a new color. The object itself is not modified! + * @param number - the number to divide + */ + divide(number: number): Color; + + /** + * Returns the division of the supplied color to the color as a new color. The object itself is not modified! + * @param color - the color to divide + */ + divide(color: Color): Color; + } /** * The Gradient object. */ export class Gradient { + /** + * Creates a Gradient object. + * @param stops [optional] - Array of GradientStops + * @param radial [optional] - Whether the gradient is radial or linear + */ + constructor(stops?:GradientStop[] | string[] | (string|number)[][], radial?:boolean); + + /** + * Creates a Gradient object. + * @param object [optional] - an object literal containing the properties to be set on the group. + */ + constructor(object?:any); + /** * The gradient stops on the gradient ramp. */ @@ -3721,12 +4759,30 @@ declare module paper { * @param color [optional] - the color of the stop, default: new Color(0, 0, 0) * @param rampPoint [optional] - the position of the stop on the gradient ramp as a value between 0 and 1, default: 0 */ - constructor(color?: Color, rampPoint?: number); + constructor(color?: Color | string, rampPoint?: number); + + /** + * Creates a new GradientStop object. + * @param object [optional] - an object literal containing the properties to be set on the group. + */ + constructor(object?: any); + + /** + * Creates a new GradientStop object. + * @param array [optional] - an object literal containing the properties to be set on the group. + */ + constructor(array?: [string, number]); + + /** + * The ramp-point of the gradient stop as a value between 0 and 1. + * @deprecated use offset instead. + */ + rampPoint: number; /** * The ramp-point of the gradient stop as a value between 0 and 1. */ - rampPoint: number; + offset: number; /** * The color of the gradient stop. @@ -3744,25 +4800,30 @@ declare module paper { */ export class View { + /** + * Controls whether the view is automatically updated in the next animation frame on changes, or whether you prefer to manually call update() or requestUpdate() after changes. Note that this is true by default, except for Node.js, where manual updates make more sense. + */ + autoUpdate: boolean; + /** * The underlying native element. * Read Only. */ - element: HTMLCanvasElement; + readonly element: HTMLCanvasElement; /** * The ratio between physical pixels and device-independent pixels (DIPs) of the underlying canvas / device. * It is 1 for normal displays, and 2 or more for high-resolution displays. * Read only. */ - pixelRatio: number; + readonly pixelRatio: number; /** * The resoltuion of the underlying canvas / device in pixel per inch (DPI). * It is 72 for normal displays, and 144 for high-resolution displays with a pixel-ratio of 2. * Read only. */ - resolution: number; + readonly resolution: number; /** * The size of the view. Changing the view's size will resize it's underlying element. @@ -3779,7 +4840,7 @@ declare module paper { * The size of the visible area in project coordinates. * Read only. */ - size: Size; + readonly size: Size; /** * The center of the visible area in project coordinates. @@ -3791,6 +4852,21 @@ declare module paper { */ zoom: number; + /** + * The current rotation angle of the view, as described by its matrix. + */ + rotation: number; + + /** + * The current scale factor of the view, as described by its matrix. + */ + scaling: number; + + /** + * The view’s transformation matrix, defining the view onto the project’s contents (position, zoom level, rotation, etc). + */ + matrix: Matrix; + /** * Handler function to be called on each frame of an animation. * The function receives an event object which contains information about the frame event: @@ -3804,45 +4880,53 @@ declare module paper { /** * The function to be called when the mouse button is pushed down on the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseDown: (event: MouseEvent) => void; + onMouseDown: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse position changes while the mouse is being dragged. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseDrag: (event: MouseEvent) => void; + onMouseDrag: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse button is released over the item. * The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseUp: (event: MouseEvent) => void; + onMouseUp: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse clicks on the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onClick: (event: MouseEvent) => void; + onClick: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse double clicks on the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onDoubleClick: (event: MouseEvent) => void; + onDoubleClick: (event: MouseEvent) => void | boolean; /** * The function to be called repeatedly when the mouse moves on top of the item. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseMove: (event: MouseEvent) => void; + onMouseMove: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse moves over the item. This function will only be called again, once the mouse moved outside of the item first. The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseEnter: (event: MouseEvent) => void; + onMouseEnter: (event: MouseEvent) => void | boolean; /** * The function to be called when the mouse moves out of the item. * The function receives a MouseEvent object which contains information about the mouse event. + * Note that such mouse events bubble up the scene graph hierarchy and will reach the view, unless they are stopped with event.stopPropagation() or by returning false from the handler. */ - onMouseLeave: (event: MouseEvent) => void; + onMouseLeave: (event: MouseEvent) => void | boolean; /** * Removes this view from the project and frees the associated element. @@ -3854,6 +4938,11 @@ declare module paper { */ isVisible(): boolean; + /** + * Checks whether the view is inserted into the browser DOM. + */ + isInserted(): boolean; + /** * Scrolls the view by the given vector. * @param point - the vector to scroll by @@ -3876,25 +4965,99 @@ declare module paper { update(): void; /** - * - * @param point - + * Requests an update of the view if there are changes through the browser’s requestAnimationFrame() mechanism for smooth animation. Note that when using built-in event handlers for interaction, animation and load events, updates are automatically invoked for you automatically at the end. + */ + requestUpdate(): void; + + /** + * Translates (scrolls) the view by the given offset vector. + * @param delta - the offset to translate the view by + */ + translate(delta: Point): void; + + /** + * Rotates the view by a given angle around the given center point. + * Angles are oriented clockwise and measured in degrees. + * @param angle - the rotation angle + * @param center [optional] - default: view.center + */ + rotate(angle:number, center?: Point): void; + + /** + * Scales the view by the given value from its center point, or optionally from a supplied point. + * @param scale - the scale factor + * @param center [optional] - default: view.center + */ + scale(scale: number, center?: Point): void; + + /** + * Scales the view by the given values from its center point, or optionally from a supplied point. + * @param hor - the horizontal scale factor + * @param ver - the vertical scale factor + * @param center [optional] - default: view.center + */ + scale(hor: number, ver: number, center?: Point): void; + + /** + * Shears the view by the given value from its center point, or optionally from a supplied point. + * @param shear - the shear factor + * @param center [optional] - default: view.center + */ + shear(shear: Point, center?: Point): void; + + /** + * Shears the view by the given values from its center point, or optionally from a supplied point. + * @param hor - the horizontal shear factor + * @param ver - the vertical shear factor + * @param center [optional] - default: view.center + */ + shear(hor: number, ver: number, center?: Point): void; + + /** + * Skews the view by the given value from its center point, or optionally from a supplied point. + * @param skew - the horziontal and vertical skew angles in degrees + * @param center [optional] - default: view.center + */ + skew(skew: Point, center?: Point): void; + + /** + * Skews the view by the given values from its center point, or optionally from a supplied point. + * @param hor - the horizontal skew angle in degrees + * @param ver - the vertical skew angle in degrees + * @param center [optional] - default: view.center + */ + skew(hor: number, ver: number, center?: Point): void; + + /** + * Converts the passed point from project coordinate space to view coordinate space, which is measured in browser pixels in relation to the position of the view element. + * @param point - the point in project coordinates to be converted */ projectToView(point: Point): Point; /** - * - * @param point - + * Converts the passed point from view coordinate space to project coordinate space. + * @param point - the point in view coordinates to be converted */ viewToProject(point: Point): Point; - //I cannot use function: Function as it is a reserved keyword + /** + * Determines and returns the event location in project coordinate space. + * @param event - the native event object for which to determine the location. + */ + getEventPoint(event: Event): Point; /** * Attach an event handler to the view. - * @param type - String('frame'|'resize') the event type - * @param function - The function to be called when the event occurs + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be called when the event occurs */ - on(type: string, callback: (event: Event) => void): Item; + on(type: string, callback: (event: Event) => void | boolean): Item; + /** + * Attach an event handler to the view. + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be called when the event occurs + */ + on(type: string, callback: (event: IFrameEvent) => void | boolean): Item; /** * Attach one or more event handlers to the view. @@ -3903,10 +5066,16 @@ declare module paper { /** * Detach an event handler from the view. - * @param type - String('frame'|'resize') the event type - * @param function - The function to be detached + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be detached */ - off(type: string, callback: (event: Event) => void): Item; + off(type: string, callback: (event: Event) => void | boolean): Item; + /** + * Detach an event handler from the view. + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ + * @param callback - The function to be detached + */ + off(type: string, callback: (event: IFrameEvent) => void | boolean): Item; /** * Detach one or more event handlers from the view. @@ -3916,14 +5085,14 @@ declare module paper { /** * Emit an event on the view. - * @param type - String('frame'|'resize') the event type + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ * @param event - an object literal containing properties describing the event. */ emit(type: string, event: any): boolean; /** * Check if the view has one or more event handlers of the specified type. - * @param type - String('frame'|'resize') the event type + * @param type - the event type: ‘frame’, ‘resize’, ‘mousedown’, ‘mouseup’, ‘mousedrag’, ‘click’, ‘doubleclick’, ‘mousemove’, ‘mouseenter’, ‘mouseleave’ */ responds(type: string): boolean; @@ -3957,36 +5126,36 @@ declare module paper { /** * The function to be called when the mouse button is pushed down. The function receives a ToolEvent object which contains information about the mouse event. */ - onMouseDown: (event: ToolEvent) => void; + onMouseDown: (event: ToolEvent) => void | boolean; /** * The function to be called when the mouse position changes while the mouse is being dragged. The function receives a ToolEvent object which contains information about the mouse event. */ - onMouseDrag: (event: ToolEvent) => void; + onMouseDrag: (event: ToolEvent) => void | boolean; /** * The function to be called the mouse moves within the project view. The function receives a ToolEvent object which contains information about the mouse event. */ - onMouseMove: (event: ToolEvent) => void; + onMouseMove: (event: ToolEvent) => void | boolean; /** * The function to be called when the mouse button is released. The function receives a ToolEvent object which contains information about the mouse event. */ - onMouseUp: (event: ToolEvent) => void; + onMouseUp: (event: ToolEvent) => void | boolean; /** * The function to be called when the user presses a key on the keyboard. * The function receives a KeyEvent object which contains information about the keyboard event. * If the function returns false, the keyboard event will be prevented from bubbling up. This can be used for example to stop the window from scrolling, when you need the user to interact with arrow keys. */ - onKeyDown: (event: KeyEvent) => void; + onKeyDown: (event: KeyEvent) => void | boolean; /** * The function to be called when the user releases a key on the keyboard. * The function receives a KeyEvent object which contains information about the keyboard event. * If the function returns false, the keyboard event will be prevented from bubbling up. This can be used for example to stop the window from scrolling, when you need the user to interact with arrow keys. */ - onKeyUp: (event: KeyEvent) => void; + onKeyUp: (event: KeyEvent) => void | boolean; /** * Activates this tool, meaning paperScope.tool will point to it and it will be the one that recieves mouse events. @@ -3998,14 +5167,12 @@ declare module paper { */ remove(): void; - //I cannot use function: Function as it is a reserved keyword - /** * Attach an event handler to the tool. * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type * @param function - The function to be called when the event occurs */ - on(type: string, callback: (event: ToolEvent) => void): Tool; + on(type: string, callback: (event: ToolEvent | KeyEvent) => void | boolean): Tool; /** * Attach one or more event handlers to the tool. @@ -4018,7 +5185,7 @@ declare module paper { * @param type - String('mousedown'|'mouseup'|'mousedrag'|'mousemove'|'keydown'|'keyup') the event type * @param function - The function to be detached */ - off(type: string, callback: (event: ToolEvent) => void): Tool; + off(type: string, callback: (event: ToolEvent | KeyEvent) => void | boolean): Tool; /** * Detach one or more event handlers from the tool. @@ -4043,9 +5210,32 @@ declare module paper { export class Event { /** + * The time at which the event was created, in milliseconds since the epoch. + * Read only. + */ + readonly timeStamp: number; + + /** + * The current state of the keyboard modifiers. * Read Only */ - modifiers: any; + readonly modifiers: any; + + /** + * Cancels the event if it is cancelable, without stopping further propagation of the event. + */ + preventDefault(): void; + + /** + * Prevents further propagation of the current event. + */ + stopPropagation(): void; + + /** + * Cancels the event if it is cancelable, and stops stopping further propagation of the event. This is has the same effect as calling both stopPropagation() and preventDefault(). + * Any handler can also return false to indicate that stop() should be called right after. + */ + stop(): void; } /** @@ -4102,6 +5292,20 @@ declare module paper { } export class Key { + /** + * + * The current state of the keyboard modifiers. + * modifiers.shift - true if the shift key is pressed, false otherwise. + * modifiers.control - true if the control key is pressed, false otherwise. + * modifiers.alt — true if the alt/option key is pressed, false otherwise. + * modifiers.meta — true if the meta/windows/command key is pressed, false otherwise. + * modifiers.capsLock — true if the caps-lock key is active, false otherwise. + * modifiers.space — true if the space key is pressed, false otherwise. + * modifiers.option — true if the alt/option key is pressed, false otherwise. This is the same as modifiers.alt + * modifiers.command — true if the meta key is pressed on Mac, or the control key is pressed on Windows and Linux, false otherwise. + */ + static modifiers: { shift: boolean, control: boolean, alt: boolean, meta: boolean, capsLock: boolean, space: boolean, option: boolean, command: boolean}; + /** * Checks whether the specified key is pressed. * @param key - One of: 'backspace', 'enter', 'shift', 'control', 'option', 'pause', 'caps-lock', 'escape', 'space', 'end', 'home', 'left', 'up', 'right', 'down', 'delete', 'command' @@ -4148,30 +5352,43 @@ declare module paper { /** * The font-family to be used in text content. + * Default: 'sans-serif' */ fontFamily: string; /** * The font-weight to be used in text content. + * Default: 'normal' */ fontWeight: string | number; /** * The font size of text content, as {@Number} in pixels, or as {@String} with optional units 'px', 'pt' and 'em'. + * Default: 10 */ fontSize: string | number; /** * The text leading of text content. + * Default: fontSize * 1.2 */ leading: string | number; /** * The justification of text paragraphs. - * String('left', 'right', 'center') + * Values: 'left', 'right', 'center' + * Default: 'left' */ justification: string; + /** + * Clones the item within the same project and places the copy above the item. + * @param options [optional] - default: { insert: true, deep: true } + * @param options.insert: specifies whether the copy should be inserted into the DOM. When set to true, it is inserted above the original. default: true + * @param options.deep: specifies whether the item’s children should also be cloned — default: true + */ + clone(options?: { insert?: boolean; deep?: boolean; }): TextItem; + } /** * A PointText item represents a piece of typography in your Paper.js project which starts from a certain point and extends by the amount of characters contained in it. @@ -4245,32 +5462,6 @@ declare module paper { */ type: 'mousedown' | 'mouseup' | 'mousedrag' | 'click' | 'doubleclick' | 'mousemove' | 'mouseenter' | 'mouseleave'; - /** - * The time at which the event was created, in milliseconds since the - * epoch. - */ - timeStamp(): number; - - /** - * Cancels the event if it is cancelable, without stopping further - * propagation of the event. - */ - preventDefault(): void; - - /** - * Prevents further propagation of the current event. - */ - stopPropagation(): void; - - /** - * Cancels the event if it is cancelable, and stops stopping further - * propagation of the event. This is has the same effect as calling - * both stopPropagation() and preventDefault(). - * - * Any handler can also return false to indicate that stop() should be - * called right after. - */ - stop(): void; } } diff --git a/types/paper/paper-tests.ts b/types/paper/paper-tests.ts index 444ffb8725..165c64b2d8 100644 --- a/types/paper/paper-tests.ts +++ b/types/paper/paper-tests.ts @@ -1,19 +1,19 @@ import paper = require('paper'); -var canvas = document.createElement('canvas') +let canvas = document.createElement('canvas') paper.setup(canvas); // Circle -var path = new paper.Path.Circle({ +let path = new paper.Path.Circle({ center: [80, 50], radius: 35, fillColor: 'red' }); // Dotted Line Tool -var dottedLinePath: paper.Path; -var dottedLineTool = new paper.Tool(); +let dottedLinePath: paper.Path = new paper.Path; +let dottedLineTool = new paper.Tool(); dottedLineTool.onMouseDown = function(event: any) { new paper.Layer().activate(); @@ -34,3 +34,15225 @@ dottedLineTool.onMouseUp = function(event: any) { dottedLinePath.smooth(); dottedLinePath.simplify(); }; + +// Hit Test stuff +// These objects are to make sure older code which didn't have the IHitTestOptions available still work. +let hitOptionsEmpty = {}; +let hitOptionsPartial = {tolerance: 0, extra: true}; +let hitOptionsFull = {tolerance: 0, class: 'Path', match: (hit: paper.HitResult)=>{return true;}, fill: true, stroke: false, segments: true, curves: false, handles: true, ends: true, position: false, center: true, bounds: true, guides: false, selected: true}; +// These objects are to make sure new code which uses the IHitTestOptions work. +let hitOptionsInterfaceEmpty:paper.IHitTestOptions = {}; +let hitOptionsInterfacePartial:paper.IHitTestOptions = {match: (hit: paper.HitResult)=>{return true;}}; +let hitOptionsInterfaceFull:paper.IHitTestOptions = {tolerance: 0, class: 'Path', match: (hit: paper.HitResult)=>{return true;}, fill: true, stroke: false, segments: true, curves: false, handles: true, ends: true, position: false, center: true, bounds: true, guides: false, selected: true}; +let compoundPath: paper.CompoundPath = new paper.CompoundPath(dottedLinePath); +let hitTestPoint = dottedLinePath.segments[0].point; +let hitTestResult: paper.HitResult; +let hitTestResults: paper.HitResult[]; +// These are Item hit tests +hitTestResult = compoundPath.hitTest(hitTestPoint); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsEmpty); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsPartial); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsFull); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsInterfaceEmpty); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsInterfacePartial); +hitTestResult = compoundPath.hitTest(hitTestPoint, hitOptionsInterfaceFull); +hitTestResults = compoundPath.hitTestAll(hitTestPoint); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsEmpty); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsPartial); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsFull); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsInterfaceEmpty); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsInterfacePartial); +hitTestResults = compoundPath.hitTestAll(hitTestPoint, hitOptionsInterfaceFull); +// These are project hit tests +hitTestResult = paper.project.hitTest(hitTestPoint); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsEmpty); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsPartial); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsFull); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsInterfaceEmpty); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsInterfacePartial); +hitTestResult = paper.project.hitTest(hitTestPoint, hitOptionsInterfaceFull); +hitTestResults = paper.project.hitTestAll(hitTestPoint); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsEmpty); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsPartial); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsFull); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsInterfaceEmpty); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsInterfacePartial); +hitTestResults = paper.project.hitTestAll(hitTestPoint, hitOptionsInterfaceFull); + +function Examples() { + function BooleanOperations(){ + let text = new paper.PointText({ + position: paper.view.center.add(new paper.Point([0, 200])), + fillColor: 'black', + justification: 'center', + fontSize: 20 + }); + + let originals = new paper.Group({ insert: false }); // Don't insert in DOM. + + let square = new paper.Path.Rectangle({ + position: paper.view.center, + size: 300, + parent: originals, + fillColor: 'white' + }); + + // Make a ring using subtraction of two circles: + let inner = new paper.Path.Circle({ + center: paper.view.center, + radius: 100, + parent: originals, + fillColor: 'white' + }); + + let outer = new paper.Path.Circle({ + center: paper.view.center, + radius: 140, + parent: originals, + fillColor: 'white' + }); + + let ring = outer.subtract(inner); + + let operations = ['unite', 'intersect', 'subtract', 'exclude', 'divide']; + let colors = ['red', 'green', 'blue', 'black']; + let curIndex = -1; + let operation: string; + let result: paper.PathItem | null; + let activeItem: paper.PathItem | null; + + // Change the mode every 3 seconds: + setInterval(setMode, 3000); + + // Set the initial mode: + setMode(); + + function setMode() { + curIndex++; + if (curIndex == operations.length * 2) + curIndex = 0; + operation = operations[curIndex % operations.length]; + } + + function onMouseDown(event: paper.ToolEvent) { + let hitResult = originals.hitTest(event.point); + activeItem = hitResult && hitResult.item as paper.PathItem; + } + + function onMouseDrag(event: paper.ToolEvent) { + if (activeItem) + activeItem.position = event.point; + } + + function onMouseUp() { + activeItem = null; + square.position = paper.view.center; + } + + function onFrame(event: paper.IFrameEvent) { + if (activeItem != ring) { + // Move the ring around: + let offset = new paper.Point(140, 80).multiply(new paper.Point([Math.sin(event.count / 60), Math.sin(event.count / 40)])); + ring.position = paper.view.center.add(offset); + } + + // Remove the result of the last path operation: + if (result) + result.remove(); + + function performOperation(operation:string, primaryItem:paper.PathItem, secondaryItem:paper.PathItem){ + switch(operation){ + case 'unite': + return primaryItem.unite(secondaryItem); + case 'intersect': + return primaryItem.intersect(secondaryItem); + case 'subtract': + return primaryItem.subtract(secondaryItem); + case 'exclude': + return primaryItem.exclude(secondaryItem); + case 'divide': + return primaryItem.divide(secondaryItem); + default: + return null; + } + } + // Perform the path operation on the ring: + if (curIndex < operations.length) { + result = performOperation(operation, square, ring); + text.content = 'square.' + operation + '(ring)'; + } else { + result = performOperation(operation, square, ring); + text.content = 'ring.' + operation + '(square)'; + } + if(result){ + result.selected = true; + result.fillColor = colors[curIndex % colors.length]; + result.moveBelow(text); + } + + // If the result is a group, color each of its children differently: + if (result instanceof paper.Group) { + for (let i = 0; i < result.children.length; i++) { + result.children[i].fillColor = colors[i]; + } + } + }; + + function onResize() { + text.position = paper.view.center.add(new paper.Point([0, 200])); + square.position = paper.view.center; + } + } + + function CandyCrash(){ + // kynd.info 2014 + class Ball{ + radius: number; + point: paper.Point; + vector: paper.Point; + maxVec: number; + numSegment: number; + boundOffset: number[]; + boundOffsetBuff: number[]; + sidePoints: paper.Point[]; + path: paper.Path; + + constructor(r: number, p: paper.Point, v: paper.Point) { + this.radius = r; + this.point = p; + this.vector = v; + this.maxVec = 15; + this.numSegment = Math.floor(r / 3 + 2); + this.boundOffset = []; + this.boundOffsetBuff = []; + this.sidePoints = []; + this.path = new paper.Path({ + fillColor: { + hue: Math.random() * 360, + saturation: 1, + brightness: 1 + }, + blendMode: 'lighter' + }); + + for (let i = 0; i < this.numSegment; i ++) { + this.boundOffset.push(this.radius); + this.boundOffsetBuff.push(this.radius); + this.path.add(new paper.Point({})); + this.sidePoints.push(new paper.Point({ + angle: 360 / this.numSegment * i, + length: 1 + })); + } + } + iterate() { + this.checkBorders(); + if (this.vector.length > this.maxVec) + this.vector.length = this.maxVec; + this.point = this.point.add(this.vector); + this.updateShape(); + } + checkBorders() { + let size = paper.view.size; + if (this.point.x < -this.radius) + this.point.x = size.width + this.radius; + if (this.point.x > size.width + this.radius) + this.point.x = -this.radius; + if (this.point.y < -this.radius) + this.point.y = size.height + this.radius; + if (this.point.y > size.height + this.radius) + this.point.y = -this.radius; + } + updateShape() { + let segments = this.path.segments; + for (let i = 0; i < this.numSegment; i ++) + segments[i].point = this.getSidePoint(i); + + this.path.smooth(); + for (let i = 0; i < this.numSegment; i ++) { + if (this.boundOffset[i] < this.radius / 4) + this.boundOffset[i] = this.radius / 4; + let next = (i + 1) % this.numSegment; + let prev = (i > 0) ? i - 1 : this.numSegment - 1; + let offset = this.boundOffset[i]; + offset += (this.radius - offset) / 15; + offset += ((this.boundOffset[next] + this.boundOffset[prev]) / 2 - offset) / 3; + this.boundOffsetBuff[i] = this.boundOffset[i] = offset; + } + } + react(b:Ball) { + let dist = this.point.getDistance(b.point); + if (dist < this.radius + b.radius && dist != 0) { + let overlap = this.radius + b.radius - dist; + let direc = (this.point.subtract(b.point)).normalize(overlap * 0.015); + this.vector = this.vector.add(direc); + b.vector = b.vector.subtract(direc); + + this.calcBounds(b); + b.calcBounds(this); + this.updateBounds(); + b.updateBounds(); + } + } + getBoundOffset(p:paper.Point) { + let diff = this.point.subtract(p); + let angle = (diff.angle + 180) % 360; + return this.boundOffset[Math.floor(angle / 360 * this.boundOffset.length)]; + } + calcBounds(b:Ball) { + for (let i = 0; i < this.numSegment; i ++) { + let tp = this.getSidePoint(i); + let bLen = b.getBoundOffset(tp); + let td = tp.getDistance(b.point); + if (td < bLen) { + this.boundOffsetBuff[i] -= (bLen - td) / 2; + } + } + } + getSidePoint(index: number) { + return this.point.add(this.sidePoints[index].multiply(this.boundOffset[index])); + } + updateBounds() { + for (let i = 0; i < this.numSegment; i ++) + this.boundOffset[i] = this.boundOffsetBuff[i]; + } + } + //--------------------- main --------------------- + let balls: Ball[] = []; + let numBalls = 18; + for (let i = 0; i < numBalls; i++) { + let position = paper.Point.random().multiply(new paper.Point(paper.view.size)); + let vector = new paper.Point({ + angle: 360 * Math.random(), + length: Math.random() * 10 + }); + let radius = Math.random() * 60 + 60; + balls.push(new Ball(radius, position, vector)); + } + + function onFrame() { + for (let i = 0; i < balls.length - 1; i++) { + for (let j = i + 1; j < balls.length; j++) { + balls[i].react(balls[j]); + } + } + for (let i = 0, l = balls.length; i < l; i++) { + balls[i].iterate(); + } + } + } + function SatieLikedToDraw(){ + let leftPath = new paper.Path({ + strokeColor: 'red', + opacity: 0.5 + }); + + let rightPath = new paper.Path({ + strokeColor: 'green', + opacity: 0.5 + }); + + let amount = 8; + let step = paper.view.size.width / (amount + 1); + let flip = true; + + for (let i = 0; i <= amount; i++) { + leftPath.add(new paper.Point(i * step, 0)); + rightPath.add(new paper.Point(i * step, 0)); + } + + let group = new paper.Group({ + children: [leftPath, rightPath], + transformContent: false, + strokeWidth: 30, + strokeJoin: 'round', + strokeCap: 'butt', + pivot: leftPath.position, + position: paper.view.center + }); + + function onMouseDown() { + flip = !flip; + } + + function onKeyDown(event: paper.KeyEvent) { + if (event.key === 'space') + group.fullySelected = !group.fullySelected; + } + + let audio: any; + let source: AudioBufferSourceNode; + let analyserL: AnalyserNode; + let analyserR: AnalyserNode; + let freqByteData: Uint8Array; + + paper.view.onFrame = function() { + let step = paper.view.size.width / (amount + 1); + let scale = paper.view.size.height / 1.75; + analyserL.getByteFrequencyData(freqByteData); + let leftBands = getEqualizerBands(freqByteData); + analyserR.getByteFrequencyData(freqByteData); + let rightBands = getEqualizerBands(freqByteData); + for (let i = 1; i <= amount; i++) { + leftPath.segments[i].point = new paper.Point([i * step, -leftBands[i - 1] * scale]); + rightPath.segments[i].point = new paper.Point([i * step, -rightBands[i - 1] * scale * (flip ? -1 : 1)]); + } + leftPath.smooth(); + rightPath.smooth(); + group.pivot = new paper.Point([leftPath.position.x, 0]); + group.position = paper.view.center; + } + + // Pause animation until we have data + paper.view.pause(); + + let AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext; + if (AudioContext) { + audio = new AudioContext(); + source = audio.createBufferSource(); + // Create two separate analyzers for left and right channel. + analyserL = audio.createAnalyser(); + analyserL.smoothingTimeConstant = 0.25; + analyserL.fftSize = Math.pow(2, amount) * 2; + analyserR = audio.createAnalyser(); + analyserR.smoothingTimeConstant = analyserL.smoothingTimeConstant; + analyserR.fftSize = analyserL.fftSize; + // Create the buffer to receive the analyzed data. + freqByteData = new Uint8Array(analyserL.frequencyBinCount); + // Create a splitter to feed them both + let splitter = audio.createChannelSplitter(); + // Connect audio processing graph + source.connect(splitter); + splitter.connect(analyserL, 0, 0); + splitter.connect(analyserR, 1, 0); + // Connect source to output also so we can hear it + source.connect(audio.destination); + loadAudioBuffer('http://assets.paperjs.org/audio/gnossienne.mp3'); + } else { + // TODO: Print error message + alert('Audio not supported'); + } + + function loadAudioBuffer(url: string) { + // Load asynchronously + let request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + + request.onload = function() { + audio.decodeAudioData( + request.response, + function(buffer: AudioBuffer) { + source.buffer = buffer; + source.loop = true; + source.start(0); + paper.view.play(); + }, + + function() { + alert("Error loading MP3"); + } + ); + }; + request.send(); + } + + function getEqualizerBands(data:Uint8Array) { + let bands:number[] = []; + let amount = Math.sqrt(data.length) / 2; + for(let i = 0; i < amount; i++) { + let start = Math.pow(2, i) - 1; + let end = start * 2 + 1; + let sum = 0; + for (let j = start; j < end; j++) { + sum += data[j]; + } + let avg = sum / (255 * (end - start)); + bands[i] = Math.sqrt(avg / Math.sqrt(2)); + } + return bands; + } + } + function Chain(){ + // Adapted from the following Processing example: + // http://processing.org/learning/topics/follow3.html + + // The amount of points in the path: + let points = 25; + + // The distance between the points: + let length = 35; + + let path = new paper.Path({ + strokeColor: '#E4141B', + strokeWidth: 20, + strokeCap: 'round' + }); + + let start = paper.view.center.divide(new paper.Point([10, 1])); + for (let i = 0; i < points; i++) + path.add(start.add(new paper.Point(i * length, 0))); + + function onMouseMove(event: paper.ToolEvent) { + path.firstSegment.point = event.point; + for (let i = 0; i < points - 1; i++) { + let segment = path.segments[i]; + let nextSegment = segment.next; + let vector = segment.point.subtract(nextSegment.point); + vector.length = length; + nextSegment.point = segment.point.subtract(vector); + } + path.smooth({ type: 'continuous' }); + } + + function onMouseDown(event: paper.ToolEvent) { + path.fullySelected = true; + path.strokeColor = '#e08285'; + } + + function onMouseUp(event: paper.ToolEvent) { + path.fullySelected = false; + path.strokeColor = '#e4141b'; + } + } + function TadPoles(){ + // Adapted from Flocking Processing example by Daniel Schiffman: + // http://processing.org/learning/topics/flocking.html + + class Boid { + acceleration: paper.Point; + vector: paper.Point; + position: paper.Point; + radius: number; + maxSpeed: number; + maxForce: number; + amount: number; + count: number; + lastLoc: paper.Point; + path: paper.Path; + shortPath: paper.Path; + head: paper.Shape; + + constructor(position: paper.Point, maxSpeed: number, maxForce: number) { + let strength = Math.random() * 0.5; + this.acceleration = new paper.Point({}); + this.vector = paper.Point.random().multiply(2).subtract(1); + this.position = position.clone(); + this.radius = 30; + this.maxSpeed = maxSpeed + strength; + this.maxForce = maxForce + strength; + this.amount = strength * 10 + 10; + this.count = 0; + this.createItems(); + } + run(boids: Boid[]) { + this.lastLoc = this.position.clone(); + if (!groupTogether) { + this.flock(boids); + } else { + this.align(boids); + } + this.borders(); + this.update(); + this.calculateTail(); + this.moveHead(); + } + calculateTail() { + let segments = this.path.segments, + shortSegments = this.shortPath.segments; + let speed = this.vector.length; + let pieceLength = 5 + speed / 3; + let point = this.position; + segments[0].point = shortSegments[0].point = point; + // Chain goes the other way than the movement + let lastVector = this.vector.multiply(-1); + for (let i = 1; i < this.amount; i++) { + let vector = segments[i].point.subtract(point); + this.count += speed * 10; + let wave = Math.sin((this.count + i * 3) / 300); + let sway = lastVector.rotate(90).normalize(wave); + point = point.add(lastVector.normalize(pieceLength).add(sway)); + segments[i].point = point; + if (i < 3) + shortSegments[i].point = point; + lastVector = vector; + } + this.path.smooth(); + } + createItems() { + this.head = paper.Shape.Ellipse({ + center: [0, 0], + size: [13, 8], + fillColor: 'white' + }); + + this.path = new paper.Path({ + strokeColor: 'white', + strokeWidth: 2, + strokeCap: 'round' + }); + for (let i = 0; i < this.amount; i++) + this.path.add(new paper.Point({})); + + this.shortPath = new paper.Path({ + strokeColor: 'white', + strokeWidth: 4, + strokeCap: 'round' + }); + for (let i = 0; i < Math.min(3, this.amount); i++) + this.shortPath.add(new paper.Point({})); + } + moveHead() { + this.head.position = this.position; + this.head.rotation = this.vector.angle; + } + // We accumulate a new acceleration each time based on three rules + flock(boids:Boid[]) { + let separation = this.separate(boids).multiply(3); + let alignment = this.align(boids); + let cohesion = this.cohesion(boids); + this.acceleration = this.acceleration.add(separation).add(alignment).add(cohesion); + } + update() { + // Update velocity + this.vector = this.vector.add(this.acceleration); + // Limit speed (vector#limit?) + this.vector.length = Math.min(this.maxSpeed, this.vector.length); + this.position = this.position.add(this.vector); + // Reset acceleration to 0 each cycle + this.acceleration = new paper.Point({}); + } + seek(target:paper.Point) { + this.acceleration = this.acceleration.add(this.steer(target, false)); + } + arrive(target:paper.Point) { + this.acceleration = this.acceleration.add(this.steer(target, true)); + } + borders() { + let vector = new paper.Point({}); + let position = this.position; + let radius = this.radius; + let size = paper.view.size; + if (position.x < -radius) vector.x = size.width + radius; + if (position.y < -radius) vector.y = size.height + radius; + if (position.x > size.width + radius) vector.x = -size.width -radius; + if (position.y > size.height + radius) vector.y = -size.height -radius; + if (!vector.isZero()) { + this.position = this.position.add(vector); + let segments = this.path.segments; + for (let i = 0; i < this.amount; i++) { + segments[i].point = segments[i].point.add(vector); + } + } + } + // A method that calculates a steering vector towards a target + // Takes a second argument, if true, it slows down as it approaches + // the target + steer(target: paper.Point, slowdown:boolean) { + let steer:paper.Point; + let desired = target.subtract(this.position); + let distance = desired.length; + // Two options for desired vector magnitude + // (1 -- based on distance, 2 -- maxSpeed) + if (slowdown && distance < 100) { + // This damping is somewhat arbitrary: + desired.length = this.maxSpeed * (distance / 100); + } else { + desired.length = this.maxSpeed; + } + steer = desired.subtract(this.vector); + steer.length = Math.min(this.maxForce, steer.length); + return steer; + } + separate(boids:Boid[]) { + let desiredSeperation = 60; + let steer = new paper.Point({}); + let count = 0; + // For every boid in the system, check if it's too close + for (let i = 0, l = boids.length; i < l; i++) { + let other = boids[i]; + let vector = this.position.subtract(other.position); + let distance = vector.length; + if (distance > 0 && distance < desiredSeperation) { + // Calculate vector pointing away from neighbor + steer= steer.add(vector.normalize(1 / distance)); + count++; + } + } + // Average -- divide by how many + if (count > 0) + steer = steer.divide(count); + if (!steer.isZero()) { + // Implement Reynolds: Steering = Desired - Velocity + steer.length = this.maxSpeed; + steer = steer.subtract(this.vector); + steer.length = Math.min(steer.length, this.maxForce); + } + return steer; + } + // Alignment + // For every nearby boid in the system, calculate the average velocity + align(boids: Boid[]) { + let neighborDist = 25; + let steer = new paper.Point({}); + let count = 0; + for (let i = 0, l = boids.length; i < l; i++) { + let other = boids[i]; + let distance = this.position.getDistance(other.position); + if (distance > 0 && distance < neighborDist) { + steer = steer.add(other.vector); + count++; + } + } + + if (count > 0) + steer = steer.divide(count); + if (!steer.isZero()) { + // Implement Reynolds: Steering = Desired - Velocity + steer.length = this.maxSpeed; + steer = steer.subtract(this.vector); + steer.length = Math.min(steer.length, this.maxForce); + } + return steer; + } + // Cohesion + // For the average location (i.e. center) of all nearby boids, + // calculate steering vector towards that location + cohesion(boids:Boid[]) { + let neighborDist = 100; + let sum = new paper.Point({}); + let count = 0; + for (let i = 0, l = boids.length; i < l; i++) { + let other = boids[i]; + let distance = this.position.getDistance(other.position); + if (distance > 0 && distance < neighborDist) { + sum = sum.add(other.position); // Add location + count++; + } + } + if (count > 0) { + sum = sum.divide(count); + // Steer towards the location + return this.steer(sum, false); + } + return sum; + } + } + + let heartPath = new paper.Path('M514.69629,624.70313c-7.10205,-27.02441 -17.2373,-52.39453 -30.40576,-76.10059c-13.17383,-23.70703 -38.65137,-60.52246 -76.44434,-110.45801c-27.71631,-36.64355 -44.78174,-59.89355 -51.19189,-69.74414c-10.5376,-16.02979 -18.15527,-30.74951 -22.84717,-44.14893c-4.69727,-13.39893 -7.04297,-26.97021 -7.04297,-40.71289c0,-25.42432 8.47119,-46.72559 25.42383,-63.90381c16.94775,-17.17871 37.90527,-25.76758 62.87354,-25.76758c25.19287,0 47.06885,8.93262 65.62158,26.79834c13.96826,13.28662 25.30615,33.10059 34.01318,59.4375c7.55859,-25.88037 18.20898,-45.57666 31.95215,-59.09424c19.00879,-18.32178 40.99707,-27.48535 65.96484,-27.48535c24.7373,0 45.69531,8.53564 62.87305,25.5957c17.17871,17.06592 25.76855,37.39551 25.76855,60.98389c0,20.61377 -5.04102,42.08691 -15.11719,64.41895c-10.08203,22.33203 -29.54687,51.59521 -58.40723,87.78271c-37.56738,47.41211 -64.93457,86.35352 -82.11328,116.8125c-13.51758,24.0498 -23.82422,49.24902 -30.9209,75.58594z'); + + let boids:Boid[] = []; + let groupTogether = false; + + // Add the boids: + for (let i = 0; i < 30; i++) { + let position = paper.Point.random().multiply(new paper.Point(paper.view.size)); + boids.push(new Boid(position, 10, 0.05)); + } + + + function onFrame(event: paper.IFrameEvent) { + for (let i = 0, l = boids.length; i < l; i++) { + if (groupTogether) { + let length = ((i + event.count / 30) % l) / l * heartPath.length; + let point = heartPath.getPointAt(length); + if (point) + boids[i].arrive(point); + } + boids[i].run(boids); + } + } + + // Reposition the heart path whenever the window is resized: + function onResize(event:paper.Event) { + heartPath.fitBounds(paper.view.bounds); + heartPath.scale(0.8); + } + + function onMouseDown(event:paper.ToolEvent) { + groupTogether = !groupTogether; + } + + function onKeyDown(event:paper.KeyEvent) { + if (event.key == 'space') { + let layer = paper.project.activeLayer; + layer.selected = !layer.selected; + return false; + } + } + } + function NyanRainbow(){ + // A tribute to Nyan Cat http://www.youtube.com/watch?v=QH2-TGUlwu4 + let mediaElement: any; + let playing = false; + /*MediaElement('nyan', { + pluginPath: '/assets/mediaelement/', + success: function(me) { + mediaElement = me; + me.play(); + me.addEventListener('timeupdate', function(time: any) { + if (me.currentTime > 3.7) + playing = true; + }); + } + });*/ + + let mousePos = paper.view.center .add(new paper.Point([paper.view.bounds.width / 3, 100])); + let position = paper.view.center; + + function onFrame(event:paper.IFrameEvent) { + position = position.add((mousePos.subtract(position)).divide(10)); + let vector = (paper.view.center.subtract(position)).divide(10); + moveStars(vector.multiply(3)); + moveRainbow(vector, event); + } + + function onMouseMove(event:paper.ToolEvent) { + mousePos = event.point; + } + + function onKeyDown(event:paper.KeyEvent) { + if (event.key == 'space') + paper.project.activeLayer.selected = !paper.project.activeLayer.selected; + } + + let moveStars: (vector:paper.Point)=>void = moveStarsFunctionCreator(); + function moveStarsFunctionCreator(): (vector:paper.Point)=>void { + // The amount of symbol we want to place; + let count = 50; + + // Create a symbol, which we will use to place instances of later: + let path = new paper.Path.Circle({ + center: [0, 0], + radius: 5, + fillColor: 'white', + strokeColor: 'black' + }); + + let symbol = new paper.Symbol(path); + + // Place the instances of the symbol: + for (let i = 0; i < count; i++) { + // The center position is a random point in the paper.view: + let center = paper.Point.random().multiply(new paper.Point(paper.view.size)); + let placed = symbol.place(center); + placed.scale(i / count + 0.01); + placed.data = { + vector: new paper.Point({ + angle: Math.random() * 360, + length : (i / count) * Math.random() / 5 + }) + }; + } + + let vector = new paper.Point({ + angle: 45, + length: 0 + }); + + function keepInView(item:paper.Item) { + let position = item.position; + let viewBounds = paper.view.bounds; + if (position.isInside(viewBounds)) + return; + let itemBounds = item.bounds; + if (position.x > viewBounds.width + 5) { + position.x = -item.bounds.width; + } + + if (position.x < -itemBounds.width - 5) { + position.x = viewBounds.width; + } + + if (position.y > viewBounds.height + 5) { + position.y = -itemBounds.height; + } + + if (position.y < -itemBounds.height - 5) { + position.y = viewBounds.height + } + } + + return function(vector:paper.Point) { + // Run through the active layer's children list and change + // the position of the placed symbols: + let layer = paper.project.activeLayer; + for (let i = 0; i < count; i++) { + let item = layer.children[i]; + let size = item.bounds.size; + let length = vector.length / 10 * size.width / 10; + item.position += vector.normalize(length) + item.data.vector; + keepInView(item); + } + }; + }; + + let moveRainbow: (vector:paper.Point, event:paper.IFrameEvent)=>void = moveRainbowunctionCreator(); + function moveRainbowunctionCreator(): (vector:paper.Point, event: paper.IFrameEvent)=>void { + let paths:paper.Path[] = []; + let colors = ['red', 'orange', 'yellow', 'lime', 'blue', 'purple']; + for (let i = 0; i < colors.length; i++) { + let path = new paper.Path({ + fillColor: colors[i] + }); + paths.push(path); + } + + let count = 30; + let group = new paper.Group(paths); + let headGroup:paper.Group; + let eyePosition = new paper.Point({}); + let eyeFollow = (paper.Point.random().subtract(0.5)); + let blinkTime = 200; + function createHead(vector: paper.Point, count: number) { + let eyeVector = (eyePosition.subtract(eyeFollow)); + eyePosition = eyePosition.subtract(eyeVector.divide(4)); + if (eyeVector.length < 0.00001) + eyeFollow = (paper.Point.random().subtract(0.5)); + if (headGroup) + headGroup.remove(); + let top = paths[0].lastSegment.point; + let bottom = paths[paths.length - 1].firstSegment.point; + let radius = (bottom.subtract(top)).length / 2; + let circle = new paper.Path.Circle({ + center: top.add((bottom.subtract(top)).divide(2)), + radius: radius, + fillColor: 'black' + }); + circle.scale(vector.length / 100, 1); + circle.rotate(vector.angle); + + let innerCircle = circle.clone(); + innerCircle.scale(0.5); + innerCircle.fillColor = (count % blinkTime < 3) + || (count % (blinkTime + 5) < 3) ? 'black' : 'white'; + if (count % (blinkTime + 40) == 0) + blinkTime = Math.round(Math.random() * 40) + 200; + let eye = circle.clone(); + eye.position = eye.position.add(eyePosition.multiply(radius)); + eye.scale(0.15, innerCircle.position); + eye.fillColor = 'black'; + headGroup = new paper.Group([circle, innerCircle, eye]); + } + + return function(v:paper.Point, event:paper.IFrameEvent) { + let vector:paper.Point = (paper.view.center.subtract(position)).divide(10); + + if (vector.length < 5) + vector.length = 5; + count += vector.length / 100; + group.translate(vector); + let rotated = vector.rotate(90); + let middle = paths.length / 2; + for (let j = 0; j < paths.length; j++) { + let path = paths[j]; + let nyanSwing = playing ? Math.sin(event.count / 2) * vector.length : 1; + let unitLength = vector.length * (2 + Math.sin(event.count / 10)) / 2; + let length = (j - middle) * unitLength + nyanSwing; + let top = paper.view.center.add(rotated.normalize(length)); + let bottom = paper.view.center.add(rotated.normalize(length + unitLength)); + path.add(top); + path.insert(0, bottom); + if (path.segments.length > 200) { + let index = Math.round(path.segments.length / 2); + path.segments[index].remove(); + path.segments[index - 1].remove(); + } + path.smooth(); + } + createHead(vector, event.count); + if (mediaElement) + mediaElement.setVolume(vector.length / 200); + } + } + } + function RoundedRectangles(){ + let mousePoint = paper.view.center; + let amount = 25; + let colors = ['red', 'white', 'blue', 'white']; + + for (let i = 0; i < amount; i++) { + let rect = new paper.Rectangle(new paper.Point([0, 0]), new paper.Point([25, 25])); + rect.center = mousePoint; + let path = new paper.Path.Rectangle(rect, 6); + path.fillColor = colors[i % 4]; + let scale = (1 - i / amount) * 20; + path.scale(scale); + } + + function onMouseMove(event: paper.ToolEvent) { + mousePoint = event.point; + } + + let children = paper.project.activeLayer.children; + function onFrame(event: paper.IFrameEvent) { + for (let i = 0, l = children.length; i < l; i++) { + let item = children[i]; + let delta = (mousePoint.subtract(item.position)).divide(i + 5); + item.rotate(Math.sin((event.count + i) / 10) * 7); + if (delta.length > 0.1) + item.position = item.position.add(delta); + } + } + } + function RadialRainbows(){ + let point = paper.view.center; + + let colors:paper.Color[] = []; + let cycles = 4; + for (let i = 0, l = 60; i < l; i++) { + let brightness = 1 - (i / l) * 1.5; + let hue = i / l * cycles * 360; + let color = new paper.Color({ + hue: hue, + saturation: 1, + brightness: brightness + }); + colors.push(color); + } + + let radius = Math.max(paper.view.size.width, paper.view.size.height) * 0.75; + + let path = new paper.Path.Rectangle({ + rectangle: paper.view.bounds, + fillColor: { + origin: point, + destination: point.add(new paper.Point([radius, 0])), + gradient: { + stops: colors, + radial: true + } + } + }); + + let color = path.fillColor as paper.Color; + let gradient = color.gradient; + let mouseDown = false; + let mousePoint = paper.view.center; + + function onMouseDown(event: paper.ToolEvent) { + mouseDown = true; + mousePoint = event.point; + } + + function onMouseDrag(event: paper.ToolEvent) { + mousePoint = event.point; + } + + function onMouseUp(event: paper.ToolEvent) { + vector.length = 10; + mouseDown = false; + } + + let grow = false; + let vector = new paper.Point(150, 0); + + function onFrame() { + if(gradient){ + for (let i = 0, l = gradient.stops.length; i < l; i++) + gradient.stops[i].color.hue -= 20; + if (grow && vector.length > 300) { + grow = false; + } else if (!grow && vector.length < 75) { + grow = true; + } + if (mouseDown) { + point = point.add((mousePoint.subtract(point)).divide(10)); + } else { + vector.length += (grow ? 1 : -1); + vector.angle += 5; + } + color.highlight = mouseDown ? point : point.add(vector); + } + } + + function onResize(event: paper.Event) { + point = paper.view.center; + path.bounds = paper.view.bounds; + let color = path.fillColor as paper.Color; + color.origin = point; + let radius = Math.max(paper.view.size.width, paper.view.size.height) * 0.75; + color.destination = point.add(new paper.Point([radius, 0])); + } + } + function MetaBalls(){ + // Ported from original Metaball script by SATO Hiroyuki + // http://park12.wakwak.com/~shp/lc/et/en_aics_script.html + paper.project.currentStyle = { + fillColor: 'black' + }; + + let ballPositions = [[255, 129], [610, 73], [486, 363], + [117, 459], [484, 726], [843, 306], [789, 615], [1049, 82], + [1292, 428], [1117, 733], [1352, 86], [92, 798]]; + + let handle_len_rate = 2.4; + let circlePaths:paper.Path[] = []; + let radius = 50; + for (let i = 0, l = ballPositions.length; i < l; i++) { + let circlePath = new paper.Path.Circle({ + center: ballPositions[i], + radius: 50 + }); + circlePaths.push(circlePath); + } + + let largeCircle = new paper.Path.Circle({ + center: [676, 433], + radius: 100 + }); + circlePaths.push(largeCircle); + + function onMouseMove(event:paper.ToolEvent) { + largeCircle.position = event.point; + generateConnections(circlePaths); + } + + let connections = new paper.Group(); + function generateConnections(paths:paper.Path[]) { + // Remove the last connection paths: + connections.children = []; + + for (let i = 0, l = paths.length; i < l; i++) { + for (let j = i - 1; j >= 0; j--) { + let path = metaball(paths[i], paths[j], 0.5, handle_len_rate, 300); + if (path) { + connections.appendTop(path); + path.removeOnMove(); + } + } + } + } + + generateConnections(circlePaths); + + // --------------------------------------------- + function metaball(ball1:paper.Path, ball2:paper.Path, v:number, handle_len_rate:number, maxDistance:number) { + let center1 = ball1.position; + let center2 = ball2.position; + let radius1 = ball1.bounds.width / 2; + let radius2 = ball2.bounds.width / 2; + let pi2 = Math.PI / 2; + let d = center1.getDistance(center2); + let u1:number; + let u2:number; + + if (radius1 == 0 || radius2 == 0) + return; + + if (d > maxDistance || d <= Math.abs(radius1 - radius2)) { + return; + } else if (d < radius1 + radius2) { // case circles are overlapping + u1 = Math.acos((radius1 * radius1 + d * d - radius2 * radius2) / + (2 * radius1 * d)); + u2 = Math.acos((radius2 * radius2 + d * d - radius1 * radius1) / + (2 * radius2 * d)); + } else { + u1 = 0; + u2 = 0; + } + + let angle1 = (center2.subtract(center1)).angleInRadians; + let angle2 = Math.acos((radius1 - radius2) / d); + let angle1a = angle1 + u1 + (angle2 - u1) * v; + let angle1b = angle1 - u1 - (angle2 - u1) * v; + let angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v; + let angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v; + let p1a = center1.add(getVector(angle1a, radius1)); + let p1b = center1.add(getVector(angle1b, radius1)); + let p2a = center2.add(getVector(angle2a, radius2)); + let p2b = center2.add(getVector(angle2b, radius2)); + + // define handle length by the distance between + // both ends of the curve to draw + let totalRadius = (radius1 + radius2); + let d2 = Math.min(v * handle_len_rate, (p1a.subtract(p2a)).length / totalRadius); + + // case circles are overlapping: + d2 *= Math.min(1, d * 2 / (radius1 + radius2)); + + radius1 *= d2; + radius2 *= d2; + + let path = new paper.Path({ + segments: [p1a, p2a, p2b, p1b], + style: ball1.style, + closed: true + }); + let segments = path.segments; + segments[0].handleOut = getVector(angle1a - pi2, radius1); + segments[1].handleIn = getVector(angle2a + pi2, radius2); + segments[2].handleOut = getVector(angle2b - pi2, radius2); + segments[3].handleIn = getVector(angle1b + pi2, radius1); + return path; + } + + // ------------------------------------------------ + function getVector(radians:number, length:number) { + return new paper.Point({ + // Convert radians to degrees: + angle: radians * 180 / Math.PI, + length: length + }); + } + } + function Voronoi(){ + let voronoi:any = {}; + let sites = generateBeeHivePoints(paper.view.size.divide(200), true); + let bbox:any; + let diagram:any; + let oldSize = paper.view.size; + let spotColor = new paper.Color('red'); + let mousePos = paper.view.center; + let selected = false; + + onResize(); + + function onMouseDown(event: paper.ToolEvent) { + sites.push(event.point); + renderDiagram(); + } + + function onMouseMove(event: paper.ToolEvent) { + mousePos = event.point; + if (event.count == 0) + sites.push(event.point); + sites[sites.length - 1] = event.point; + renderDiagram(); + } + + function renderDiagram() { + paper.project.activeLayer.children = []; + let diagram = voronoi.compute(sites, bbox); + if (diagram) { + for (let i = 0, l = sites.length; i < l; i++) { + let cell = diagram.cells[(sites[i] as any).voronoiId]; + if (cell) { + let halfedges = cell.halfedges, + length = halfedges.length; + if (length > 2) { + let points:paper.Point[] = []; + for (let j = 0; j < length; j++) { + let v = halfedges[j].getEndpoint(); + points.push(new paper.Point(v)); + } + createPath(points, sites[i]); + } + } + } + } + } + + function removeSmallBits(path:paper.Path) { + let averageLength = path.length / path.segments.length; + let min = path.length / 50; + for(let i = path.segments.length - 1; i >= 0; i--) { + let segment = path.segments[i]; + let cur = segment.point; + let nextSegment = segment.next; + let next = nextSegment.point.add(nextSegment.handleIn); + if (cur.getDistance(next) < min) { + segment.remove(); + } + } + } + + function generateBeeHivePoints(size:paper.Size, loose: boolean) { + let points:paper.Point[] = []; + let col = paper.view.size.divide(size); + for(let i = -1; i < size.width + 1; i++) { + for(let j = -1; j < size.height + 1; j++) { + let point = new paper.Point(i, j).divide(new paper.Point(size)).multiply(new paper.Point(paper.view.size)).add(new paper.Point(col).divide(2)); + if(j % 2) + point = point.add(new paper.Point(col.width / 2, 0)); + if(loose) + point = point.add(new paper.Point(col).divide(4).multiply(paper.Point.random()).subtract(new paper.Point(col.divide(4)))); + points.push(point); + } + } + return points; + } + function createPath(points: paper.Point[], center: paper.Point) { + let path = new paper.Path(); + if (!selected) { + path.fillColor = spotColor; + } else { + path.fullySelected = selected; + } + path.closed = true; + + for (let i = 0, l = points.length; i < l; i++) { + let point = points[i]; + let next = points[(i + 1) == points.length ? 0 : i + 1]; + let vector = (next.subtract(point)).divide(2); + path.add(new paper.Point({ + point: point.add(vector), + handleIn: vector.multiply(-1), + handleOut: vector + })); + } + path.scale(0.95); + removeSmallBits(path); + return path; + } + + function onResize() { + let margin = 20; + bbox = { + xl: margin, + xr: paper.view.bounds.width - margin, + yt: margin, + yb: paper.view.bounds.height - margin + }; + for (let i = 0, l = sites.length; i < l; i++) { + sites[i] = sites[i].multiply(new paper.Point(paper.view.size.divide(oldSize))); + } + oldSize = paper.view.size; + renderDiagram(); + } + + function onKeyDown(event: paper.KeyEvent) { + if (event.key == 'space') { + selected = !selected; + renderDiagram(); + } + } + } + function FutureSplash(){ + // Code ported to Paper.js from http://the389.com/9/1/ + // with permission. + + let values = { + friction: 0.8, + timeStep: 0.01, + amount: 15, + mass: 2, + count: 0, + invMass: 1/2 + }; + values.invMass = 1 / values.mass; + + let path: paper.Path; + let springs: Spring[]; + let size = paper.view.size.multiply(new paper.Size([1.2, 1])); + + class SpringPoint extends paper.Point{ + fixed: boolean; + px: number; + py: number; + } + + class Spring { + a: SpringPoint; + b: SpringPoint; + restLength: number; + strength: number; + mamb: number; + + constructor(a:SpringPoint, b:SpringPoint, strength:number, restLength:number=0){ + this.a = a; + this.b = b; + this.restLength = restLength || 80; + this.strength = strength ? strength : 0.55; + this.mamb = values.invMass * values.invMass; + } + update() { + let delta = this.b.subtract(this.a); + let dist = delta.length; + let normDistStrength = (dist - this.restLength) / + (dist * this.mamb) * this.strength; + delta.y *= normDistStrength * values.invMass * 0.2; + if (!this.a.fixed) + this.a.y += delta.y; + if (!this.b.fixed) + this.b.y -= delta.y; + } + }; + + + function createPath(strength: number) { + let path = new paper.Path({ + fillColor: 'black' + }); + springs = []; + for (let i = 0; i <= values.amount; i++) { + let segment = path.add(new paper.Point(i / values.amount, 0.5).multiply(new paper.Point(size))); + let point = segment.point as SpringPoint; + if (i == 0 || i == values.amount) + point.y += size.height; + point.px = point.x; + point.py = point.y; + // The first two and last two points are fixed: + point.fixed = i < 2 || i > values.amount - 2; + if (i > 0) { + let spring = new Spring(segment.previous.point as SpringPoint, point, strength); + springs.push(spring); + } + } + path.position.x -= size.width / 4; + return path; + } + + function onResize() { + if (path) + path.remove(); + size = paper.view.bounds.size.multiply(new paper.Size([2, 1])); + path = createPath(0.1); + } + + function onMouseMove(event: paper.ToolEvent) { + let location = path.getNearestLocation(event.point); + let segment = location.segment; + let point = segment.point as SpringPoint; + + if (!point.fixed && location.distance < size.height / 4) { + let y = event.point.y; + point.y += (y - point.y) / 6; + if (segment.previous && !(segment.previous.point as SpringPoint).fixed) { + let previous = segment.previous.point; + previous.y += (y - previous.y) / 24; + } + if (segment.next && !(segment.next.point as SpringPoint).fixed) { + let next = segment.next.point; + next.y += (y - next.y) / 24; + } + } + } + + function onFrame(event:paper.IFrameEvent) { + updateWave(path); + } + + function updateWave(path:paper.Path) { + let force = 1 - values.friction * values.timeStep * values.timeStep; + for (let i = 0, l = path.segments.length; i < l; i++) { + let point = path.segments[i].point as SpringPoint; + let dy = (point.y - point.py) * force; + point.py = point.y; + point.y = Math.max(point.y + dy, 0); + } + + for (let j = 0, l = springs.length; j < l; j++) { + springs[j].update(); + } + path.smooth({ type: 'continuous' }); + } + + function onKeyDown(event:paper.KeyEvent) { + if (event.key == 'space') { + path.fullySelected = !path.fullySelected; + path.fillColor = path.fullySelected ? new paper.Color('') : 'black'; + } + } + } + function Smoothing(){ + let width: number; + let height: number; + let center: paper.Point; + let points = 10; + let smooth = true; + let path = new paper.Path(); + let mousePos = paper.view.center.divide(2); + let pathHeight = mousePos.y; + path.fillColor = 'black'; + initializePath(); + + function initializePath() { + center = paper.view.center; + width = paper.view.size.width; + height = paper.view.size.height / 2; + path.segments = []; + path.add(paper.view.bounds.bottomLeft); + for (let i = 1; i < points; i++) { + let point = new paper.Point(width / points * i, center.y); + path.add(point); + } + path.add(paper.view.bounds.bottomRight); + path.fullySelected = true; + } + + function onFrame(event:paper.IFrameEvent) { + pathHeight += (center.y - mousePos.y - pathHeight) / 10; + for (let i = 1; i < points; i++) { + let sinSeed = event.count + (i + i % 10) * 100; + let sinHeight = Math.sin(sinSeed / 200) * pathHeight; + let yPos = Math.sin(sinSeed / 100) * sinHeight + height; + path.segments[i].point.y = yPos; + } + if (smooth) + path.smooth({ type: 'continuous' }); + } + + function onMouseMove(event:paper.ToolEvent) { + mousePos = event.point; + } + + function onMouseDown(event:paper.ToolEvent) { + smooth = !smooth; + if (!smooth) { + // If smooth has been turned off, we need to reset + // the handles of the path: + for (let i = 0, l = path.segments.length; i < l; i++) { + let segment = path.segments[i]; + segment.clearHandles(); + } + } + } + + // Reposition the path whenever the window is resized: + function onResize(event:paper.Event) { + initializePath(); + } + } + function SpiralRaster(){ + // Please note: dragging and dropping images only works for + // certain browsers when serving this script online: + let path:paper.Path; + let position:paper.Point; + let max:number; + let count = 0; + let grow = false; + + // As the web is asynchronous, we need to wait for the raster to + // load before we can perform any operation on its pixels. + let raster = new paper.Raster('mona'); + raster.visible = false; + raster.on('load', resetSpiral); + + let text = new paper.PointText({ + justification: 'right', + fontSize: 12, + content: (window as any).FileReader + ? 'drag & drop an image from your desktop to rasterize it' + : 'to drag & drop images, please use Webkit, Firefox, Chrome or IE 10' + }); + + function onFrame(event:paper.IFrameEvent) { + if (grow) { + if (raster.loaded && (paper.view.center.subtract(position)).length < max) { + for (let i = 0, l = count / 36 + 1; i < l; i++) { + growSpiral(); + } + path.smooth(); + } else { + grow = false; + } + } + } + + function growSpiral() { + count++; + let vector = new paper.Point({ + angle: count * 5, + length: count / 100 + }); + let rot = vector.rotate(90); + let color = raster.getAverageColor(position.add(vector.divide(2))); + let value = color ? (1 - color.gray) * 3.7 : 0; + rot.length = Math.max(value, 0.2); + path.add(position.add(vector).subtract(rot)); + path.insert(0, position.add(vector).add(rot)); + position = position.add(vector); + } + + function resetSpiral() { + grow = true; + + // Transform the raster, so it fills the paper.view: + raster.fitBounds(paper.view.bounds); + + if (path) + path.remove(); + + position = paper.view.center; + count = 0; + path = new paper.Path({ + fillColor: 'black', + closed: true + }); + + position = paper.view.center; + max = Math.min(raster.bounds.width, raster.bounds.height) * 0.5; + } + + function onResize() { + if (raster.loaded) + resetSpiral(); + text.point = paper.view.bounds.bottomRight.subtract(new paper.Point([30, 30])); + } + + function onKeyDown(event:paper.KeyEvent) { + if (event.key == 'space') { + path.selected = !path.selected; + } + } + + function onDocumentDrag(event:Event) { + event.preventDefault(); + } + + function onDocumentDrop(event:Event) { + event.preventDefault(); + + let file = (event as any).dataTransfer.files[0]; + let reader = new FileReader(); + + reader.onload = function (event) { + let image = document.createElement('img'); + image.onload = function () { + raster = new paper.Raster(image); + raster.visible = false; + resetSpiral(); + }; + if(event.target) + image.src = (event.target as any).result; + }; + reader.readAsDataURL(file); + } + + document.addEventListener('drop', onDocumentDrop, false); + document.addEventListener('dragover', onDocumentDrag, false); + document.addEventListener('dragleave', onDocumentDrag, false); + } + function DivisionRaster(){ + // Based on 'JPEG Raster' by Jonathan Puckey: + // http://www.flickr.com/photos/puckey/3179779686/in/photostream/ + + // Create a raster item: + let raster = new paper.Raster('mona.jpg'); + let loaded = false; + + raster.on('load', function(event: paper.Event) { + loaded = true; + paper.view.onResize(event); + }); + + // Make the raster invisible: + raster.visible = false; + + let lastPos = paper.view.center; + function moveHandler(this: paper.Path, event:paper.MouseEvent) { + if (!loaded) + return; + if (lastPos.getDistance(event.point) < 10) + return; + lastPos = event.point; + + let size: paper.Size = this.bounds.size.clone(); + let isLandscape = size.width > size.height; + + // If the path is in landscape orientation, we're going to + // split the path horizontally, otherwise vertically: + + size= size.divide(new paper.Size(isLandscape ? [2, 1] : [1, 2])); + + let path = new paper.Path.Rectangle({ + point: this.bounds.topLeft.floor(), + size: size.ceil(), + onMouseMove: moveHandler + }); + path.fillColor = raster.getAverageColor(path); + + let path2 = new paper.Path.Rectangle({ + point: isLandscape + ? this.bounds.topCenter.ceil() + : this.bounds.leftCenter.ceil(), + size: size.floor(), + onMouseMove: moveHandler + }); + path2.fillColor = raster.getAverageColor(path2); + + this.remove(); + } + + function onResize(event:paper.Event) { + if (!loaded) + return; + paper.project.activeLayer.removeChildren(); + + // Transform the raster so that it fills the bounding rectangle + // of the paper.view: + raster.fitBounds(paper.view.bounds, true); + + // Create a path that fills the paper.view, and fill it with + // the average color of the raster: + new paper.Path.Rectangle({ + rectangle: paper.view.bounds, + fillColor: raster.getAverageColor(paper.view.bounds), + onMouseMove: moveHandler + }); + } + } + function Qbertify(){ + // Please note: dragging and dropping images only works for + // certain browsers when serving this script online: + + let values = { + amount: 30 + }; + + let raster: paper.Raster; + let group: paper.Group; + let piece = createPiece(); + let count = 0; + + handleImage('mona'); + + let text = new paper.PointText({ + point: paper.view.center, + justification: 'center', + fillColor: 'white', + fontSize: 15, + content: (window as any).FileReader + ? 'Drag & drop an image from your desktop' + : 'To drag & drop images, please use Webkit, Firefox, Chrome or IE 10' + }); + + function createPiece() { + let group = new paper.Group(); + let hexagon = new paper.Path.RegularPolygon({ + center: paper.view.center, + sides: 6, + radius: 50, + fillColor: 'gray', + parent: group + }); + for (let i = 0; i < 2; i++) { + let path = new paper.Path({ + closed: true, + parent: group, + fillColor: i == 0 ? 'white' : 'black' + }); + for (let j = 0; j < 3; j++) { + let index = (i * 2 + j) % hexagon.segments.length; + path.add(hexagon.segments[index].clone()); + } + path.add(hexagon.bounds.center); + } + // Remove the group from the document, so it is not drawn: + group.remove(); + return group; + } + + function handleImage(image:HTMLImageElement|string) { + count = 0; + let size = piece.bounds.size; + + if (group) + group.remove(); + + // As the web is asynchronous, we need to wait for the raster to + // load before we can perform any operation on its pixels. + raster = new paper.Raster(image); + raster.visible = false; + raster.on('load', function() { + // Transform the raster, so it fills the paper.view: + raster.fitBounds(paper.view.bounds, true); + group = new paper.Group(); + for (let y = 0; y < values.amount; y++) { + for (let x = 0; x < values.amount; x++) { + let copy = piece.clone(); + copy.position = copy.position.add(new paper.Point(size.multiply(new paper.Size([x + (y % 2 ? 0.5 : 0), y * 0.75])))); + group.addChild(copy); + } + } + + // Transform the group so it covers the paper.view: + group.fitBounds(paper.view.bounds, true); + group.scale(1.1); + }) + } + + function onFrame(event:paper.IFrameEvent) { + if (!group) + return; + // Loop through the uncolored hexagons in the group and fill them + // with the average color: + let length = Math.min(count + values.amount, group.children.length); + for (let i = count; i < length; i++) { + piece = group.children[i] as paper.Group; + let hexagon = piece.children[0] as paper.Path; + let color = raster.getAverageColor(hexagon); + if (color) { + hexagon.fillColor = color; + let top = piece.children[1]; + top.fillColor = color.clone(); + top.fillColor.brightness *= 1.5; + + let right = piece.children[2]; + right.fillColor = color.clone(); + right.fillColor.brightness *= 0.5; + } + } + count += values.amount; + } + + function onResize() { + paper.project.activeLayer.position = paper.view.center; + } + + function onDocumentDrag(event:Event) { + event.preventDefault(); + } + + function onDocumentDrop(event:Event) { + event.preventDefault(); + + let file = (event as any).dataTransfer.files[0]; + let reader = new FileReader(); + + reader.onload = function(event) { + let image = document.createElement('img'); + image.onload = function () { + handleImage(image); + paper.view.draw(); + }; + image.src = (event as any).target.result; + }; + reader.readAsDataURL(file); + } + + document.addEventListener('drop', onDocumentDrop, false); + document.addEventListener('dragover', onDocumentDrag, false); + document.addEventListener('dragleave', onDocumentDrag, false); + } + function PathIntersections(){ + // Imported SVG Groups have their applyMatrix flag turned off by + // default. This is required for SVG importing to work correctly. Turn + // it on now, so we don't have to deal with nested coordinate spaces. + let words = paper.project.importSVG((document.getElementById('svg') as any) as SVGElement); + words.visible = true; // Turn off the effect of display:none; + words.fillColor = new paper.Color(''); + words.strokeColor = 'black'; + let yesGroup = words.getItem({name:'yes'}) as paper.Group; + + let noGroup = words.getItem({name:'no'}) as paper.Group; + // Resize the words to fit snugly inside the paper.view: + words.fitBounds(paper.view.bounds); + words.scale(0.8); + + yesGroup.position = paper.view.center; + noGroup.position = new paper.Point([-900, -900]); + + function onMouseMove(event:paper.MouseEvent) { + noGroup.position = event.point; + for (let i = 0; i < yesGroup.children.length; i++) { + for (let j = 0; j < noGroup.children.length; j++) { + showIntersections(noGroup.children[j] as paper.PathItem, yesGroup.children[i] as paper.PathItem) + } + } + } +0 + function showIntersections(path1:paper.PathItem, path2:paper.PathItem) { + let intersections = path1.getIntersections(path2); + for (let i = 0; i < intersections.length; i++) { + new paper.Path.Circle({ + center: intersections[i].point, + radius: 5, + fillColor: '#009dec' + }).removeOnMove(); + } + } + } + function PathSimplification(){ + let path:paper.Path; + + let textItem = new paper.PointText({ + content: 'Click and drag to draw a line.', + point: new paper.Point(20, 30), + fillColor: 'black', + }); + + function onMouseDown(event:paper.ToolEvent) { + // If we produced a path before, deselect it: + if (path) { + path.selected = false; + } + + // Create a new path and set its stroke color to black: + path = new paper.Path({ + segments: [event.point], + strokeColor: 'black', + // Select the path, so we can see its segment points: + fullySelected: true + }); + } + + // While the user drags the mouse, points are added to the path + // at the position of the mouse: + function onMouseDrag(event:paper.ToolEvent) { + path.add(event.point); + + // Update the content of the text item to show how many + // segments it has: + textItem.content = 'Segment count: ' + path.segments.length; + } + + // When the mouse is released, we simplify the path: + function onMouseUp(event:paper.ToolEvent) { + let segmentCount = path.segments.length; + + // When the mouse is released, simplify it: + path.simplify(10); + + // Select the path, so we can see its segments: + path.fullySelected = true; + + let newSegmentCount = path.segments.length; + let difference = segmentCount - newSegmentCount; + let percentage = 100 - Math.round(newSegmentCount / segmentCount * 100); + textItem.content = difference + ' of the ' + segmentCount + ' segments were removed. Saving ' + percentage + '%'; + } + } + function HitTesting(){ + let values = { + paths: 50, + minPoints: 5, + maxPoints: 15, + minRadius: 30, + maxRadius: 90 + }; + + let hitOptions = { + segments: true, + stroke: true, + fill: true, + tolerance: 5 + }; + + createPaths(); + + function createPaths() { + let radiusDelta = values.maxRadius - values.minRadius; + let pointsDelta = values.maxPoints - values.minPoints; + for (let i = 0; i < values.paths; i++) { + let radius = values.minRadius + Math.random() * radiusDelta; + let points = values.minPoints + Math.floor(Math.random() * pointsDelta); + let path = createBlob(paper.Point.random().multiply(new paper.Point(paper.view.size)), radius, points); + let lightness = (Math.random() - 0.5) * 0.4 + 0.4; + let hue = Math.random() * 360; + path.fillColor = new paper.Color({ hue: hue, saturation: 1, lightness: lightness }); + path.strokeColor = 'black'; + }; + } + + function createBlob(center:paper.Point, maxRadius:number, points:number) { + let path = new paper.Path(); + path.closed = true; + for (let i = 0; i < points; i++) { + let delta = new paper.Point({ + length: (maxRadius * 0.5) + (Math.random() * maxRadius * 0.5), + angle: (360 / points) * i + }); + path.add(center.add(delta)); + } + path.smooth(); + return path; + } + + let segment:paper.Segment | null; + let path:paper.Path | null; + let movePath = false; + function onMouseDown(event:paper.ToolEvent) { + segment = path = null; + let hitResult = paper.project.hitTest(event.point, hitOptions); + if (!hitResult) + return; + + if (event.modifiers.shift) { + if (hitResult.type == 'segment') { + hitResult.segment.remove(); + }; + return; + } + + if (hitResult) { + path = hitResult.item as paper.Path; + if (hitResult.type == 'segment') { + segment = hitResult.segment; + } else if (hitResult.type == 'stroke') { + let location = hitResult.location; + segment = path.insert(location.index + 1, event.point); + path.smooth(); + } + } + movePath = hitResult.type == 'fill'; + if (movePath) + paper.project.activeLayer.addChild(hitResult.item); + } + + function onMouseMove(event:paper.ToolEvent) { + paper.project.activeLayer.selected = false; + if (event.item) + event.item.selected = true; + } + + function onMouseDrag(event:paper.ToolEvent) { + if (segment) { + segment.point= segment.point.add(event.delta); + if(path) + path.smooth(); + } else if (path) { + path.position = path.position.add(event.delta); + } + } + } + function BouncingBalls(){ + class Ball{ + point: paper.Point; + vector:paper.Point; + dampen:number; + gravity:number; + bounce:number; + radius: number; + item: paper.Item; + + constructor(point:paper.Point, vector:paper.Point) { + if (!vector || vector.isZero()) { + this.vector = paper.Point.random().multiply(5); + } else { + this.vector = vector.multiply(2);; + } + this.point = point; + this.dampen = 0.4; + this.gravity = 3; + this.bounce = -0.6; + + let color = new paper.Color({ + hue: Math.random() * 360, + saturation: 1, + brightness: 1 + }); + let gradient = new paper.Gradient([new paper.GradientStop(color), new paper.GradientStop(new paper.Color('black'))], true); + + let radius = this.radius = 50 * Math.random() + 30; + // Wrap CompoundPath in a Group, since CompoundPaths directly + // applies the transformations to the content, just like Path. + let ball = new paper.CompoundPath({ + children: [ + new paper.Path.Circle({ + radius: radius + }), + new paper.Path.Circle({ + center: radius / 8, + radius: radius / 3 + }) + ], + fillColor: new paper.Color(gradient, new paper.Point([0]), new paper.Point([radius]), new paper.Point([radius / 8])), + }); + + this.item = new paper.Group({ + children: [ball], + transformContent: false, + position: this.point + }); + } + iterate() { + let size = paper.view.size; + this.vector.y += this.gravity; + this.vector.x *= 0.99; + let pre = this.point.add(this.vector); + if (pre.x < this.radius || pre.x > size.width - this.radius) + this.vector.x *= -this.dampen; + if (pre.y < this.radius || pre.y > size.height - this.radius) { + if (Math.abs(this.vector.x) < 3) + this.vector = paper.Point.random().multiply(new paper.Point([150, 100]).add(new paper.Point([-75, 20]))); + this.vector.y *= this.bounce; + } + + let max = paper.Point.max(new paper.Point([this.radius]), this.point.add(this.vector)); + this.item.position = this.point = paper.Point.min(max, new paper.Point(size).subtract(this.radius)); + this.item.rotate(this.vector.x); + } + } + + let balls:Ball[] = []; + for (let i = 0; i < 10; i++) { + let position = paper.Point.random().multiply(new paper.Point(paper.view.size)); + let vector = (paper.Point.random().subtract(new paper.Point([0.5, 0])).multiply(new paper.Point([50, 100]))); + let ball = new Ball(position, vector); + balls.push(ball); + } + + let textItem = new paper.PointText({ + point: [20, 30], + fillColor: 'black', + content: 'Click, drag and release to add balls.' + }); + + let lastDelta:paper.Point|null; + function onMouseDrag(event:paper.ToolEvent) { + lastDelta = event.delta; + } + + function onMouseUp(event:paper.ToolEvent) { + if(lastDelta){ + let ball = new Ball(event.point, lastDelta); + balls.push(ball); + } + lastDelta = null; + } + + function onFrame() { + for (let i = 0, l = balls.length; i < l; i++) + balls[i].iterate(); + } + } +} + +function APIReferenceExamples() { + function Color0() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30. + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Pass a color name to the fillColor property, which is internally + // converted to a Color. + circle.fillColor = 'green'; + + } + function Color1() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30. + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Pass a hex string to the fillColor property, which is internally + // converted to a Color. + circle.fillColor = '#ff0000'; + + } + function Color2() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // 100% red, 0% blue, 50% blue: + circle.fillColor = new paper.Color(1, 0, 0.5); + + } + function Color3() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Create a GrayColor with 50% gray: + circle.fillColor = new paper.Color(0.5); + + } + function Color4() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Create an HSB Color with a hue of 90 degrees, a saturation + // 100% and a brightness of 100%: + circle.fillColor = new paper.Color({ hue: 90, saturation: 1, brightness: 1 }); + + } + function Color5() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Create an HSL Color with a hue of 90 degrees, a saturation + // 100% and a lightness of 50%: + circle.fillColor = new paper.Color({ hue: 90, saturation: 1, lightness: 0.5 }); + + } + function Color6() { + + // Define two points which we will be using to construct + // the path and to position the gradient color: + let topLeft = paper.view.center.subtract(new paper.Point([80, 80])); + let bottomRight = paper.view.center.add(new paper.Point([80, 80])); + + let path = new paper.Path.Rectangle({ + topLeft: topLeft, + bottomRight: bottomRight, + // Fill the path with a gradient of three color stops + // that runs between the two points we defined earlier: + fillColor: { + stops: ['yellow', 'red', 'blue'], + origin: topLeft, + destination: bottomRight + } + }); + + } + function Color7() { + + // Define two points which we will be using to construct + // the path and to position the gradient color: + let topLeft = paper.view.center.subtract(new paper.Point([80, 80])); + let bottomRight = paper.view.center.add(new paper.Point([80, 80])); + + // Create a rectangle shaped path between + // the topLeft and bottomRight points: + let path = new paper.Path.Rectangle(topLeft, bottomRight); + + // Create the gradient, passing it an array of colors to be converted + // to evenly distributed color stops: + let gradient = new paper.Gradient(['yellow','red','blue']); + + // Have the gradient color run between the topLeft and + // bottomRight points we defined earlier: + let gradientColor = new paper.Color(gradient, topLeft, bottomRight); + + // Set the fill color of the path to the gradient color: + path.fillColor = gradientColor; + + } + function Color8() { + + // Create a circle shaped path at the center of the paper.view + // with a radius of 80: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 80 + }); + + // The stops array: yellow mixes with red between 0 and 15%, + // 15% to 30% is pure red, red mixes with black between 30% to 100%: + let stops = [ + ['yellow', 0], + ['red', 0.15], + ['red', 0.3], + ['black', 0.9] + ]; + + // Create a radial gradient using the color stops array: + let gradient = new paper.Gradient(stops, true); + + // We will use the center point of the circle shaped path as + // the origin point for our gradient color + let from = path.position; + + // The destination point of the gradient color will be the + // center point of the path + 80pt in horizontal direction: + let to = path.position.add(new paper.Point([80, 0])); + + // Create the gradient color: + let gradientColor = new paper.Color(gradient, from, to); + + // Set the fill color of the path to the gradient color: + path.fillColor = gradientColor; + + } + function Color9() { + + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // Fill the circle with red and give it a 20pt green stroke: + circle.style = { + fillColor: 'red', + strokeColor: 'green', + strokeWidth: 20 + }; + + // Make the stroke half transparent: + (circle.strokeColor as paper.Color).alpha = 0.5; + + } + function Color10() { + + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + circle.fillColor = new paper.Color('blue'); + + // Blue + red = purple: + circle.fillColor.red = 1; + + } + function Color11() { + + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // First we set the fill color to red: + circle.fillColor = new paper.Color('red'); + + // Red + green = yellow: + circle.fillColor.green = 1; + + } + function Color12() { + + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + // First we set the fill color to red: + circle.fillColor = new paper.Color('red'); + + // Red + blue = purple: + circle.fillColor.blue = 1; + + } + function Color13() { + + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + circle.fillColor = new paper.Color('red'); + circle.fillColor.hue += 30; + + } + function Color14() { + + // Create a rectangle shaped path, using the dimensions + // of the paper.view: + let path = new paper.Path.Rectangle(paper.view.bounds); + path.fillColor = new paper.Color('red'); + + function onFrame(event:paper.IFrameEvent) { + (path.fillColor as paper.Color).hue += 0.5; + } + + } + function Color15() { + + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: paper.view.bounds.height * 0.4 + }); + + path.fillColor = new paper.Color({ + gradient: new paper.Gradient({ + stops: ['yellow', 'red', 'black'], + radial: true }), + origin: path.position, + destination: path.bounds.rightCenter + }); + + function onMouseMove(event:paper.ToolEvent) { + // Set the origin highlight of the path's gradient color + // to the position of the mouse: + (path.fillColor as paper.Color).highlight = event.point; + } + + } + function CompoundPath0() { + + let path = new paper.CompoundPath({ + children: [ + new paper.Path.Circle({ + center: new paper.Point(50, 50), + radius: 30 + }), + new paper.Path.Circle({ + center: new paper.Point(50, 50), + radius: 10 + }) + ], + fillColor: 'black', + selected: true + }); + + } + function CompoundPath1() { + + let pathData = 'M20,50c0,-16.56854 13.43146,-30 30,-30c16.56854,0 30,13.43146 30,30c0,16.56854 -13.43146,30 -30,30c-16.56854,0 -30,-13.43146 -30,-30z M50,60c5.52285,0 10,-4.47715 10,-10c0,-5.52285 -4.47715,-10 -10,-10c-5.52285,0 -10,4.47715 -10,10c0,5.52285 4.47715,10 10,10z'; + let path = new paper.CompoundPath(pathData); + path.fillColor = 'black'; + + } + function CompoundPath2() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function CompoundPath3() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function CompoundPath4() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function CompoundPath5() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function CompoundPath6() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function CompoundPath7() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function CompoundPath8() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function CompoundPath9() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function CompoundPath10() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function CompoundPath11() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function CompoundPath12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function CompoundPath13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function CompoundPath14() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function CompoundPath15() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function CompoundPath16() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function CompoundPath17() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function CompoundPath18() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function CompoundPath19() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function CompoundPath20() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function CompoundPath21() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function CompoundPath22() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function CompoundPath23() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function CompoundPath24() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function CompoundPath25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function CompoundPath26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function CompoundPath27() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function CompoundPath28() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function CompoundPath29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function CompoundPath30() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function CompoundPath31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function CompoundPath32() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function CompoundPath33() { + + function enter(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function CompoundPath34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function CompoundPath35() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function CompoundPath36() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function CompoundPath37() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function CompoundPath38() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function CompoundPath39() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function CompoundPath40() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function CompoundPath41() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function CompoundPath42() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function CompoundPath43() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function CompoundPath44() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function CompoundPath45() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function CompoundPath46() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function CompoundPath47() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function CompoundPath48() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Item, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Item, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + }); + + } + function CompoundPath49() { + + let pathHandlers = { + mouseenter: function(this:paper.Item, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Item, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function CompoundPath50() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function CompoundPath51() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function CompoundPath52() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function CompoundPath53() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function CompoundPath54() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function CompoundPath55() { + + let path = new paper.Path.Rectangle(new paper.Point(30, 25), new paper.Size(50, 50)); + path.strokeColor = 'black'; + + let secondPath = path.clone(); + let intersectionGroup = new paper.Group(); + + function onFrame(event:paper.IFrameEvent) { + secondPath.rotate(1); + + let intersections = path.getIntersections(secondPath); + intersectionGroup.removeChildren(); + + for (let i = 0; i < intersections.length; i++) { + let intersectionPath = new paper.Path.Circle({ + center: intersections[i].point, + radius: 4, + fillColor: 'red', + parent: intersectionGroup + }); + } + } + + } + function CompoundPath56() { + + let star = new paper.Path.Star({ + center: paper.view.center, + points: 10, + radius1: 30, + radius2: 60, + strokeColor: 'black' + }); + + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 3, + fillColor: 'red' + }); + + function onMouseMove(event:paper.ToolEvent) { + // Get the nearest point from the mouse position + // to the star shaped path: + let nearestPoint = star.getNearestPoint(event.point); + + // Move the red circle to the nearest point: + circle.position = nearestPoint; + } + + } + function CompoundPath57() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Select the path, so we can inspect its segments: + path.selected = true; + + // Create a copy of the path and move it by 150 points: + let copy = path.clone(); + copy.position.x += 150; + + // Flatten the copied path, with a maximum error of 4 points: + copy.flatten(4); + + } + function CompoundPath58() { + + // Create a rectangular path with its top-left point at + // {x: 30, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle({ + point: [30, 25], + size: [50, 50], + strokeColor: 'black', + }); + + // Select the path, so we can see its handles: + path.fullySelected = true; + + // Create a copy of the path and move it 100 to the right: + let copy = path.clone(); + copy.position.x += 100; + + // Smooth the segments of the copy: + copy.smooth({ type: 'continuous' }); + + } + function CompoundPath59() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 50)); + + let y = 5; + let x = 3; + + for (let i = 0; i < 28; i++) { + y *= -1.1; + x *= 1.1; + path.lineBy(new paper.Point(x, y)); + } + + // Create a copy of the path and move it 100 down: + let copy = path.clone(); + copy.position.y += 120; + + // Select the path, so we can see its handles: + copy.fullySelected = true; + + // Smooth the path using centripetal Catmull-Rom splines: + copy.smooth({ type: 'catmull-rom', factor: 0.5 }); + + } + function CompoundPath60() { + + // Create 5 rectangles, next to each other: + let paths:paper.Path[] = []; + for (let i = 0; i < 5; i++) { + paths.push(new paper.Path.Rectangle({ + point: [30 + i * 100, 30], + size: [50, 50], + fullySelected: true + })); + } + // Smooth a range, using segments: + paths[1].smooth({ + type: 'continuous', + from: paths[1].segments[0], + to: paths[1].segments[2] + }); + + // Smooth a range, using curves: + paths[2].smooth({ + type: 'continuous', + from: paths[2].curves[0], + to: paths[2].curves[1] + }); + + // Smooth a range, using indices: + paths[3].smooth({ type: 'continuous', from: 0, to: 2 }); + + // Smooth a range, using negative indices: + paths[4].smooth({ type: 'continuous', from: -1, to: 1 }); + + } + function CompoundPath61() { + + let path: paper.Path | null; + function onMouseDown(event:paper.ToolEvent) { + // If we already made a path before, deselect it: + if (path) { + path.selected = false; + } + + // Create a new path and add the position of the mouse + // as its first segment. Select it, so we can see the + // segment points: + path = new paper.Path({ + segments: [event.point], + strokeColor: 'black', + selected: true + }); + } + + function onMouseDrag(event:paper.ToolEvent) { + // On every drag event, add a segment to the path + // at the position of the mouse: + if(path){ + path.add(event.point); + } + } + + function onMouseUp(event:paper.ToolEvent) { + // When the mouse is released, simplify the path: + if(path){ + path.simplify(); + path.selected = true; + } + } + + } + function CompoundPath62() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + let firstPoint = new paper.Point(30, 75); + path.add(firstPoint); + + // The point through which we will create the arc: + let throughPoint = new paper.Point(40, 40); + + // The point at which the arc will end: + let toPoint = new paper.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': + let circle = new paper.Path.Circle(throughPoint, 3); + circle.fillColor = 'red'; + + } + function CompoundPath63() { + + let myPath: paper.Path | null; + function onMouseDrag(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw an arc through the position of the mouse to 'toPoint' + let toPoint = new paper.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:paper.ToolEvent) { + if(myPath){ + myPath.selected = false; + myPath.fillColor = 'black'; + } + } + + } + function CompoundPath64() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 75)); + path.arcTo(new paper.Point(130, 75)); + + let path2 = new paper.Path(); + path2.strokeColor = 'red'; + path2.add(new paper.Point(180, 25)); + + // To draw an arc in anticlockwise direction, + // we pass `false` as the second argument to arcTo: + path2.arcTo(new paper.Point(280, 25), false); + + } + function CompoundPath65() { + + let myPath:paper.Path; + + // The mouse has to move at least 20 points before + // the next mouse drag event is fired: + paper.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:paper.ToolEvent) { + myPath = new paper.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:paper.ToolEvent) { + myPath.arcTo(event.point); + } + + } + function CompoundPath66() { + + let myPath: paper.Path | null; + function onMouseMove(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw a curve through the position of the mouse to 'toPoint' + let toPoint = new paper.Point(350, 150); + myPath.curveTo(event.point, toPoint); + + // Select the path, so we can see its segments: + myPath.selected = true; + } + + } + function CompoundPath67() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add a segment at {x: 50, y: 50} + path.add(new paper.Point(25, 25)); + + // Add a segment relative to the last segment of the path. + // 50 in x direction and 0 in y direction, becomes {x: 75, y: 25} + path.lineBy(new paper.Point(50, 0)); + + // 0 in x direction and 50 in y direction, becomes {x: 75, y: 75} + path.lineBy(new paper.Point(0, 50)); + + } + function CompoundPath68() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add the first segment at {x: 50, y: 50} + path.add(paper.view.center); + + // Loop 500 times: + for (let i = 0; i < 500; i++) { + // Create a vector with an ever increasing length + // and an angle in increments of 45 degrees + let vector = new paper.Point({ + angle: i * 45, + length: i / 2 + }); + // Add the vector relatively to the last segment point: + path.lineBy(vector); + } + + // Smooth the handles of the path: + path.smooth(); + + // Uncomment the following line and click on 'run' to see + // the construction of the path: + // path.selected = true; + + } + function Gradient0() { + + // Define two points which we will be using to construct + // the path and to position the gradient color: + let topLeft = paper.view.center.subtract(new paper.Point([80, 80])); + let bottomRight = paper.view.center.add(new paper.Point([80, 80])); + + // Create a rectangle shaped path between + // the topLeft and bottomRight points: + let path = new paper.Path.Rectangle({ + topLeft: topLeft, + bottomRight: bottomRight, + // Fill the path with a gradient of three color stops + // that runs between the two points we defined earlier: + fillColor: { + gradient: { + stops: ['yellow', 'red', 'blue'] + }, + origin: topLeft, + destination: bottomRight + } + }); + + } + function Gradient1() { + + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: paper.view.bounds.height * 0.4 + }); + + // Fill the path with a radial gradient color with three stops: + // yellow from 0% to 5%, mix between red from 5% to 20%, + // mix between red and black from 20% to 100%: + path.fillColor = new paper.Color({ + gradient: new paper.Gradient({ + stops: [['yellow', 0.05], ['red', 0.2], ['black', 1]], + radial: true + }), + origin: path.position, + destination: path.bounds.rightCenter + }); + + } + function GradientStop0() { + + // Create a circle shaped path at the center of the paper.view, + // using 40% of the height of the paper.view as its radius + // and fill it with a radial gradient color: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: paper.view.bounds.height * 0.4 + }); + + path.fillColor = new paper.Color({ + gradient: new paper.Gradient({ + stops: [['yellow', 0.05], ['red', 0.2], ['black', 1]], + radial: true + }), + origin: path.position, + destination: path.bounds.rightCenter + }); + + let gradient = path.fillColor.gradient; + + // This function is called each frame of the animation: + function onFrame(event:paper.IFrameEvent) { + if(gradient){ + let blackStop = gradient.stops[2]; + // Animate the offset between 0.7 and 0.9: + blackStop.offset = Math.sin(event.time * 5) * 0.1 + 0.8; + + // Animate the offset between 0.2 and 0.4 + let redStop = gradient.stops[1]; + redStop.offset = Math.sin(event.time * 3) * 0.1 + 0.3; + } + } + + } + function GradientStop1() { + + // Create a circle shaped path at the center of the paper.view, + // using 40% of the height of the paper.view as its radius + // and fill it with a radial gradient color: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: paper.view.bounds.height * 0.4 + }); + + path.fillColor = new paper.Color({ + gradient: new paper.Gradient({ + stops: [['yellow', 0.05], ['red', 0.2], ['black', 1]], + radial: true + }), + origin: path.position, + destination: path.bounds.rightCenter + }); + + let redStop:paper.GradientStop; + let blackStop:paper.GradientStop; + if(path.fillColor.gradient){ + redStop = path.fillColor.gradient.stops[1]; + blackStop = path.fillColor.gradient.stops[2]; + } + + // This function is called each frame of the animation: + function onFrame(event:paper.IFrameEvent) { + // Animate the offset between 0.7 and 0.9: + blackStop.offset = Math.sin(event.time * 5) * 0.1 + 0.8; + + // Animate the offset between 0.2 and 0.4 + redStop.offset = Math.sin(event.time * 3) * 0.1 + 0.3; + } + + } + function Group0() { + + let path = new paper.Path([new paper.Point([100, 100]), new paper.Point([100, 200])]); + let path2 = new paper.Path([new paper.Point([50, 150]), new paper.Point([150, 150])]); + + // Create a group from the two paths: + let group = new paper.Group([path, path2]); + + // Set the stroke color of all items in the group: + group.strokeColor = 'black'; + + // Move the group to the center of the paper.view: + group.position = paper.view.center; + + } + function Group1() { + + let group = new paper.Group(); + + function onMouseDown(event:paper.ToolEvent) { + // Create a new circle shaped path at the position + // of the mouse: + let path = new paper.Path.Circle(event.point, 5); + path.fillColor = 'black'; + + // Add the path to the group's children list: + group.addChild(path); + } + + function onFrame(event:paper.IFrameEvent) { + // Rotate the group by 1 degree from + // the centerpoint of the paper.view: + group.rotate(1, paper.view.center); + } + + } + function Group2() { + + let path = new paper.Path([new paper.Point([100, 100]), new paper.Point([100, 200])]); + let path2 = new paper.Path([new paper.Point([50, 150]), new paper.Point([150, 150])]); + + // Create a group from the two paths: + let group = new paper.Group({ + children: [path, path2], + // Set the stroke color of all items in the group: + strokeColor: 'black', + // Move the group to the center of the paper.view: + position: paper.view.center + }); + + } + function Group3() { + + let star = new paper.Path.Star({ + center: paper.view.center, + points: 6, + radius1: 20, + radius2: 40, + fillColor: 'red' + }); + + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + strokeColor: 'black' + }); + + // Create a group of the two items and clip it: + let group = new paper.Group([circle, star]); + group.clipped = true; + + // Lets animate the circle: + function onFrame(event:paper.IFrameEvent) { + let offset = Math.sin(event.count / 30) * 30; + circle.position.x = paper.view.center.x + offset; + } + + } + function Group4() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Group5() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Group6() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Group7() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Group8() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Group9() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Group10() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Group11() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Group12() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Group13() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Group14() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Group15() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Group16() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Group17() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Group18() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Group19() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Group20() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Group21() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Group22() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Group23() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Group24() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Group25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Group26() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Group27() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Group28() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Group29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Group30() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Group31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Group32() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Group33() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Group34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Group35() { + + function enter(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Group36() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Group37() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Group38() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Group39() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Group40() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Group41() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Group42() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Group43() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Group44() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Group45() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Group46() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Group47() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Group48() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Group49() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Group50() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + }); + + } + function Group51() { + + let pathHandlers = { + mouseenter: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Group52() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Group53() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Group54() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Group55() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Group56() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Item0() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Item1() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Item2() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Item3() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Item4() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Item5() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Item6() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Item7() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Item8() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Item9() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Item10() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Item11() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Item12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Item13() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Item14() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Item15() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Item16() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Item17() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Item18() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Item19() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Item20() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Item21() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Item22() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Item23() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Item24() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Item25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Item26() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Item27() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Item28() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Item29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Item30() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Item31() { + + function enter(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Item32() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Item33() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Item34() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Item35() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Item36() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Item37() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Item38() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Item39() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Item40() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Item41() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Item42() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Item43() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Item44() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Item45() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Item46() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function Item47() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Item48() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Item49() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Item50() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Item51() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Item52() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Layer0() { + + let path = new paper.Path([[100, 100], [100, 200]]); + let path2 = new paper.Path([[50, 150], [150, 150]]); + + // Create a layer. The properties in the object literal + // are set on the newly created layer. + let layer = new paper.Layer({ + children: [path, path2], + strokeColor: 'black', + position: paper.view.center + }); + + } + function Layer1() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Layer2() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Layer3() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Layer4() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Layer5() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Layer6() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Layer7() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Layer8() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Layer9() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Layer10() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Layer11() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Layer12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Layer13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Layer14() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Layer15() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Layer16() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Layer17() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Layer18() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Layer19() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Layer20() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Layer21() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Layer22() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Layer23() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Layer24() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Layer25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Layer26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Layer27() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Layer28() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Layer29() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Layer30() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Layer31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Layer32() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Layer33() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Layer34() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Layer35() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Layer36() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Layer37() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Layer38() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Layer39() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Layer40() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Layer41() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Layer42() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Layer43() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Layer44() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Layer45() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Layer46() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Layer47() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + }); + + } + function Layer48() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Layer49() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Layer50() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Layer51() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Layer52() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Layer53() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Layer54() { + + let star = new paper.Path.Star({ + center: paper.view.center, + points: 6, + radius1: 20, + radius2: 40, + fillColor: 'red' + }); + + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + strokeColor: 'black' + }); + + // Create a group of the two items and clip it: + let group = new paper.Group([circle, star]); + group.clipped = true; + + // Lets animate the circle: + function onFrame(event:paper.IFrameEvent) { + let offset = Math.sin(event.count / 30) * 30; + circle.position.x = paper.view.center.x + offset; + } + + } + function Path0() { + + let path = new paper.Path({ + segments: [[20, 20], [80, 80], [140, 20]], + fillColor: 'black', + closed: true + }); + + } + function Path1() { + + let path = new paper.Path({ + segments: [[20, 20], [80, 80], [140, 20]], + strokeColor: 'red', + strokeWidth: 20, + strokeCap: 'round', + selected: true + }); + + } + function Path2() { + + let pathData = 'M100,50c0,27.614-22.386,50-50,50S0,77.614,0,50S22.386,0,50,0S100,22.386,100,50'; + let path = new paper.Path(pathData); + path.fillColor = 'red'; + + } + function Path3() { + + let from = new paper.Point(20, 20); + let to = new paper.Point(80, 80); + let path = new paper.Path.Line(from, to); + path.strokeColor = 'black'; + + } + function Path4() { + + let path = new paper.Path.Line({ + from: [20, 20], + to: [80, 80], + strokeColor: 'black' + }); + + } + function Path5() { + + let path = new paper.Path.Circle(new paper.Point(80, 50), 30); + path.strokeColor = 'black'; + + } + function Path6() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + strokeColor: 'black' + }); + + } + function Path7() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(60, 60)); + let path = new paper.Path.Rectangle(rectangle); + path.strokeColor = 'black'; + + } + function Path8() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(60, 60)); + let cornerSize = new paper.Size(10, 10); + let path = new paper.Path.Rectangle(rectangle, cornerSize.height); + path.strokeColor = 'black'; + + } + function Path9() { + + let point = new paper.Point(20, 20); + let size = new paper.Size(60, 60); + let path = new paper.Path.Rectangle(point, size); + path.strokeColor = 'black'; + + } + function Path10() { + + let from = new paper.Point(20, 20); + let to = new paper.Point(80, 80); + let path = new paper.Path.Rectangle(from, to); + path.strokeColor = 'black'; + + } + function Path11() { + + let path = new paper.Path.Rectangle({ + point: [20, 20], + size: [60, 60], + strokeColor: 'black' + }); + + } + function Path12() { + + let path = new paper.Path.Rectangle({ + from: [20, 20], + to: [80, 80], + strokeColor: 'black' + }); + + } + function Path13() { + + let path = new paper.Path.Rectangle({ + rectangle: { + topLeft: [20, 20], + bottomRight: [80, 80] + }, + strokeColor: 'black' + }); + + } + function Path14() { + + let path = new paper.Path.Rectangle({ + topLeft: [20, 20], + bottomRight: [80, 80], + radius: 10, + strokeColor: 'black' + }); + + } + function Path15() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(180, 60)); + let path = new paper.Path.Ellipse(rectangle); + path.fillColor = 'black'; + + } + function Path16() { + + let path = new paper.Path.Ellipse({ + point: [20, 20], + size: [180, 60], + fillColor: 'black' + }); + + } + function Path17() { + + let shape = new paper.Path.Ellipse({ + center: [110, 50], + radius: [90, 30], + fillColor: 'black' + }); + + } + function Path18() { + + let from = new paper.Point(20, 20); + let through = new paper.Point(60, 20); + let to = new paper.Point(80, 80); + let path = new paper.Path.Arc(from, through, to); + path.strokeColor = 'black'; + + } + function Path19() { + + let path = new paper.Path.Arc({ + from: [20, 20], + through: [60, 20], + to: [80, 80], + strokeColor: 'black' + }); + + } + function Path20() { + + let center = new paper.Point(50, 50); + let sides = 3; + let radius = 40; + let triangle = new paper.Path.RegularPolygon(center, sides, radius); + triangle.fillColor = 'black'; + + } + function Path21() { + + let triangle = new paper.Path.RegularPolygon({ + center: [50, 50], + sides: 10, + radius: 40, + fillColor: 'black' + }); + + } + function Path22() { + + let center = new paper.Point(50, 50); + let points = 12; + let radius1 = 25; + let radius2 = 40; + let path = new paper.Path.Star(center, points, radius1, radius2); + path.fillColor = 'black'; + + } + function Path23() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 25, + radius2: 40, + fillColor: 'black' + }); + + } + function Path24() { + + let myPath = new paper.Path(); + myPath.strokeColor = 'black'; + myPath.add(new paper.Point(50, 75)); + myPath.add(new paper.Point(100, 25)); + myPath.add(new paper.Point(150, 75)); + + // Close the path: + myPath.closed = true; + + } + function Path25() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.fullySelected = true; + + let path2 = new paper.Path.Circle({ + center: [180, 50], + radius: 35 + }); + + // 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'; + } + + } + function Path26() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + + // Add a segment at {x: 30, y: 75} + path.add(new paper.Point(30, 75)); + + // Add two segments in one go at {x: 100, y: 20} + // and {x: 170, y: 75}: + path.addSegments([new paper.Point(100, 20), new paper.Point(170, 75)]); + + } + function Path27() { + + let path = new paper.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.addSegments([[100, 20], [170, 75]]); + + } + function Path28() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + + // Add a segment at {x: 30, y: 75} + path.add(new paper.Point({x: 30, y: 75})); + + // Add two segments in one go at {x: 100, y: 20} + // and {x: 170, y: 75}: + path.addSegments([new paper.Point({x: 100, y: 20}), new paper.Point({x: 170, y: 75})]); + + } + function Path29() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(30, 75)); + + // Add a segment with handles: + let point = new paper.Point(100, 20); + let handleIn = new paper.Point(-50, 0); + let handleOut = new paper.Point(50, 0); + let added = path.add(new paper.Segment(point, handleIn, handleOut)); + + // Select the added segment, so we can see its handles: + added.selected = true; + + path.add(new paper.Point(170, 75)); + + } + function Path30() { + + let myPath = new paper.Path(); + myPath.strokeColor = 'black'; + myPath.add(new paper.Point(50, 75)); + myPath.add(new paper.Point(150, 75)); + + // Insert a new segment into myPath at index 1: + myPath.insert(1, new paper.Point(100, 25)); + + // Select the segment which we just inserted: + myPath.segments[1].selected = true; + + } + function Path31() { + + let myPath = new paper.Path(); + myPath.strokeColor = 'black'; + myPath.add(new paper.Point(50, 75)); + myPath.add(new paper.Point(150, 75)); + + // Insert two segments into myPath at index 1: + myPath.insertSegments(1, [[80, 25], [120, 25]]); + + // Select the segments which we just inserted: + myPath.segments[1].selected = true; + myPath.segments[2].selected = true; + + } + function Path32() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + let points = [new paper.Point(30, 50), new paper.Point(170, 50)]; + path.addSegments(points); + + } + function Path33() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + let array = [[30, 75], [100, 20], [170, 75]]; + path.addSegments(array); + + } + function Path34() { + + let path = new paper.Path({ + strokeColor: 'black' + }); + path.addSegments([[30, 75], [100, 20], [170, 75]]); + + let path2 = new paper.Path(); + path2.strokeColor = 'red'; + + // Add the second and third segments of path to path2: + path2.addSegments([path.segments[1], path.segments[2]]); + + // Move path2 30pt to the right: + path2.position.x += 30; + + } + function Path35() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let path = new paper.Path.Circle({ + center: new paper.Point(80, 50), + radius: 35, + strokeColor: 'black' + }); + + // Remove its second segment: + path.removeSegment(1); + + // Select the path, so we can see its segments: + path.selected = true; + + } + function Path36() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let path = new paper.Path.Circle({ + center: new paper.Point(80, 50), + radius: 35, + 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; + + } + function Path37() { + + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 40, + strokeColor: 'black' + }); + + let pointOnCircle = paper.view.center.add(new paper.Point({ + length: 40, + angle: 30 + })); + + let location = path.getNearestLocation(pointOnCircle); + + path.split(location); + path.lastSegment.selected = true; + + } + function Path38() { + + let path = new paper.Path([[20, 20], [50, 80], [80, 20]]); + path.strokeColor = 'black'; + + // Split the path half-way: + let path2 = path.split(path.length / 2); + + // Give the resulting path a red stroke-color + // and move it 20px to the right: + path2.strokeColor = 'red'; + path2.position.x += 20; + + } + function Path39() { + + let path = new paper.Path.Rectangle({ + from: [20, 20], + to: [80, 80], + strokeColor: 'black' + }); + + // Split the path half-way: + path.split(path.length / 2); + + // Move the first segment, to show where the path + // was split: + path.firstSegment.point.x += 20; + + // Select the first segment: + path.firstSegment.selected = true; + + } + function Path40() { + + let path = new paper.Path({ + segments: [[30, 25], [30, 75]], + strokeColor: 'black' + }); + + let path2 = new paper.Path({ + segments: [[200, 25], [200, 75]], + strokeColor: 'black' + }); + + // Join the paths: + path.join(path2); + + } + function Path41() { + + let path = new paper.Path({ + segments: [[30, 25], [30, 75]], + strokeColor: 'black' + }); + + let path2 = new paper.Path({ + segments: [[30, 25], [80, 25]], + 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; + + } + function Path42() { + + let path = new paper.Path({ + segments: [[30, 25], [80, 25], [80, 75]], + strokeColor: 'black' + }); + + let path2 = new paper.Path({ + segments: [[30, 25], [30, 75], [80, 75]], + 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; + + } + function Path43() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + // We're going to be working with a third of the length + // of the path as the offset: + let offset = path.length / 3; + + // Find the point on the path: + let point = path.getPointAt(offset); + + // Create a small circle shaped path at the point: + let circle = new paper.Path.Circle({ + center: point, + radius: 3, + fillColor: 'red' + }); + + } + function Path44() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + let amount = 5; + let length = path.length; + for (let i = 0; i < amount + 1; i++) { + let offset = i / amount * length; + + // Find the point on the path at the given offset: + let point = path.getPointAt(offset); + + // Create a small circle shaped path at the point: + let circle = new paper.Path.Circle({ + center: point, + radius: 3, + fillColor: 'red' + }); + } + + } + function Path45() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + // We're going to be working with a third of the length + // of the path as the offset: + let offset = path.length / 3; + + // Find the point on the path: + let point = path.getPointAt(offset); + + // Find the tangent vector at the given offset + // and give it a length of 60: + let tangent = path.getTangentAt(offset).multiply(60); + + let line = new paper.Path({ + segments: [point, point.add(tangent)], + strokeColor: 'red' + }) + + } + function Path46() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + let amount = 6; + let length = path.length; + for (let i = 0; i < amount + 1; i++) { + let offset = i / amount * length; + + // Find the point on the path at the given offset: + let point = path.getPointAt(offset); + + // Find the tangent vector on the path at the given offset + // and give it a length of 60: + let tangent = path.getTangentAt(offset).multiply(60); + + let line = new paper.Path({ + segments: [point, point.add(tangent)], + strokeColor: 'red' + }) + } + + } + function Path47() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + // We're going to be working with a third of the length + // of the path as the offset: + let offset = path.length / 3; + + // Find the point on the path: + let point = path.getPointAt(offset); + + // Find the normal vector on the path at the given offset + // and give it a length of 30: + let normal = path.getNormalAt(offset).multiply(30); + + let line = new paper.Path({ + segments: [point, point.add(normal)], + strokeColor: 'red' + }); + + } + function Path48() { + + // Create an arc shaped path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + path.add(new paper.Point(40, 100)); + path.arcTo(new paper.Point(150, 100)); + + let amount = 10; + let length = path.length; + for (let i = 0; i < amount + 1; i++) { + let offset = i / amount * length; + + // Find the point on the path at the given offset: + let point = path.getPointAt(offset); + + // Find the normal vector on the path at the given offset + // and give it a length of 30: + let normal = path.getNormalAt(offset).multiply(30); + + let line = new paper.Path({ + segments: [point, point.add(normal)], + strokeColor: 'red' + }); + } + + } + function Path49() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Path50() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Path51() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Path52() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Path53() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Path54() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Path55() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Path56() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Path57() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Path58() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Path59() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Path60() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Path61() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Path62() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Path63() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Path64() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Path65() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Path66() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Path67() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Path68() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Path69() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Path70() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Path71() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Path72() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Path73() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Path74() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Path75() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Path76() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Path77() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Path78() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Path79() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Path80() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Path81() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Path82() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Path83() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Path84() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Path85() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Path86() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Path87() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Path88() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Path89() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Path90() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Path91() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Path92() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Path93() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Path94() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Path95() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function Path96() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Path97() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Path98() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Path99() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Path100() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Path101() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Path102() { + + let path = new paper.Path.Rectangle(new paper.Point(30, 25), new paper.Size(50, 50)); + path.strokeColor = 'black'; + + let secondPath = path.clone(); + let intersectionGroup = new paper.Group(); + + function onFrame(event:paper.IFrameEvent) { + secondPath.rotate(1); + + let intersections = path.getIntersections(secondPath); + intersectionGroup.removeChildren(); + + for (let i = 0; i < intersections.length; i++) { + let intersectionPath = new paper.Path.Circle({ + center: intersections[i].point, + radius: 4, + fillColor: 'red', + parent: intersectionGroup + }); + } + } + + } + function Path103() { + + let star = new paper.Path.Star({ + center: paper.view.center, + points: 10, + radius1: 30, + radius2: 60, + strokeColor: 'black' + }); + + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 3, + fillColor: 'red' + }); + + function onMouseMove(event:paper.ToolEvent) { + // Get the nearest point from the mouse position + // to the star shaped path: + let nearestPoint = star.getNearestPoint(event.point); + + // Move the red circle to the nearest point: + circle.position = nearestPoint; + } + + } + function Path104() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Select the path, so we can inspect its segments: + path.selected = true; + + // Create a copy of the path and move it by 150 points: + let copy = path.clone(); + copy.position.x += 150; + + // Flatten the copied path, with a maximum error of 4 points: + copy.flatten(4); + + } + function Path105() { + + // Create a rectangular path with its top-left point at + // {x: 30, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle({ + point: [30, 25], + size: [50, 50], + strokeColor: 'black', + }); + + // Select the path, so we can see its handles: + path.fullySelected = true; + + // Create a copy of the path and move it 100 to the right: + let copy = path.clone(); + copy.position.x += 100; + + // Smooth the segments of the copy: + copy.smooth({ type: 'continuous' }); + + } + function Path106() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 50)); + + let y = 5; + let x = 3; + + for (let i = 0; i < 28; i++) { + y *= -1.1; + x *= 1.1; + path.lineBy(new paper.Point(x, y)); + } + + // Create a copy of the path and move it 100 down: + let copy = path.clone(); + copy.position.y += 120; + + // Select the path, so we can see its handles: + copy.fullySelected = true; + + // Smooth the path using centripetal Catmull-Rom splines: + copy.smooth({ type: 'catmull-rom', factor: 0.5 }); + + } + function Path107() { + + // Create 5 rectangles, next to each other: + let paths:paper.Path[] = []; + for (let i = 0; i < 5; i++) { + paths.push(new paper.Path.Rectangle({ + point: [30 + i * 100, 30], + size: [50, 50], + fullySelected: true + })); + } + // Smooth a range, using segments: + paths[1].smooth({ + type: 'continuous', + from: paths[1].segments[0], + to: paths[1].segments[2] + }); + + // Smooth a range, using curves: + paths[2].smooth({ + type: 'continuous', + from: paths[2].curves[0], + to: paths[2].curves[1] + }); + + // Smooth a range, using indices: + paths[3].smooth({ type: 'continuous', from: 0, to: 2 }); + + // Smooth a range, using negative indices: + paths[4].smooth({ type: 'continuous', from: -1, to: 1 }); + + } + function Path108() { + + let path: paper.Path | null; + function onMouseDown(event:paper.ToolEvent) { + // If we already made a path before, deselect it: + if (path) { + path.selected = false; + } + + // Create a new path and add the position of the mouse + // as its first segment. Select it, so we can see the + // segment points: + path = new paper.Path({ + segments: [event.point], + strokeColor: 'black', + selected: true + }); + } + + function onMouseDrag(event:paper.ToolEvent) { + // On every drag event, add a segment to the path + // at the position of the mouse: + if(path) + path.add(event.point); + } + + function onMouseUp(event:paper.ToolEvent) { + // When the mouse is released, simplify the path: + if(path){ + path.simplify(); + path.selected = true; + } + } + + } + function Path109() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + let firstPoint = new paper.Point(30, 75); + path.add(firstPoint); + + // The point through which we will create the arc: + let throughPoint = new paper.Point(40, 40); + + // The point at which the arc will end: + let toPoint = new paper.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': + let circle = new paper.Path.Circle(throughPoint, 3); + circle.fillColor = 'red'; + + } + function Path110() { + + let myPath:paper.Path | null; + function onMouseDrag(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw an arc through the position of the mouse to 'toPoint' + let toPoint = new paper.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:paper.ToolEvent) { + if(myPath){ + myPath.selected = false; + myPath.fillColor = 'black'; + } + } + + } + function Path111() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 75)); + path.arcTo(new paper.Point(130, 75)); + + let path2 = new paper.Path(); + path2.strokeColor = 'red'; + path2.add(new paper.Point(180, 25)); + + // To draw an arc in anticlockwise direction, + // we pass `false` as the second argument to arcTo: + path2.arcTo(new paper.Point(280, 25), false); + + } + function Path112() { + + let myPath:paper.Path; + + // The mouse has to move at least 20 points before + // the next mouse drag event is fired: + paper.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:paper.ToolEvent) { + myPath = new paper.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:paper.ToolEvent) { + myPath.arcTo(event.point); + } + + } + function Path113() { + + let myPath: paper.Path | null; + function onMouseMove(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw a curve through the position of the mouse to 'toPoint' + let toPoint = new paper.Point(350, 150); + myPath.curveTo(event.point, toPoint); + + // Select the path, so we can see its segments: + myPath.selected = true; + } + + } + function Path114() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add a segment at {x: 50, y: 50} + path.add(new paper.Point(25, 25)); + + // Add a segment relative to the last segment of the path. + // 50 in x direction and 0 in y direction, becomes {x: 75, y: 25} + path.lineBy(new paper.Point(50, 0)); + + // 0 in x direction and 50 in y direction, becomes {x: 75, y: 75} + path.lineBy(new paper.Point(0, 50)); + + } + function Path115() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add the first segment at {x: 50, y: 50} + path.add(paper.view.center); + + // Loop 500 times: + for (let i = 0; i < 500; i++) { + // Create a vector with an ever increasing length + // and an angle in increments of 45 degrees + let vector = new paper.Point({ + angle: i * 45, + length: i / 2 + }); + // Add the vector relatively to the last segment point: + path.lineBy(vector); + } + + // Smooth the handles of the path: + path.smooth(); + + // Uncomment the following line and click on 'run' to see + // the construction of the path: + // path.selected = true; + + } + function PathItem0() { + + let path = new paper.Path.Rectangle(new paper.Point(30, 25), new paper.Size(50, 50)); + path.strokeColor = 'black'; + + let secondPath = path.clone(); + let intersectionGroup = new paper.Group(); + + function onFrame(event:paper.IFrameEvent) { + secondPath.rotate(1); + + let intersections = path.getIntersections(secondPath); + intersectionGroup.removeChildren(); + + for (let i = 0; i < intersections.length; i++) { + let intersectionPath = new paper.Path.Circle({ + center: intersections[i].point, + radius: 4, + fillColor: 'red', + parent: intersectionGroup + }); + } + } + + } + function PathItem1() { + + let star = new paper.Path.Star({ + center: paper.view.center, + points: 10, + radius1: 30, + radius2: 60, + strokeColor: 'black' + }); + + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 3, + fillColor: 'red' + }); + + function onMouseMove(event:paper.ToolEvent) { + // Get the nearest point from the mouse position + // to the star shaped path: + let nearestPoint = star.getNearestPoint(event.point); + + // Move the red circle to the nearest point: + circle.position = nearestPoint; + } + + } + function PathItem2() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Select the path, so we can inspect its segments: + path.selected = true; + + // Create a copy of the path and move it by 150 points: + let copy = path.clone(); + copy.position.x += 150; + + // Flatten the copied path, with a maximum error of 4 points: + copy.flatten(4); + + } + function PathItem3() { + + // Create a rectangular path with its top-left point at + // {x: 30, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle({ + point: [30, 25], + size: [50, 50], + strokeColor: 'black', + }); + + // Select the path, so we can see its handles: + path.fullySelected = true; + + // Create a copy of the path and move it 100 to the right: + let copy = path.clone(); + copy.position.x += 100; + + // Smooth the segments of the copy: + copy.smooth({ type: 'continuous' }); + + } + function PathItem4() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 50)); + + let y = 5; + let x = 3; + + for (let i = 0; i < 28; i++) { + y *= -1.1; + x *= 1.1; + path.lineBy(new paper.Point(x, y)); + } + + // Create a copy of the path and move it 100 down: + let copy = path.clone(); + copy.position.y += 120; + + // Select the path, so we can see its handles: + copy.fullySelected = true; + + // Smooth the path using centripetal Catmull-Rom splines: + copy.smooth({ type: 'catmull-rom', factor: 0.5 }); + + } + function PathItem5() { + + // Create 5 rectangles, next to each other: + let paths:paper.Path[] = []; + for (let i = 0; i < 5; i++) { + paths.push(new paper.Path.Rectangle({ + point: [30 + i * 100, 30], + size: [50, 50], + fullySelected: true + })); + } + // Smooth a range, using segments: + paths[1].smooth({ + type: 'continuous', + from: paths[1].segments[0], + to: paths[1].segments[2] + }); + + // Smooth a range, using curves: + paths[2].smooth({ + type: 'continuous', + from: paths[2].curves[0], + to: paths[2].curves[1] + }); + + // Smooth a range, using indices: + paths[3].smooth({ type: 'continuous', from: 0, to: 2 }); + + // Smooth a range, using negative indices: + paths[4].smooth({ type: 'continuous', from: -1, to: 1 }); + + } + function PathItem6() { + + let path:paper.Path | null; + function onMouseDown(event:paper.ToolEvent) { + // If we already made a path before, deselect it: + if (path) { + path.selected = false; + } + + // Create a new path and add the position of the mouse + // as its first segment. Select it, so we can see the + // segment points: + path = new paper.Path({ + segments: [event.point], + strokeColor: 'black', + selected: true + }); + } + + function onMouseDrag(event:paper.ToolEvent) { + // On every drag event, add a segment to the path + // at the position of the mouse: + if(path) + path.add(event.point); + } + + function onMouseUp(event:paper.ToolEvent) { + // When the mouse is released, simplify the path: + if(path){ + path.simplify(); + path.selected = true; + } + } + + } + function PathItem7() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + let firstPoint = new paper.Point(30, 75); + path.add(firstPoint); + + // The point through which we will create the arc: + let throughPoint = new paper.Point(40, 40); + + // The point at which the arc will end: + let toPoint = new paper.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': + let circle = new paper.Path.Circle(throughPoint, 3); + circle.fillColor = 'red'; + + } + function PathItem8() { + + let myPath: paper.Path | null; + function onMouseDrag(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw an arc through the position of the mouse to 'toPoint' + let toPoint = new paper.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:paper.ToolEvent) { + if(myPath){ + myPath.selected = false; + myPath.fillColor = 'black'; + } + } + + } + function PathItem9() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + path.add(new paper.Point(30, 75)); + path.arcTo(new paper.Point(130, 75)); + + let path2 = new paper.Path(); + path2.strokeColor = 'red'; + path2.add(new paper.Point(180, 25)); + + // To draw an arc in anticlockwise direction, + // we pass `false` as the second argument to arcTo: + path2.arcTo(new paper.Point(280, 25), false); + + } + function PathItem10() { + + let myPath:paper.Path | null; + + // The mouse has to move at least 20 points before + // the next mouse drag event is fired: + paper.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:paper.ToolEvent) { + myPath = new paper.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:paper.ToolEvent) { + if(myPath) + myPath.arcTo(event.point); + } + + } + function PathItem11() { + + let myPath:paper.Path | null; + function onMouseMove(event:paper.ToolEvent) { + // 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 paper.Path(); + myPath.add(new paper.Point(150, 150)); + + // Draw a curve through the position of the mouse to 'toPoint' + let toPoint = new paper.Point(350, 150); + myPath.curveTo(event.point, toPoint); + + // Select the path, so we can see its segments: + myPath.selected = true; + } + + } + function PathItem12() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add a segment at {x: 50, y: 50} + path.add(new paper.Point(25, 25)); + + // Add a segment relative to the last segment of the path. + // 50 in x direction and 0 in y direction, becomes {x: 75, y: 25} + path.lineBy(new paper.Point(50, 0)); + + // 0 in x direction and 50 in y direction, becomes {x: 75, y: 75} + path.lineBy(new paper.Point(0, 50)); + + } + function PathItem13() { + + let path = new paper.Path(); + path.strokeColor = 'black'; + + // Add the first segment at {x: 50, y: 50} + path.add(paper.view.center); + + // Loop 500 times: + for (let i = 0; i < 500; i++) { + // Create a vector with an ever increasing length + // and an angle in increments of 45 degrees + let vector = new paper.Point({ + angle: i * 45, + length: i / 2 + }); + // Add the vector relatively to the last segment point: + path.lineBy(vector); + } + + // Smooth the handles of the path: + path.smooth(); + + // Uncomment the following line and click on 'run' to see + // the construction of the path: + // path.selected = true; + + } + function PathItem14() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function PathItem15() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function PathItem16() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function PathItem17() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function PathItem18() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function PathItem19() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function PathItem20() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function PathItem21() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function PathItem22() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function PathItem23() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function PathItem24() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function PathItem25() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function PathItem26() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function PathItem27() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function PathItem28() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function PathItem29() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function PathItem30() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function PathItem31() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function PathItem32() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function PathItem33() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function PathItem34() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function PathItem35() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PathItem36() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function PathItem37() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function PathItem38() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PathItem39() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PathItem40() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function PathItem41() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PathItem42() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function PathItem43() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function PathItem44() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function PathItem45() { + + function enter(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function PathItem46() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PathItem47() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function PathItem48() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function PathItem49() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function PathItem50() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function PathItem51() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function PathItem52() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function PathItem53() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function PathItem54() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function PathItem55() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function PathItem56() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function PathItem57() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function PathItem58() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function PathItem59() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function PathItem60() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function PathItem61() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function PathItem62() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function PathItem63() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function PathItem64() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function PathItem65() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function PathItem66() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Point0() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40 + }); + + // Select the third segment point: + path.segments[2].point.selected = true; + + // Select the item's position, which is the pivot point + // around which it is transformed: + path.position.selected = true; + + } + function PointText0() { + + let text = new paper.PointText(new paper.Point(200, 50)); + text.justification = 'center'; + text.fillColor = 'black'; + text.content = 'The contents of the point text'; + + } + function PointText1() { + + let text = new paper.PointText({ + point: [50, 50], + content: 'The contents of the point text', + fillColor: 'black', + fontFamily: 'Courier New', + fontWeight: 'bold', + fontSize: 25 + }); + + } + function PointText2() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function PointText3() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function PointText4() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function PointText5() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function PointText6() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function PointText7() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function PointText8() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function PointText9() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function PointText10() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function PointText11() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function PointText12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function PointText13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function PointText14() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function PointText15() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function PointText16() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function PointText17() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function PointText18() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function PointText19() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function PointText20() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function PointText21() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function PointText22() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function PointText23() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PointText24() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function PointText25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function PointText26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PointText27() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PointText28() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function PointText29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PointText30() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function PointText31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function PointText32() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function PointText33() { + + function enter(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function PointText34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function PointText35() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function PointText36() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function PointText37() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function PointText38() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function PointText39() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function PointText40() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function PointText41() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function PointText42() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function PointText43() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function PointText44() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function PointText45() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function PointText46() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function PointText47() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function PointText48() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function PointText49() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function PointText50() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function PointText51() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function PointText52() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function PointText53() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function PointText54() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function PointText55() { + + // Create a point-text item at {x: 30, y: 30}: + let text = new paper.PointText(new paper.Point(30, 30)); + text.fillColor = 'black'; + + // Set the content of the text item: + text.content = 'Hello world'; + + } + function PointText56() { + + // Create a point-text item at {x: 30, y: 30}: + let text = new paper.PointText(new paper.Point(30, 30)); + text.fillColor = 'black'; + + text.content = 'Move your mouse over the paper.view, to see its position'; + + function onMouseMove(event:paper.ToolEvent) { + // Each time the mouse is moved, set the content of + // the point text to describe the position of the mouse: + text.content = 'Your position is: ' + event.point.toString(); + } + + } + function Project0() { + + paper.project.currentStyle = { + fillColor: 'red', + strokeColor: 'black', + strokeWidth: 5 + } + + // The following paths will take over all style properties of + // the current style: + let path = new paper.Path.Circle(new paper.Point(75, 50), 30); + let path2 = new paper.Path.Circle(new paper.Point(175, 50), 20); + + } + function Project1() { + + paper.project.currentStyle.fillColor = 'red'; + + // The following path will take over the fill color we just set: + let path = new paper.Path.Circle(new paper.Point(75, 50), 30); + let path2 = new paper.Path.Circle(new paper.Point(175, 50), 20); + + } + function Project2() { + + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black' + }); + + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'black' + }); + + // Select path2: + path2.selected = true; + + // Fetch all selected path items: + let items = paper.project.getItems({ + selected: true, + class: paper.Path + }); + + // Change the fill color of the selected path to red: + items[0].fillColor = 'red'; + + } + function Project3() { + + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black' + }); + + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'purple' + }); + + // Fetch all items with a purple fill color: + let items = paper.project.getItems({ + fillColor: 'purple' + }); + + // Select the fetched item: + items[0].selected = true; + + } + function Project4() { + + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black' + }); + + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'black' + }); + + // Fetch all path items positioned at {x: 150, y: 150}: + let items = paper.project.getItems({ + position: [150, 50] + }); + + // Select the fetched path: + items[0].selected = true; + + } + function Project5() { + + // Create a circle shaped path: + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black' + }); + + // Create a circle shaped path with 50% opacity: + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'black', + opacity: 0.5 + }); + + // Fetch all items whose opacity is smaller than 1 + let items = paper.project.getItems({ + opacity: function(value:number) { + return value < 1; + } + }); + + // Select the fetched item: + items[0].selected = true; + + } + function Project6() { + + // Create a rectangle shaped path (4 segments): + let path1 = new paper.Path.Rectangle({ + from: [25, 25], + to: [75, 75], + strokeColor: 'black', + strokeWidth: 10 + }); + + // Create a line shaped path (2 segments): + let path2 = new paper.Path.Line({ + from: [125, 50], + to: [175, 50], + strokeColor: 'black', + strokeWidth: 10 + }); + + // Fetch all paths with 2 segments: + let items = paper.project.getItems({ + class: paper.Path, + segments: function(segments: paper.Segment[]) { + return segments.length == 2; + } + }); + + // Select the fetched path: + items[0].selected = true; + + } + function Project7() { + + // Create a black circle shaped path: + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black', + data: { + person: { + name: 'john', + length: 200, + hair: true + } + } + }); + + // Create a red circle shaped path: + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'red', + data: { + person: { + name: 'john', + length: 180, + hair: false + } + } + }); + + // Fetch all items whose data object contains a person + // object whose name is john and length is 180: + let items = paper.project.getItems({ + data: { + person: { + name: 'john', + length: 180 + } + } + }); + + // Select the fetched item: + items[0].selected = true; + + } + function Project8() { + + // Create a path named 'aardvark': + let path1 = new paper.Path.Circle({ + center: [50, 50], + radius: 25, + fillColor: 'black', + name: 'aardvark' + }); + + // Create a path named 'apple': + let path2 = new paper.Path.Circle({ + center: [150, 50], + radius: 25, + fillColor: 'black', + name: 'apple' + }); + + // Create a path named 'banana': + path2 = new paper.Path.Circle({ + center: [250, 50], + radius: 25, + fillColor: 'black', + name: 'banana' + }); + + // Fetch all items that have a name starting with 'a': + let items = paper.project.getItems({ + name: /^a/ + }); + + // Change the fill color of the matched items: + for (let i = 0; i < items.length; i++) { + items[i].fillColor = 'red'; + } + + } + function Raster0() { + + let url = 'http://assets.paperjs.org/images/marilyn.jpg'; + let raster = new paper.Raster(url); + + // If you create a Raster using a url, you can use the onLoad + // handler to do something once it is loaded: + raster.onLoad = function() { + console.log('The image has loaded.'); + }; + + } + function Raster1() { + + let raster = new paper.Raster({ + source: 'http://assets.paperjs.org/images/marilyn.jpg', + position: paper.view.center + }); + + raster.scale(0.5); + raster.rotate(10); + + } + function Raster2() { + + let raster = new paper.Raster(); + raster.source = 'http://paperjs.org/about/paper-js.gif'; + raster.position = paper.view.center; + + } + function Raster3() { + + let raster = new paper.Raster({ + source: 'http://paperjs.org/about/paper-js.gif', + position: paper.view.center + }); + + } + function Raster4() { + + let raster = new paper.Raster({ + crossOrigin: 'anonymous', + source: 'http://assets.paperjs.org/images/marilyn.jpg', + position: paper.view.center + }); + + console.log(paper.view.element.toDataURL('image/png').substring(0, 32)); + + } + function Raster5() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Raster6() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Raster7() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Raster8() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Raster9() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Raster10() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Raster11() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Raster12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Raster13() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Raster14() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Raster15() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Raster16() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Raster17() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Raster18() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Raster19() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Raster20() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Raster21() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Raster22() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Raster23() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Raster24() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Raster25() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Raster26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Raster27() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Raster28() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Raster29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Raster30() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Raster31() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Raster32() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Raster33() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Raster34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Raster35() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Raster36() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Raster37() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Raster38() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Raster39() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Raster40() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Raster41() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Raster42() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Raster43() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Raster44() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Raster45() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Raster46() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Raster47() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Raster48() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Raster49() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Raster50() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Raster51() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function Raster52() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Raster53() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Raster54() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Raster55() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Raster56() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Raster57() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Rectangle0() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + selected: true + }); + + path.bounds.selected = true; + + } + function Rectangle1() { + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 30. + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + circle.fillColor = 'red'; + + function onMouseMove(event:paper.ToolEvent) { + // Check whether the mouse position intersects with the + // bounding box of the item: + if (circle.bounds.contains(event.point)) { + // If it intersects, fill it with green: + circle.fillColor = 'green'; + } else { + // If it doesn't intersect, fill it with red: + circle.fillColor = 'red'; + } + } + + } + function Rectangle2() { + + // All newly created paths will inherit these styles: + paper.project.currentStyle = { + fillColor: 'green', + strokeColor: 'black' + }; + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 45. + let largeCircle = new paper.Path.Circle(new paper.Point(80, 50), 45); + + // Create a smaller circle shaped path in the same position + // with a radius of 30. + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + function onMouseMove(event:paper.ToolEvent) { + // Move the circle to the position of the mouse: + circle.position = event.point; + + // Check whether the bounding box of the smaller circle + // is contained within the bounding box of the larger item: + if (largeCircle.bounds.contains(circle.bounds)) { + // If it does, fill it with green: + circle.fillColor = 'green'; + largeCircle.fillColor = 'green'; + } else { + // If doesn't, fill it with red: + circle.fillColor = 'red'; + largeCircle.fillColor = 'red'; + } + } + + } + function Rectangle3() { + + // All newly created paths will inherit these styles: + paper.project.currentStyle = { + fillColor: 'green', + strokeColor: 'black' + }; + + // Create a circle shaped path at {x: 80, y: 50} + // with a radius of 45. + let largeCircle = new paper.Path.Circle(new paper.Point(80, 50), 45); + + // Create a smaller circle shaped path in the same position + // with a radius of 30. + let circle = new paper.Path.Circle(new paper.Point(80, 50), 30); + + function onMouseMove(event:paper.ToolEvent) { + // Move the circle to the position of the mouse: + circle.position = event.point; + + // Check whether the bounding box of the two circle + // shaped paths intersect: + if (largeCircle.bounds.intersects(circle.bounds)) { + // If it does, fill it with green: + circle.fillColor = 'green'; + largeCircle.fillColor = 'green'; + } else { + // If doesn't, fill it with red: + circle.fillColor = 'red'; + largeCircle.fillColor = 'red'; + } + } + + } + function Rectangle4() { + + // Create two rectangles that overlap each other + let size = new paper.Size(50, 50); + let rectangle1 = new paper.Rectangle(new paper.Point(25, 15), size); + let rectangle2 = new paper.Rectangle(new paper.Point(50, 40), size); + + // The rectangle that represents the intersection of the + // two rectangles: + let intersected = rectangle1.intersect(rectangle2); + + // To visualize the intersecting of the rectangles, we will + // create rectangle shaped paths using the Path.Rectangle + // constructor. + + // Have all newly created paths inherit a black stroke: + paper.project.currentStyle.strokeColor = 'black'; + + // Create two rectangle shaped paths using the abstract rectangles + // we created before: + new paper.Path.Rectangle(rectangle1); + new paper.Path.Rectangle(rectangle2); + + // Create a path that represents the intersected rectangle, + // and fill it with red: + let intersectionPath = new paper.Path.Rectangle(intersected); + intersectionPath.fillColor = 'red'; + + } + function Segment0() { + + let handleIn = new paper.Point(-80, -100); + let handleOut = new paper.Point(80, 100); + + let firstPoint = new paper.Point(100, 50); + let firstSegment = new paper.Segment(firstPoint, undefined, handleOut); + + let secondPoint = new paper.Point(300, 50); + let secondSegment = new paper.Segment(secondPoint, handleIn, undefined); + + let path = new paper.Path([firstSegment, secondSegment]); + path.strokeColor = 'black'; + + } + function Segment1() { + + let firstSegment = new paper.Segment({ + point: [100, 50], + handleOut: [80, 100] + }); + + let secondSegment = new paper.Segment({ + point: [300, 50], + handleIn: [-80, -100] + }); + + let path = new paper.Path({ + segments: [firstSegment, secondSegment], + strokeColor: 'black' + }); + + } + function Segment2() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40 + }); + + // Select the third segment point: + path.segments[2].selected = true; + + } + function Shape0() { + + let shape = paper.Shape.Circle(new paper.Point(80, 50), 30); + shape.strokeColor = 'black'; + + } + function Shape1() { + + let shape = paper.Shape.Circle({ + center: [80, 50], + radius: 30, + strokeColor: 'black' + }); + + } + function Shape2() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(60, 60)); + let shape = paper.Shape.Rectangle(rectangle); + shape.strokeColor = 'black'; + + } + function Shape3() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(60, 60)); + let cornerSize = new paper.Size(10, 10); + let shape = paper.Shape.Rectangle([rectangle, cornerSize]); + shape.strokeColor = 'black'; + + } + function Shape4() { + + let point = new paper.Point(20, 20); + let size = new paper.Size(60, 60); + let shape = paper.Shape.Rectangle(point, size); + shape.strokeColor = 'black'; + + } + function Shape5() { + + let from = new paper.Point(20, 20); + let to = new paper.Point(80, 80); + let shape = paper.Shape.Rectangle(from, to); + shape.strokeColor = 'black'; + + } + function Shape6() { + + let shape = paper.Shape.Rectangle({ + point: [20, 20], + size: [60, 60], + strokeColor: 'black' + }); + + } + function Shape7() { + + let shape = paper.Shape.Rectangle({ + from: [20, 20], + to: [80, 80], + strokeColor: 'black' + }); + + } + function Shape8() { + + let shape = paper.Shape.Rectangle({ + rectangle: { + topLeft: [20, 20], + bottomRight: [80, 80] + }, + strokeColor: 'black' + }); + + } + function Shape9() { + + let shape = paper.Shape.Rectangle({ + topLeft: [20, 20], + bottomRight: [80, 80], + radius: 10, + strokeColor: 'black' + }); + + } + function Shape10() { + + let rectangle = new paper.Rectangle(new paper.Point(20, 20), new paper.Size(180, 60)); + let shape = paper.Shape.Ellipse(rectangle); + shape.fillColor = 'black'; + + } + function Shape11() { + + let shape = paper.Shape.Ellipse({ + point: [20, 20], + size: [180, 60], + fillColor: 'black' + }); + + } + function Shape12() { + + let shape = paper.Shape.Ellipse({ + center: [110, 50], + radius: [90, 30], + fillColor: 'black' + }); + + } + function Shape13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function Shape14() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function Shape15() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function Shape16() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function Shape17() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function Shape18() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function Shape19() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function Shape20() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function Shape21() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function Shape22() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function Shape23() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function Shape24() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function Shape25() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function Shape26() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Shape27() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Shape28() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Shape29() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Shape30() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Shape31() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Shape32() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function Shape33() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function Shape34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Shape35() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function Shape36() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function Shape37() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Shape38() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Shape39() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Shape40() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Shape41() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function Shape42() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function Shape43() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function Shape44() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function Shape45() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function Shape46() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function Shape47() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function Shape48() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function Shape49() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function Shape50() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function Shape51() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function Shape52() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function Shape53() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function Shape54() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function Shape55() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function Shape56() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function Shape57() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function Shape58() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function Shape59() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function Shape60() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function Shape61() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function Shape62() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function Shape63() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function Shape64() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function Shape65() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Style0() { + + let path = new paper.Path.Circle(new paper.Point(80, 50), 30); + path.style = { + fillColor: new paper.Color(1, 0, 0), + strokeColor: 'black', + strokeWidth: 5 + }; + + } + function Style1() { + + let text = new paper.PointText(paper.view.center); + text.content = 'Hello world.'; + text.style = { + fontFamily: 'Courier New', + fontWeight: 'bold', + fontSize: 20, + fillColor: 'red', + justification: 'center' + }; + + } + function Style2() { + + let path1 = new paper.Path.Circle({ + center: [100, 50], + radius: 30 + }); + + let path2 = new paper.Path.Rectangle({ + from: [170, 20], + to: [230, 80] + }); + + let group = new paper.Group([path1, path2]); + + // All styles set on a group are automatically + // set on the children of the group: + group.style = { + strokeColor: 'black', + dashArray: [4, 10], + strokeWidth: 4, + strokeCap: 'round' + }; + + } + function Style3() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 35); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function Style4() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 35); + + // Set its stroke color to black: + circle.strokeColor = 'black'; + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function Style5() { + + let line = new paper.Path([new paper.Point(80, 50), new paper.Point(420, 50)]); + line.strokeColor = 'black'; + line.strokeWidth = 20; + + // Select the path, so we can see where the stroke is formed: + line.selected = true; + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function Style6() { + + let path = new paper.Path(); + path.add(new paper.Point(80, 100)); + path.add(new paper.Point(120, 40)); + path.add(new paper.Point(160, 100)); + path.strokeColor = 'black'; + path.strokeWidth = 20; + + // Select the path, so we can see where the stroke is formed: + path.selected = true; + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function Style7() { + + let path = new paper.Path.Circle(new paper.Point(80, 50), 40); + path.strokeWidth = 2; + path.strokeColor = 'black'; + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function Style8() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle(new paper.Point(80, 50), 35); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function Style9() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function SymbolDefinition0() { + + let path = new paper.Path.Star(new paper.Point(0, 0), 6, 5, 13); + path.style = { + fillColor: 'white', + strokeColor: 'black' + }; + + // Create a symbol definition from the path: + let definition = new paper.Symbol(path); + + // Place 100 instances of the symbol definition: + for (let i = 0; i < 100; i++) { + // Place an instance of the symbol definition in the project: + let instance = definition.place(); + + // Move the instance to a random position within the paper.view: + instance.position = paper.Point.random().multiply(new paper.Point(paper.view.size)); + + // Rotate the instance by a random amount between + // 0 and 360 degrees: + instance.rotate(Math.random() * 360); + + // Scale the instance between 0.25 and 1: + instance.scale(0.25 + Math.random() * 0.75); + } + + } + function SymbolItem0() { + + let path = new paper.Path.Star({ + center: new paper.Point(0, 0), + points: 6, + radius1: 5, + radius2: 13, + fillColor: 'white', + strokeColor: 'black' + }); + + // Create a symbol definition from the path: + let definition = new paper.Symbol(path); + + // Place 100 instances of the symbol: + for (let i = 0; i < 100; i++) { + // Place an instance of the symbol in the project: + let instance = new paper.PlacedSymbol(definition); + + // Move the instance to a random position within the paper.view: + instance.position = paper.Point.random().multiply(new paper.Point(paper.view.size)); + + // Rotate the instance by a random amount between + // 0 and 360 degrees: + instance.rotate(Math.random() * 360); + + // Scale the instance between 0.25 and 1: + instance.scale(0.25 + Math.random() * 0.75); + } + + } + function SymbolItem1() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function SymbolItem2() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function SymbolItem3() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function SymbolItem4() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function SymbolItem5() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function SymbolItem6() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function SymbolItem7() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function SymbolItem8() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function SymbolItem9() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function SymbolItem10() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function SymbolItem11() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function SymbolItem12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function SymbolItem13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function SymbolItem14() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function SymbolItem15() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function SymbolItem16() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function SymbolItem17() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function SymbolItem18() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function SymbolItem19() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function SymbolItem20() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function SymbolItem21() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function SymbolItem22() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function SymbolItem23() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function SymbolItem24() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function SymbolItem25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function SymbolItem26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function SymbolItem27() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function SymbolItem28() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function SymbolItem29() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function SymbolItem30() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function SymbolItem31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function SymbolItem32() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function SymbolItem33() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function SymbolItem34() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function SymbolItem35() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function SymbolItem36() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function SymbolItem37() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function SymbolItem38() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function SymbolItem39() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function SymbolItem40() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function SymbolItem41() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function SymbolItem42() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function SymbolItem43() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function SymbolItem44() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function SymbolItem45() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function SymbolItem46() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function SymbolItem47() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + }); + + } + function SymbolItem48() { + + let pathHandlers = { + mouseenter: function(this:paper.Path) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function SymbolItem49() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function SymbolItem50() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function SymbolItem51() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function SymbolItem52() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function SymbolItem53() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function TextItem0() { + + // Create a point-text item at {x: 30, y: 30}: + let text = new paper.PointText(new paper.Point(30, 30)); + text.fillColor = 'black'; + + // Set the content of the text item: + text.content = 'Hello world'; + + } + function TextItem1() { + + // Create a point-text item at {x: 30, y: 30}: + let text = new paper.PointText(new paper.Point(30, 30)); + text.fillColor = 'black'; + + text.content = 'Move your mouse over the paper.view, to see its position'; + + function onMouseMove(event:paper.ToolEvent) { + // Each time the mouse is moved, set the content of + // the point text to describe the position of the mouse: + text.content = 'Your position is: ' + event.point.toString(); + } + + } + function TextItem2() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and add path to it as a child: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'red'; + + } + function TextItem3() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 30 + }); + circle.style = { + fillColor: 'blue', + strokeColor: 'red', + strokeWidth: 5 + }; + + } + function TextItem4() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30, + fillColor: 'red' + }); + + let path2 = new paper.Path.Circle({ + center: new paper.Point(180, 50), + radius: 20 + }); + + // Copy the path style of path: + path2.style = path.style; + + } + function TextItem5() { + + let myStyle = { + fillColor: 'red', + strokeColor: 'blue', + strokeWidth: 4 + }; + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 30 + }); + path.style = myStyle; + + let path2 = new paper.Path.Circle({ + center: new paper.Point(150, 50), + radius: 20 + }); + path2.style = myStyle; + + } + function TextItem6() { + + let path = new paper.Path.Circle({ + center: [50, 50], + radius: 20, + fillColor: 'red' + }); + + // Hide the path: + path.visible = false; + + } + function TextItem7() { + + // Create a white rectangle in the background + // with the same dimensions as the paper.view: + let background = new paper.Path.Rectangle(paper.view.bounds); + background.fillColor = 'white'; + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue' + }); + + // Set the blend mode of circle2: + circle2.blendMode = 'multiply'; + + } + function TextItem8() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'red' + }); + + let circle2 = new paper.Path.Circle({ + center: new paper.Point(120, 50), + radius: 35, + fillColor: 'blue', + strokeColor: 'green', + strokeWidth: 10 + }); + + // Make circle2 50% transparent: + circle2.opacity = 0.5; + + } + function TextItem9() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + path.selected = true; // Select the path + + } + function TextItem10() { + + // Create a circle at position { x: 10, y: 10 } + let circle = new paper.Path.Circle({ + center: new paper.Point(10, 10), + radius: 10, + fillColor: 'red' + }); + + // Move the circle to { x: 20, y: 20 } + circle.position = new paper.Point(20, 20); + + // Move the circle 100 points to the right and 50 points down + circle.position = circle.position.add(new paper.Point(100, 50)); + + } + function TextItem11() { + + // Create a circle at position { x: 20, y: 20 } + let circle = new paper.Path.Circle({ + center: new paper.Point(20, 20), + radius: 10, + fillColor: 'red' + }); + + // Move the circle 100 points to the right + circle.position.x += 100; + + } + function TextItem12() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // Access the path through the group's children array: + group.children[0].fillColor = 'red'; + + } + function TextItem13() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + // Set the name of the path: + path.name = 'example'; + + // Create a group and move the path into it: + let group = new paper.Group(); + group.addChild(path); + + // The path can be accessed by name: + group.getItem('example').fillColor = 'orange'; + + } + function TextItem14() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + let group = new paper.Group(); + group.children = [path]; + + // The path is the first child of the group: + group.firstChild.fillColor = 'green'; + + } + function TextItem15() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set its stroke color to RGB red: + circle.strokeColor = new paper.Color(1, 0, 0); + + } + function TextItem16() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + strokeColor: 'red' + }); + + // Set its stroke width to 10: + circle.strokeWidth = 10; + + } + function TextItem17() { + + let line = new paper.Path({ + segments: [[80, 50], [420, 50]], + strokeColor: 'black', + strokeWidth: 20, + selected: true + }); + + // Set the stroke cap of the line to be round: + line.strokeCap = 'round'; + + // Copy the path and set its stroke cap to be square: + let line2 = line.clone(); + line2.position.y += 50; + line2.strokeCap = 'square'; + + // Make another copy and set its stroke cap to be butt: + line2 = line.clone(); + line2.position.y += 100; + line2.strokeCap = 'butt'; + + } + function TextItem18() { + + let path = new paper.Path({ + segments: [[80, 100], [120, 40], [160, 100]], + strokeColor: 'black', + strokeWidth: 20, + // Select the path, in order to see where the stroke is formed: + selected: true + }); + + let path2 = path.clone(); + path2.position.x += path2.bounds.width * 1.5; + path2.strokeJoin = 'round'; + + let path3 = path2.clone(); + path3.position.x += path3.bounds.width * 1.5; + path3.strokeJoin = 'bevel'; + + } + function TextItem19() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 40, + strokeWidth: 2, + strokeColor: 'black' + }); + + // Set the dashed stroke to [10pt dash, 4pt gap]: + path.dashArray = [10, 4]; + + } + function TextItem20() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 35: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + // Set the fill color of the circle to RGB red: + circle.fillColor = new paper.Color(1, 0, 0); + + } + function TextItem21() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35, + fillColor: 'white', + // Set the shadow color of the circle to RGB black: + shadowColor: new paper.Color(0, 0, 0), + // Set the shadow blur radius to 12: + shadowBlur: 12, + // Offset the shadow by { x: 5, y: 5 } + shadowOffset: new paper.Point(5, 5) + }); + + } + function TextItem22() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + path.onFrame = function(this:paper.Path) { + // Every frame, rotate the path by 3 degrees: + this.rotate(3); + } + + } + function TextItem23() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is pressed on the item, + // set its fill color to red: + path.onMouseDown = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function TextItem24() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is pressed on the item, remove it: + path.onMouseDown = function(this:paper.Path) { + this.remove(); + } + } + + } + function TextItem25() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 50, + fillColor: 'blue' + }); + + // Install a drag event handler that moves the path along. + path.onMouseDrag = function(this:paper.Path, event:paper.MouseEvent) { + path.position = path.position.add(event.delta); + } + + } + function TextItem26() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is released over the item, + // set its fill color to red: + path.onMouseUp = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function TextItem27() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is clicked on the item, + // set its fill color to red: + path.onClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function TextItem28() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse clicks on the item, remove it: + path.onClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function TextItem29() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse is double clicked on the item, + // set its fill color to red: + path.onDoubleClick = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function TextItem30() { + + // Loop 30 times: + for (let i = 0; i < 30; i++) { + // Create a circle shaped path at a random position + // in the paper.view: + let path = new paper.Path.Circle({ + center: paper.Point.random().multiply(new paper.Point(paper.view.size)), + radius: 25, + fillColor: 'black', + strokeColor: 'white' + }); + + // When the mouse is double clicked on the item, remove it: + path.onDoubleClick = function(this:paper.Path) { + this.remove(); + } + } + + } + function TextItem31() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse moves on top of the item, set its opacity + // to a random value between 0 and 1: + path.onMouseMove = function(this:paper.Path) { + this.opacity = Math.random(); + } + + } + function TextItem32() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = function(this:paper.Path) { + this.fillColor = 'red'; + } + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'black'; + } + + } + function TextItem33() { + + function enter(this:paper.Path) { + this.fillColor = 'red'; + } + + function leave(this:paper.Path) { + this.fillColor = 'black'; + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle(event.point, 25); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.onMouseEnter = enter; + + // When the mouse leaves the item, set its fill color to black: + path.onMouseLeave = leave; + } + + } + function TextItem34() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse leaves the item, set its fill color to red: + path.onMouseLeave = function(this:paper.Path) { + this.fillColor = 'red'; + } + + } + function TextItem35() { + + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 35 + }); + + circle.set({ + strokeColor: 'red', + strokeWidth: 10, + fillColor: 'black', + selected: true + }); + + } + function TextItem36() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 10, + fillColor: 'red' + }); + + // Make 20 copies of the circle: + for (let i = 0; i < 20; i++) { + let copy = circle.clone(); + + // Distribute the copies horizontally, so we can see them: + copy.position.x += i * copy.bounds.width; + } + + } + function TextItem37() { + + let circle = new paper.Path.Circle({ + center: [50, 50], + radius: 5, + fillColor: 'red' + }); + + // Create a rasterized version of the path: + let raster = circle.rasterize(); + + // Move it 100pt to the right: + raster.position.x += 100; + + // Scale the path and the raster by 300%, so we can compare them: + circle.scale(5); + raster.scale(5); + + } + function TextItem38() { + + let path = new paper.Path.Star({ + center: [50, 50], + points: 12, + radius1: 20, + radius2: 40, + fillColor: 'black' + }); + + // Whenever the user presses the mouse: + function onMouseDown(event:paper.ToolEvent) { + // If the position of the mouse is within the path, + // set its fill color to red, otherwise set it to + // black: + if (path.contains(event.point)) { + path.fillColor = 'red'; + } else { + path.fillColor = 'black'; + } + } + + } + function TextItem39() { + + // Create a rectangle shaped path with its top left + // point at {x: 80, y: 25} and a size of {width: 50, height: 50}: + let path = new paper.Path.Rectangle(new paper.Point(80, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + // Rotate the path by 30 degrees: + path.rotate(30); + + } + function TextItem40() { + + // Create a rectangle shaped path with its top left + // point at {x: 175, y: 50} and a size of {width: 100, height: 100}: + let topLeft = new paper.Point(175, 50); + let size = new paper.Size(100, 100); + let path = new paper.Path.Rectangle(topLeft, size); + path.fillColor = 'black'; + + // Draw a circle shaped path in the center of the paper.view, + // to show the rotation point: + let circle = new paper.Path.Circle({ + center: paper.view.center, + radius: 5, + fillColor: 'white' + }); + + // Each frame rotate the path 3 degrees around the center point + // of the paper.view: + function onFrame(event:paper.IFrameEvent) { + path.rotate(3, paper.view.center); + } + + } + function TextItem41() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path by 150% from its center point + circle.scale(1.5); + + } + function TextItem42() { + + // Create a circle shaped path at { x: 80, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [80, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path 150% from its bottom left corner + circle.scale(1.5, circle.bounds.bottomLeft); + + } + function TextItem43() { + + // Create a circle shaped path at { x: 100, y: 50 } + // with a radius of 20: + let circle = new paper.Path.Circle({ + center: [100, 50], + radius: 20, + fillColor: 'red' + }); + + // Scale the path horizontally by 300% + circle.scale(3, 1); + + } + function TextItem44() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds); + + } + function TextItem45() { + + // Create a rectangle shaped path with its top left corner + // at {x: 80, y: 25} and a size of {width: 75, height: 50}: + let path = new paper.Path.Rectangle({ + point: [80, 25], + size: [75, 50], + fillColor: 'black' + }); + + // Create a circle shaped path with its center at {x: 80, y: 50} + // and a radius of 30. + let circlePath = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the circlePath to the bounding rectangle of + // the rectangular path: + circlePath.fitBounds(path.bounds, true); + + } + function TextItem46() { + + let path = new paper.Path.Circle({ + center: [80, 50], + radius: 30, + fillColor: 'red' + }); + + // Fit the path to the bounding rectangle of the paper.view: + path.fitBounds(paper.view.bounds); + + } + function TextItem47() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25, + fillColor: 'black' + }); + + // When the mouse enters the item, set its fill color to red: + path.on('mouseenter', function(this:paper.Path) { + this.fillColor = 'red'; + }); + + // When the mouse leaves the item, set its fill color to black: + path.on('mouseleave', function(this:paper.Path) { + this.fillColor = 'black'; + }); + + } + function TextItem48() { + + // Create a circle shaped path at the center of the paper.view: + let path = new paper.Path.Circle({ + center: paper.view.center, + radius: 25 + }); + path.fillColor = 'black'; + + // When the mouse enters the item, set its fill color to red: + path.on({ + mouseenter: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + }); + + } + function TextItem49() { + + let pathHandlers = { + mouseenter: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'red'; + }, + mouseleave: function(this:paper.Path, event:paper.MouseEvent) { + this.fillColor = 'black'; + } + } + + // When the mouse is pressed: + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the position of the mouse: + let path = new paper.Path.Circle({ + center: event.point, + radius: 25, + fillColor: 'black' + }); + + // Attach the handers inside the object literal to the path: + path.on(pathHandlers); + } + + } + function TextItem50() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path on the next onMouseDrag or onMouseDown event: + path.removeOn({ + drag: true, + down: true + }); + } + + } + function TextItem51() { + + function onMouseMove(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next move event, automatically remove the path: + path.removeOnMove(); + } + + } + function TextItem52() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, next time the mouse is pressed: + path.removeOnDown(); + } + + } + function TextItem53() { + + function onMouseDrag(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // On the next drag event, automatically remove the path: + path.removeOnDrag(); + } + + } + function TextItem54() { + + function onMouseDown(event:paper.ToolEvent) { + // Create a circle shaped path at the mouse position, + // with a radius of 10: + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + + // Remove the path, when the mouse is released: + path.removeOnUp(); + } + + } + function Tool0() { + + let path:paper.Path; + + // Only execute onMouseDrag when the mouse + // has moved at least 10 points: + paper.tool.minDistance = 10; + + paper.tool.onMouseDown = function(this:paper.Tool, event:paper.ToolEvent) { + // Create a new path every time the mouse is clicked + path = new paper.Path(); + path.add(event.point); + path.strokeColor = 'black'; + } + + paper.tool.onMouseDrag = function(this:paper.Tool, event:paper.ToolEvent) { + // Add a point to the path every time the mouse is dragged + path.add(event.point); + } + + } + function Tool1() { + + paper.tool.onMouseDown = function(event:paper.ToolEvent) { + // Create a new circle shaped path with a radius of 10 + // at the position of the mouse (event.point): + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + } + + } + function Tool2() { + + // Create an empty path: + let path = new paper.Path({ + strokeColor: 'black' + }); + + paper.tool.onMouseDrag = function(event:paper.ToolEvent) { + // Add a segment to the path at the position of the mouse: + path.add(event.point); + } + + } + function Tool3() { + + // Create a circle shaped path with a radius of 10 at {x: 0, y: 0}: + let path = new paper.Path.Circle({ + center: [0, 0], + radius: 10, + fillColor: 'black' + }); + + paper.tool.onMouseMove = function(event:paper.ToolEvent) { + // Whenever the user moves the mouse, move the path + // to that position: + path.position = event.point; + } + + } + function Tool4() { + + paper.tool.onMouseUp = function(event:paper.ToolEvent) { + // Create a new circle shaped path with a radius of 10 + // at the position of the mouse (event.point): + let path = new paper.Path.Circle({ + center: event.point, + radius: 10, + fillColor: 'black' + }); + } + + } + function Tool5() { + + // Create a circle shaped path: + let path = new paper.Path.Circle({ + center: new paper.Point(50, 50), + radius: 30, + fillColor: 'red' + }); + + paper.tool.onKeyDown = function(event:paper.KeyEvent) { + if (event.key == 'space') { + // Scale the path by 110%: + path.scale(1.1); + + // Prevent the key event from bubbling + return false; + } + } + + } + function View0() { + + // Create a rectangle shaped path with its top left point at: + // {x: 50, y: 25} and a size of {width: 50, height: 50} + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + paper.view.onFrame = function(event:paper.IFrameEvent) { + // Every frame, rotate the path by 3 degrees: + path.rotate(3); + } + + } + function View1() { + + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + let frameHandler = function(event: paper.IFrameEvent){ + // Every frame, rotate the path by 3 degrees: + path.rotate(3); + }; + + paper.view.on('frame', frameHandler); + + } + function View2() { + + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + let frameHandler = function(event:paper.IFrameEvent) { + // Every frame, rotate the path by 3 degrees: + path.rotate(3); + }; + + paper.view.on({ + frame: frameHandler + }); + + } + function View3() { + + let path = new paper.Path.Rectangle(new paper.Point(50, 25), new paper.Size(50, 50)); + path.fillColor = 'black'; + + let frameHandler = function(event:paper.IFrameEvent) { + // Every frame, rotate the path by 3 degrees: + path.rotate(3); + }; + + paper.view.on({ + frame: frameHandler + }); + + // When the user presses the mouse, + // detach the frame handler from the paper.view: + function onMouseDown(event:paper.ToolEvent) { + paper.view.off('frame'); + } + + } + +}