/* * Graphics * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ // namespace: this.createjs = this.createjs||{}; (function() { /** * Inner class used by the {{#crossLink "Graphics"}}{{/crossLink}} class. Used to create the instruction lists used in Graphics: * @class Command * @protected * @constructor **/ function Command(f, params, path) { this.f = f; this.params = params; this.path = path==null ? true : path; } /** * @method exec * @protected * @param {Object} scope **/ Command.prototype.exec = function(scope) { this.f.apply(scope, this.params); } /** * The Graphics class exposes an easy to use API for generating vector drawing instructions and drawing them to a * specified context. Note that you can use Graphics without any dependency on the Easel framework by calling {{#crossLink "DisplayObject/draw"}}{{/crossLink}} * directly, or it can be used with the {{#crossLink "Shape"}}{{/crossLink}} object to draw vector graphics within the * context of an Easel display list. * *

Example

* var g = new Graphics(); * g.setStrokeStyle(1); * g.beginStroke(Graphics.getRGB(0,0,0)); * g.beginFill(Graphics.getRGB(255,0,0)); * g.drawCircle(0,0,3); * * var s = new Shape(g); * s.x = 100; * s.y = 100; * * stage.addChild(s); * stage.update(); * * Note that all drawing methods in Graphics return the Graphics instance, so they can be chained together. For example, * the following line of code would generate the instructions to draw a rectangle with a red stroke and blue fill, then * render it to the specified context2D: * * myGraphics.beginStroke("#F00").beginFill("#00F").drawRect(20, 20, 100, 50).draw(myContext2D); * *

Tiny API

* The Graphics class also includes a "tiny API", which is one or two-letter methods that are shortcuts for all of the * Graphics methods. These methods are great for creating compact instructions, and is used by the Toolkit for CreateJS * to generate readable code. All tiny methods are marked as protected, so you can view them by enabling protected * descriptions in the docs. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
TinyMethodTinyMethod
mt{{#crossLink "Graphics/moveTo"}}{{/crossLink}} lt {{#crossLink "Graphics/lineTo"}}{{/crossLink}}
at{{#crossLink "Graphics/arcTo"}}{{/crossLink}} bt{{#crossLink "Graphics/bezierCurveTo"}}{{/crossLink}}
qt{{#crossLink "Graphics/quadraticCurveTo"}}{{/crossLink}} (also curveTo)r{{#crossLink "Graphics/rect"}}{{/crossLink}}
cp{{#crossLink "Graphics/closePath"}}{{/crossLink}} c{{#crossLink "Graphics/clear"}}{{/crossLink}}
f{{#crossLink "Graphics/beginFill"}}{{/crossLink}} lf{{#crossLink "Graphics/beginLinearGradientFill"}}{{/crossLink}}
rf{{#crossLink "Graphics/beginRadialGradientFill"}}{{/crossLink}} bf{{#crossLink "Graphics/beginBitmapFill"}}{{/crossLink}}
ef{{#crossLink "Graphics/endFill"}}{{/crossLink}} ss{{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}}
s{{#crossLink "Graphics/beginStroke"}}{{/crossLink}} ls{{#crossLink "Graphics/beginLinearGradientStroke"}}{{/crossLink}}
rs{{#crossLink "Graphics/beginRadialGradientStroke"}}{{/crossLink}} bs{{#crossLink "Graphics/beginBitmapStroke"}}{{/crossLink}}
es{{#crossLink "Graphics/endStroke"}}{{/crossLink}} dr{{#crossLink "Graphics/drawRect"}}{{/crossLink}}
rr{{#crossLink "Graphics/drawRoundRect"}}{{/crossLink}} rc{{#crossLink "Graphics/drawRoundRectComplex"}}{{/crossLink}}
dc{{#crossLink "Graphics/drawCircle"}}{{/crossLink}} de{{#crossLink "Graphics/drawEllipse"}}{{/crossLink}}
dp{{#crossLink "Graphics/drawPolyStar"}}{{/crossLink}} p{{#crossLink "Graphics/decodePath"}}{{/crossLink}}
* * Here is the above example, using the tiny API instead. * * myGraphics.s("#F00").f("#00F").r(20, 20, 100, 50).draw(myContext2D); * * @class Graphics * @constructor * @for Graphics **/ var Graphics = function() { this.initialize(); }; var p = Graphics.prototype; // static public methods: /** * Returns a CSS compatible color string based on the specified RGB numeric color values in the format * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)". For example, * * Graphics.getRGB(50, 100, 150, 0.5); * * will return "rgba(50,100,150,0.5)". It also supports passing a single hex color value as the first param, and an * optional alpha value as the second param. For example, * * Graphics.getRGB(0xFF00FF, 0.2); * * will return "rgba(255,0,255,0.2)". * @method getRGB * @static * @param {Number} r The red component for the color, between 0 and 0xFF (255). * @param {Number} g The green component for the color, between 0 and 0xFF (255). * @param {Number} b The blue component for the color, between 0 and 0xFF (255). * @param {Number} alpha Optional. The alpha component for the color where 0 is fully transparent and 1 is fully opaque. * @return {String} A CSS compatible color string based on the specified RGB numeric color values in the format * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)". **/ Graphics.getRGB = function(r, g, b, alpha) { if (r != null && b == null) { alpha = g; b = r&0xFF; g = r>>8&0xFF; r = r>>16&0xFF; } if (alpha == null) { return "rgb("+r+","+g+","+b+")"; } else { return "rgba("+r+","+g+","+b+","+alpha+")"; } }; /** * Returns a CSS compatible color string based on the specified HSL numeric color values in the format "hsla(360,100,100,1.0)", * or if alpha is null then in the format "hsl(360,100,100)". For example, this will return "hsl(150,100,70)". * * Graphics.getHSL(150, 100, 70); * * @method getHSL * @static * @param {Number} hue The hue component for the color, between 0 and 360. * @param {Number} saturation The saturation component for the color, between 0 and 100. * @param {Number} lightness The lightness component for the color, between 0 and 100. * @param {Number} alpha Optional. The alpha component for the color where 0 is fully transparent and 1 is fully opaque. * @return {String} A CSS compatible color string based on the specified HSL numeric color values in the format * "hsla(360,100,100,1.0)", or if alpha is null then in the format "hsl(360,100,100)". **/ Graphics.getHSL = function(hue, saturation, lightness, alpha) { if (alpha == null) { return "hsl("+(hue%360)+","+saturation+"%,"+lightness+"%)"; } else { return "hsla("+(hue%360)+","+saturation+"%,"+lightness+"%,"+alpha+")"; } }; /** * Map of Base64 characters to values. Used by {{#crossLink "Graphics/decodePath"}}{{/crossLink}}. * @property BASE_64 * @static * @final * @type {Object} **/ Graphics.BASE_64 = {"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"+":62,"/":63}; /** * Maps numeric values for the caps parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to * "butt", 1 to "round", and 2 to "square". * For example, to set the line caps to "square": * * myGraphics.ss(16, 2); * * @property STROKE_CAPS_MAP * @static * @final * @type {Array} **/ Graphics.STROKE_CAPS_MAP = ["butt", "round", "square"]; /** * Maps numeric values for the joints parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to * "miter", 1 to "round", and 2 to "bevel". * For example, to set the line joints to "bevel": * myGraphics.ss(16, 0, 2); * * @property STROKE_JOINTS_MAP * @static * @final * @type {Array} **/ Graphics.STROKE_JOINTS_MAP = ["miter", "round", "bevel"]; /** * @property _ctx * @static * @protected * @type {CanvasRenderingContext2D} **/ Graphics._ctx = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas")).getContext("2d"); /** * @property beginCmd * @static * @protected * @type {Command} **/ Graphics.beginCmd = new Command(Graphics._ctx.beginPath, [], false); /** * @property fillCmd * @static * @protected * @type {Command} **/ Graphics.fillCmd = new Command(Graphics._ctx.fill, [], false); /** * @property strokeCmd * @static * @protected * @type {Command} **/ Graphics.strokeCmd = new Command(Graphics._ctx.stroke, [], false); // public properties // private properties /** * @property _strokeInstructions * @protected * @type {Array} **/ p._strokeInstructions = null; /** * @property _strokeStyleInstructions * @protected * @type {Array} **/ p._strokeStyleInstructions = null; /** * @property _ignoreScaleStroke * @protected * @type Boolean **/ p._ignoreScaleStroke = false; /** * @property _fillInstructions * @protected * @type {Array} **/ p._fillInstructions = null; /** * @property _instructions * @protected * @type {Array} **/ p._instructions = null; /** * @property _oldInstructions * @protected * @type {Array} **/ p._oldInstructions = null; /** * @property _activeInstructions * @protected * @type {Array} **/ p._activeInstructions = null; /** * @property _active * @protected * @type {Boolean} * @default false **/ p._active = false; /** * @property _dirty * @protected * @type {Boolean} * @default false **/ p._dirty = false; /** * Initialization method. * @method initialize * @protected **/ p.initialize = function() { this.clear(); this._ctx = Graphics._ctx; }; /** * Returns true if this Graphics instance has no drawing commands. * @method isEmpty * @return {Boolean} Returns true if this Graphics instance has no drawing commands. **/ p.isEmpty = function() { return !(this._instructions.length || this._oldInstructions.length || this._activeInstructions.length); }; /** * Draws the display object into the specified context ignoring it's visible, alpha, shadow, and transform. * Returns true if the draw was handled (useful for overriding functionality). * * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. * @method draw * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. **/ p.draw = function(ctx) { if (this._dirty) { this._updateInstructions(); } var instr = this._instructions; for (var i=0, l=instr.length; i * whatwg spec. * @method lineTo * @param {Number} x The x coordinate the drawing point should draw to. * @param {Number} y The y coordinate the drawing point should draw to. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.lineTo = function(x, y) { this._dirty = this._active = true; this._activeInstructions.push(new Command(this._ctx.lineTo, [x, y])); return this; }; /** * Draws an arc with the specified control points and radius. For detailed information, read the * * whatwg spec. * @method arcTo * @param {Number} x1 * @param {Number} y1 * @param {Number} x2 * @param {Number} y2 * @param {Number} radius * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.arcTo = function(x1, y1, x2, y2, radius) { this._dirty = this._active = true; this._activeInstructions.push(new Command(this._ctx.arcTo, [x1, y1, x2, y2, radius])); return this; }; /** * Draws an arc defined by the radius, startAngle and endAngle arguments, centered at the position (x, y). For * example, to draw a full circle with a radius of 20 centered at (100, 100): * * arc(100, 100, 20, 0, Math.PI*2); * * For detailed information, read the * whatwg spec. * @method arc * @param {Number} x * @param {Number} y * @param {Number} radius * @param {Number} startAngle Measured in radians. * @param {Number} endAngle Measured in radians. * @param {Boolean} anticlockwise * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) { this._dirty = this._active = true; if (anticlockwise == null) { anticlockwise = false; } this._activeInstructions.push(new Command(this._ctx.arc, [x, y, radius, startAngle, endAngle, anticlockwise])); return this; }; /** * Draws a quadratic curve from the current drawing point to (x, y) using the control point (cpx, cpy). For detailed * information, read the * whatwg spec. * @method quadraticCurveTo * @param {Number} cpx * @param {Number} cpy * @param {Number} x * @param {Number} y * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.quadraticCurveTo = function(cpx, cpy, x, y) { this._dirty = this._active = true; this._activeInstructions.push(new Command(this._ctx.quadraticCurveTo, [cpx, cpy, x, y])); return this; }; /** * Draws a bezier curve from the current drawing point to (x, y) using the control points (cp1x, cp1y) and (cp2x, * cp2y). For detailed information, read the * * whatwg spec. * @method bezierCurveTo * @param {Number} cp1x * @param {Number} cp1y * @param {Number} cp2x * @param {Number} cp2y * @param {Number} x * @param {Number} y * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.bezierCurveTo = function(cp1x, cp1y, cp2x, cp2y, x, y) { this._dirty = this._active = true; this._activeInstructions.push(new Command(this._ctx.bezierCurveTo, [cp1x, cp1y, cp2x, cp2y, x, y])); return this; }; /** * Draws a rectangle at (x, y) with the specified width and height using the current fill and/or stroke. * For detailed information, read the * * whatwg spec. * @method rect * @param {Number} x * @param {Number} y * @param {Number} w Width of the rectangle * @param {Number} h Height of the rectangle * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.rect = function(x, y, w, h) { this._dirty = this._active = true; this._activeInstructions.push(new Command(this._ctx.rect, [x, y, w, h])); return this; }; /** * Closes the current path, effectively drawing a line from the current drawing point to the first drawing point specified * since the fill or stroke was last set. * @method closePath * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.closePath = function() { if (this._active) { this._dirty = true; this._activeInstructions.push(new Command(this._ctx.closePath, [])); } return this; }; // public methods that roughly map to Flash graphics APIs: /** * Clears all drawing instructions, effectively resetting this Graphics instance. * @method clear * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.clear = function() { this._instructions = []; this._oldInstructions = []; this._activeInstructions = []; this._strokeStyleInstructions = this._strokeInstructions = this._fillInstructions = null; this._active = this._dirty = false; return this; }; /** * Begins a fill with the specified color. This ends the current sub-path. * @method beginFill * @param {String} color A CSS compatible color value (ex. "red", "#FF0000", or "rgba(255,0,0,0.5)"). Setting to * null will result in no fill. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.beginFill = function(color) { if (this._active) { this._newPath(); } this._fillInstructions = color ? [new Command(this._setProp, ["fillStyle", color], false), Graphics.fillCmd] : null; return this; }; /** * Begins a linear gradient fill defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a square to display it: * * myGraphics.beginLinearGradientFill(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120); * * @method beginLinearGradientFill * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define a gradient * drawing from red to blue. * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, 0.9] would draw * the first color to 10% then interpolating to the second color at 90%. * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.beginLinearGradientFill = function(colors, ratios, x0, y0, x1, y1) { if (this._active) { this._newPath(); } var o = this._ctx.createLinearGradient(x0, y0, x1, y1); for (var i=0, l=colors.length; ibeginFill(null). * @method endFill * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.endFill = function() { return this.beginFill(); }; /** * Sets the stroke style for the current sub-path. Like all drawing methods, this can be chained, so you can define * the stroke style and color in a single line of code like so: * * myGraphics.setStrokeStyle(8,"round").beginStroke("#F00"); * * @method setStrokeStyle * @param {Number} thickness The width of the stroke. * @param {String | Number} [caps=0] Indicates the type of caps to use at the end of lines. One of butt, * round, or square. Defaults to "butt". Also accepts the values 0 (butt), 1 (round), and 2 (square) for use with * the tiny API. * @param {String | Number} [joints=0] Specifies the type of joints that should be used where two lines meet. * One of bevel, round, or miter. Defaults to "miter". Also accepts the values 0 (miter), 1 (round), and 2 (bevel) * for use with the tiny API. * @param {Number} [miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which * controls at what point a mitered joint will be clipped. * @param {Boolean} [ignoreScale=false] If true, the stroke will be drawn at the specified thickness regardless * of active transformations. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.setStrokeStyle = function(thickness, caps, joints, miterLimit, ignoreScale) { if (this._active) { this._newPath(); } this._strokeStyleInstructions = [ new Command(this._setProp, ["lineWidth", (thickness == null ? "1" : thickness)], false), new Command(this._setProp, ["lineCap", (caps == null ? "butt" : (isNaN(caps) ? caps : Graphics.STROKE_CAPS_MAP[caps]))], false), new Command(this._setProp, ["lineJoin", (joints == null ? "miter" : (isNaN(joints) ? joints : Graphics.STROKE_JOINTS_MAP[joints]))], false), new Command(this._setProp, ["miterLimit", (miterLimit == null ? "10" : miterLimit)], false) ]; this._ignoreScaleStroke = ignoreScale; return this; }; /** * Begins a stroke with the specified color. This ends the current sub-path. * @method beginStroke * @param {String} color A CSS compatible color value (ex. "#FF0000", "red", or "rgba(255,0,0,0.5)"). Setting to * null will result in no stroke. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.beginStroke = function(color) { if (this._active) { this._newPath(); } this._strokeInstructions = color ? [new Command(this._setProp, ["strokeStyle", color], false)] : null; return this; }; /** * Begins a linear gradient stroke defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a * square to display it: * * myGraphics.setStrokeStyle(10).beginLinearGradientStroke(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120); * * @method beginLinearGradientStroke * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define * a gradient drawing from red to blue. * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, * 0.9] would draw the first color to 10% then interpolating to the second color at 90%. * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.beginLinearGradientStroke = function(colors, ratios, x0, y0, x1, y1) { if (this._active) { this._newPath(); } var o = this._ctx.createLinearGradient(x0, y0, x1, y1); for (var i=0, l=colors.length; ibeginStroke(null). * @method endStroke * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.endStroke = function() { this.beginStroke(); return this; }; /** * Maps the familiar ActionScript curveTo() method to the functionally similar {{#crossLink "Graphics/quadraticCurveTo"}}{{/crossLink}} * method. * @method curveTo * @type {Function} **/ p.curveTo = p.quadraticCurveTo; /** * Maps the familiar ActionScript drawRect() method to the functionally similar {{#crossLink "Graphics/rect"}}{{/crossLink}} * method. * @method drawRect * @type {Function} **/ p.drawRect = p.rect; /** * Draws a rounded rectangle with all corners with the specified radius. * @method drawRoundRect * @param {Number} x * @param {Number} y * @param {Number} w * @param {Number} h * @param {Number} radius Corner radius. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.drawRoundRect = function(x, y, w, h, radius) { this.drawRoundRectComplex(x, y, w, h, radius, radius, radius, radius); return this; }; /** * Draws a rounded rectangle with different corner radii. Supports positive and negative corner radii. * @method drawRoundRectComplex * @param {Number} x * @param {Number} y * @param {Number} w * @param {Number} h * @param {Number} radiusTL Top left corner radius. * @param {Number} radiusTR Top right corner radius. * @param {Number} radiusBR Bottom right corner radius. * @param {Number} radiusBL Bottom left corner radius. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.drawRoundRectComplex = function(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL) { var max = (w max) { radiusTL = max; } if (radiusTR < 0) { radiusTR *= (mTR=-1); } if (radiusTR > max) { radiusTR = max; } if (radiusBR < 0) { radiusBR *= (mBR=-1); } if (radiusBR > max) { radiusBR = max; } if (radiusBL < 0) { radiusBL *= (mBL=-1); } if (radiusBL > max) { radiusBL = max; } this._dirty = this._active = true; var arcTo=this._ctx.arcTo, lineTo=this._ctx.lineTo; this._activeInstructions.push( new Command(this._ctx.moveTo, [x+w-radiusTR, y]), new Command(arcTo, [x+w+radiusTR*mTR, y-radiusTR*mTR, x+w, y+radiusTR, radiusTR]), new Command(lineTo, [x+w, y+h-radiusBR]), new Command(arcTo, [x+w+radiusBR*mBR, y+h+radiusBR*mBR, x+w-radiusBR, y+h, radiusBR]), new Command(lineTo, [x+radiusBL, y+h]), new Command(arcTo, [x-radiusBL*mBL, y+h+radiusBL*mBL, x, y+h-radiusBL, radiusBL]), new Command(lineTo, [x, y+radiusTL]), new Command(arcTo, [x-radiusTL*mTL, y-radiusTL*mTL, x+radiusTL, y, radiusTL]), new Command(this._ctx.closePath) ); return this; }; /** * Draws a circle with the specified radius at (x, y). * * var g = new Graphics(); * g.setStrokeStyle(1); * g.beginStroke(Graphics.getRGB(0,0,0)); * g.beginFill(Graphics.getRGB(255,0,0)); * g.drawCircle(0,0,3); * * var s = new Shape(g); * s.x = 100; * s.y = 100; * * stage.addChild(s); * stage.update(); * * @method drawCircle * @param {Number} x x coordinate center point of circle. * @param {Number} y y coordinate center point of circle. * @param {Number} radius Radius of circle. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.drawCircle = function(x, y, radius) { this.arc(x, y, radius, 0, Math.PI*2); return this; }; /** * Draws an ellipse (oval) with a specified width (w) and height (h). Similar to {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}, * except the width and height can be different. * @method drawEllipse * @param {Number} x x coordinate center point of ellipse. * @param {Number} y y coordinate center point of ellipse. * @param {Number} w height (horizontal diameter) of ellipse. The horizontal radius will be half of this number. * @param {Number} h width (vertical diameter) of ellipse. The vertical radius will be half of this number. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.drawEllipse = function(x, y, w, h) { this._dirty = this._active = true; var k = 0.5522848; var ox = (w / 2) * k; var oy = (h / 2) * k; var xe = x + w; var ye = y + h; var xm = x + w / 2; var ym = y + h / 2; this._activeInstructions.push( new Command(this._ctx.moveTo, [x, ym]), new Command(this._ctx.bezierCurveTo, [x, ym-oy, xm-ox, y, xm, y]), new Command(this._ctx.bezierCurveTo, [xm+ox, y, xe, ym-oy, xe, ym]), new Command(this._ctx.bezierCurveTo, [xe, ym+oy, xm+ox, ye, xm, ye]), new Command(this._ctx.bezierCurveTo, [xm-ox, ye, x, ym+oy, x, ym]) ); return this; }; /** * Draws a star if pointSize is greater than 0, or a regular polygon if pointSize is 0 with the specified number of * points. For example, the following code will draw a familiar 5 pointed star shape centered at 100, 100 and with a * radius of 50: * myGraphics.beginFill("#FF0").drawPolyStar(100, 100, 50, 5, 0.6, -90); * // Note: -90 makes the first point vertical * * @method drawPolyStar * @param {Number} x Position of the center of the shape. * @param {Number} y Position of the center of the shape. * @param {Number} radius The outer radius of the shape. * @param {Number} sides The number of points on the star or sides on the polygon. * @param {Number} pointSize The depth or "pointy-ness" of the star points. A pointSize of 0 will draw a regular * polygon (no points), a pointSize of 1 will draw nothing because the points are infinitely pointy. * @param {Number} angle The angle of the first point / corner. For example a value of 0 will draw the first point * directly to the right of the center. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.drawPolyStar = function(x, y, radius, sides, pointSize, angle) { this._dirty = this._active = true; if (pointSize == null) { pointSize = 0; } pointSize = 1-pointSize; if (angle == null) { angle = 0; } else { angle /= 180/Math.PI; } var a = Math.PI/sides; this._activeInstructions.push(new Command(this._ctx.moveTo, [x+Math.cos(angle)*radius, y+Math.sin(angle)*radius])); for (var i=0; iA - bits 000000. First 3 bits (000) indicate a moveTo operation. 4th bit (0) indicates 2 chars per parameter. *
n0 - 110111011100. Absolute x position of -150.0px. First bit indicates a negative value, remaining bits indicate 1500 tenths of a pixel. *
AA - 000000000000. Absolute y position of 0. *
I - 001100. First 3 bits (001) indicate a lineTo operation. 4th bit (1) indicates 3 chars per parameter. *
Au4 - 000000101110111000. An x delta of 300.0px, which is added to the previous x value of -150.0px to provide an absolute position of +150.0px. *
AAA - 000000000000000000. A y delta value of 0. * * @method decodePath * @param {String} str The path string to decode. * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) **/ p.decodePath = function(str) { var instructions = [this.moveTo, this.lineTo, this.quadraticCurveTo, this.bezierCurveTo, this.closePath]; var paramCount = [2, 2, 4, 6, 0]; var i=0, l=str.length; var params = []; var x=0, y=0; var base64 = Graphics.BASE_64; while (i>3; // highest order bits 1-3 code for operation. var f = instructions[fi]; // check that we have a valid instruction & that the unused bits are empty: if (!f || (n&3)) { throw("bad path data (@"+i+"): "+c); } var pl = paramCount[fi]; if (!fi) { x=y=0; } // move operations reset the position. params.length = 0; i++; var charCount = (n>>2&1)+2; // 4th header bit indicates number size for this operation. for (var p=0; p>5) ? -1 : 1; num = ((num&31)<<6)|(base64[str.charAt(i+1)]); if (charCount == 3) { num = (num<<6)|(base64[str.charAt(i+2)]); } num = sign*num/10; if (p%2) { x = (num += x); } else { y = (num += y); } params[p] = num; i += charCount; } f.apply(this,params); } return this; }; /** * Returns a clone of this Graphics instance. * @method clone * @return {Graphics} A clone of the current Graphics instance. **/ p.clone = function() { var o = new Graphics(); o._instructions = this._instructions.slice(); o._activeInstructions = this._activeInstructions.slice(); o._oldInstructions = this._oldInstructions.slice(); if (this._fillInstructions) { o._fillInstructions = this._fillInstructions.slice(); } if (this._strokeInstructions) { o._strokeInstructions = this._strokeInstructions.slice(); } if (this._strokeStyleInstructions) { o._strokeStyleInstructions = this._strokeStyleInstructions.slice(); } o._active = this._active; o._dirty = this._dirty; return o; }; /** * Returns a string representation of this object. * @method toString * @return {String} a string representation of the instance. **/ p.toString = function() { return "[Graphics]"; }; // tiny API: /** Shortcut to moveTo. * @method mt * @protected * @type {Function} **/ p.mt = p.moveTo; /** Shortcut to lineTo. * @method lt * @protected * @type {Function} **/ p.lt = p.lineTo; /** Shortcut to arcTo. * @method at * @protected * @type {Function} **/ p.at = p.arcTo; /** Shortcut to bezierCurveTo. * @method bt * @protected * @type {Function} **/ p.bt = p.bezierCurveTo; /** Shortcut to quadraticCurveTo / curveTo. * @method qt * @protected * @type {Function} **/ p.qt = p.quadraticCurveTo; /** Shortcut to arc. * @method a * @protected * @type {Function} **/ p.a = p.arc; /** Shortcut to rect. * @method r * @protected * @type {Function} **/ p.r = p.rect; /** Shortcut to closePath. * @method cp * @protected * @type {Function} **/ p.cp = p.closePath; /** Shortcut to clear. * @method c * @protected * @type {Function} **/ p.c = p.clear; /** Shortcut to beginFill. * @method f * @protected * @type {Function} **/ p.f = p.beginFill; /** Shortcut to beginLinearGradientFill. * @method lf * @protected * @type {Function} **/ p.lf = p.beginLinearGradientFill; /** Shortcut to beginRadialGradientFill. * @method rf * @protected * @type {Function} **/ p.rf = p.beginRadialGradientFill; /** Shortcut to beginBitmapFill. * @method bf * @protected * @type {Function} **/ p.bf = p.beginBitmapFill; /** Shortcut to endFill. * @method ef * @protected * @type {Function} **/ p.ef = p.endFill; /** Shortcut to setStrokeStyle. * @method ss * @protected * @type {Function} **/ p.ss = p.setStrokeStyle; /** Shortcut to beginStroke. * @method s * @protected * @type {Function} **/ p.s = p.beginStroke; /** Shortcut to beginLinearGradientStroke. * @method ls * @protected * @type {Function} **/ p.ls = p.beginLinearGradientStroke; /** Shortcut to beginRadialGradientStroke. * @method rs * @protected * @type {Function} **/ p.rs = p.beginRadialGradientStroke; /** Shortcut to beginBitmapStroke. * @method bs * @protected * @type {Function} **/ p.bs = p.beginBitmapStroke; /** Shortcut to endStroke. * @method es * @protected * @type {Function} **/ p.es = p.endStroke; /** Shortcut to drawRect. * @method dr * @protected * @type {Function} **/ p.dr = p.drawRect; /** Shortcut to drawRoundRect. * @method rr * @protected * @type {Function} **/ p.rr = p.drawRoundRect; /** Shortcut to drawRoundRectComplex. * @method rc * @protected * @type {Function} **/ p.rc = p.drawRoundRectComplex; /** Shortcut to drawCircle. * @method dc * @protected * @type {Function} **/ p.dc = p.drawCircle; /** Shortcut to drawEllipse. * @method de * @protected * @type {Function} **/ p.de = p.drawEllipse; /** Shortcut to drawPolyStar. * @method dp * @protected * @type {Function} **/ p.dp = p.drawPolyStar; /** Shortcut to decodePath. * @method p * @protected * t@ype Function **/ p.p = p.decodePath; // private methods: /** * @method _updateInstructions * @protected **/ p._updateInstructions = function() { this._instructions = this._oldInstructions.slice(); this._instructions.push(Graphics.beginCmd); this._instructions.push.apply(this._instructions, this._activeInstructions); if (this._fillInstructions) { this._instructions.push.apply(this._instructions, this._fillInstructions); } if (this._strokeInstructions) { if (this._strokeStyleInstructions) { this._instructions.push.apply(this._instructions, this._strokeStyleInstructions); } this._instructions.push.apply(this._instructions, this._strokeInstructions); if (this._ignoreScaleStroke) { this._instructions.push( new Command(this._ctx.save, [], false), new Command(this._ctx.setTransform, [1,0,0,1,0,0], false), Graphics.strokeCmd, new Command(this._ctx.restore, [], false) ); } else { this._instructions.push(Graphics.strokeCmd); } } }; /** * @method _newPath * @protected **/ p._newPath = function() { if (this._dirty) { this._updateInstructions(); } this._oldInstructions = this._instructions; this._activeInstructions = []; this._active = this._dirty = false; }; // used to create Commands that set properties: /** * Used to create Commands that set properties * @method _setProp * @param {String} name * @param {String} value * @protected **/ p._setProp = function(name, value) { this[name] = value; }; createjs.Graphics = Graphics; }());