Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojox.gfx.canvas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojox.gfx.canvas"] = true;dojo.provide("dojox.gfx.canvas");dojo.require("dojox.gfx._base");dojo.require("dojox.gfx.shape");dojo.require("dojox.gfx.path");dojo.require("dojox.gfx.arc");dojo.require("dojox.gfx.decompose");dojo.experimental("dojox.gfx.canvas");(function(){var g = dojox.gfx, gs = g.shape, ga = g.arc,m = g.matrix, mp = m.multiplyPoint, twoPI = 2 * Math.PI;dojo.extend(g.Shape, {render: function(/* Object */ ctx){// summary: render the shapectx.save();this._renderTransform(ctx);this._renderShape(ctx);this._renderFill(ctx, true);this._renderStroke(ctx, true);ctx.restore();},_renderTransform: function(/* Object */ ctx){if("canvasTransform" in this){var t = this.canvasTransform;ctx.translate(t.dx, t.dy);ctx.rotate(t.angle2);ctx.scale(t.sx, t.sy);ctx.rotate(t.angle1);// The future implementation when vendors catch up with the spec:// var t = this.matrix;// ctx.transform(t.xx, t.yx, t.xy, t.yy, t.dx, t.dy);}},_renderShape: function(/* Object */ ctx){// nothing},_renderFill: function(/* Object */ ctx, /* Boolean */ apply){if("canvasFill" in this){if("canvasFillImage" in this){this.canvasFill = ctx.createPattern(this.canvasFillImage, "repeat");delete this.canvasFillImage;}ctx.fillStyle = this.canvasFill;if(apply){ ctx.fill(); }}else{ctx.fillStyle = "rgba(0,0,0,0.0)";}},_renderStroke: function(/* Object */ ctx, /* Boolean */ apply){var s = this.strokeStyle;if(s){ctx.strokeStyle = s.color.toString();ctx.lineWidth = s.width;ctx.lineCap = s.cap;if(typeof s.join == "number"){ctx.lineJoin = "miter";ctx.miterLimit = s.join;}else{ctx.lineJoin = s.join;}if(apply){ ctx.stroke(); }}else if(!apply){ctx.strokeStyle = "rgba(0,0,0,0.0)";}},// events are not implementedgetEventSource: function(){ return null; },connect: function(){},disconnect: function(){}});var modifyMethod = function(shape, method, extra){var old = shape.prototype[method];shape.prototype[method] = extra ?function(){this.surface.makeDirty();old.apply(this, arguments);extra.call(this);return this;} :function(){this.surface.makeDirty();return old.apply(this, arguments);};};modifyMethod(g.Shape, "setTransform",function(){// prepare Canvas-specific structuresif(this.matrix){this.canvasTransform = g.decompose(this.matrix);}else{delete this.canvasTransform;}});modifyMethod(g.Shape, "setFill",function(){// prepare Canvas-specific structuresvar fs = this.fillStyle, f;if(fs){if(typeof(fs) == "object" && "type" in fs){var ctx = this.surface.rawNode.getContext("2d");switch(fs.type){case "linear":case "radial":f = fs.type == "linear" ?ctx.createLinearGradient(fs.x1, fs.y1, fs.x2, fs.y2) :ctx.createRadialGradient(fs.cx, fs.cy, 0, fs.cx, fs.cy, fs.r);dojo.forEach(fs.colors, function(step){f.addColorStop(step.offset, g.normalizeColor(step.color).toString());});break;case "pattern":var img = new Image(fs.width, fs.height);this.surface.downloadImage(img, fs.src);this.canvasFillImage = img;}}else{// Set fill color using CSS RGBA func stylef = fs.toString();}this.canvasFill = f;}else{delete this.canvasFill;}});modifyMethod(g.Shape, "setStroke");modifyMethod(g.Shape, "setShape");dojo.declare("dojox.gfx.Group", g.Shape, {// summary: a group shape (Canvas), which can be used// to logically group shapes (e.g, to propagate matricies)constructor: function(){gs.Container._init.call(this);},render: function(/* Object */ ctx){// summary: render the groupctx.save();this._renderTransform(ctx);this._renderFill(ctx);this._renderStroke(ctx);for(var i = 0; i < this.children.length; ++i){this.children[i].render(ctx);}ctx.restore();}});dojo.declare("dojox.gfx.Rect", gs.Rect, {// summary: a rectangle shape (Canvas)_renderShape: function(/* Object */ ctx){var s = this.shape, r = Math.min(s.r, s.height / 2, s.width / 2),xl = s.x, xr = xl + s.width, yt = s.y, yb = yt + s.height,xl2 = xl + r, xr2 = xr - r, yt2 = yt + r, yb2 = yb - r;ctx.beginPath();ctx.moveTo(xl2, yt);ctx.lineTo(xr2, yt);if(r){ ctx.arcTo(xr, yt, xr, yt2, r); }ctx.lineTo(xr, yb2);if(r){ ctx.arcTo(xr, yb, xr2, yb, r); }ctx.lineTo(xl2, yb);if(r){ ctx.arcTo(xl, yb, xl, yb2, r); }ctx.lineTo(xl, yt2);if(r){ ctx.arcTo(xl, yt, xl2, yt, r); }ctx.closePath();}});var bezierCircle = [];(function(){var u = ga.curvePI4;bezierCircle.push(u.s, u.c1, u.c2, u.e);for(var a = 45; a < 360; a += 45){var r = m.rotateg(a);bezierCircle.push(mp(r, u.c1), mp(r, u.c2), mp(r, u.e));}})();dojo.declare("dojox.gfx.Ellipse", gs.Ellipse, {// summary: an ellipse shape (Canvas)setShape: function(){g.Ellipse.superclass.setShape.apply(this, arguments);// prepare Canvas-specific structuresvar s = this.shape, t, c1, c2, r = [],M = m.normalize([m.translate(s.cx, s.cy), m.scale(s.rx, s.ry)]);t = mp(M, bezierCircle[0]);r.push([t.x, t.y]);for(var i = 1; i < bezierCircle.length; i += 3){c1 = mp(M, bezierCircle[i]);c2 = mp(M, bezierCircle[i + 1]);t = mp(M, bezierCircle[i + 2]);r.push([c1.x, c1.y, c2.x, c2.y, t.x, t.y]);}this.canvasEllipse = r;return this;},_renderShape: function(/* Object */ ctx){var r = this.canvasEllipse;ctx.beginPath();ctx.moveTo.apply(ctx, r[0]);for(var i = 1; i < r.length; ++i){ctx.bezierCurveTo.apply(ctx, r[i]);}ctx.closePath();}});dojo.declare("dojox.gfx.Circle", gs.Circle, {// summary: a circle shape (Canvas)_renderShape: function(/* Object */ ctx){var s = this.shape;ctx.beginPath();ctx.arc(s.cx, s.cy, s.r, 0, twoPI, 1);}});dojo.declare("dojox.gfx.Line", gs.Line, {// summary: a line shape (Canvas)_renderShape: function(/* Object */ ctx){var s = this.shape;ctx.beginPath();ctx.moveTo(s.x1, s.y1);ctx.lineTo(s.x2, s.y2);}});dojo.declare("dojox.gfx.Polyline", gs.Polyline, {// summary: a polyline/polygon shape (Canvas)setShape: function(){g.Polyline.superclass.setShape.apply(this, arguments);// prepare Canvas-specific structuresvar p = this.shape.points, f = p[0], r = [], c, i;if(p.length){if(typeof f == "number"){r.push(f, p[1]);i = 2;}else{r.push(f.x, f.y);i = 1;}for(; i < p.length; ++i){c = p[i];if(typeof c == "number"){r.push(c, p[++i]);}else{r.push(c.x, c.y);}}}this.canvasPolyline = r;return this;},_renderShape: function(/* Object */ ctx){var p = this.canvasPolyline;if(p.length){ctx.beginPath();ctx.moveTo(p[0], p[1]);for(var i = 2; i < p.length; i += 2){ctx.lineTo(p[i], p[i + 1]);}}}});dojo.declare("dojox.gfx.Image", gs.Image, {// summary: an image shape (Canvas)setShape: function(){g.Image.superclass.setShape.apply(this, arguments);// prepare Canvas-specific structuresvar img = new Image();this.surface.downloadImage(img, this.shape.src);this.canvasImage = img;return this;},_renderShape: function(/* Object */ ctx){var s = this.shape;ctx.drawImage(this.canvasImage, s.x, s.y, s.width, s.height);}});dojo.declare("dojox.gfx.Text", gs.Text, {// summary: a text shape (Canvas)_renderShape: function(/* Object */ ctx){var s = this.shape;// nothing for the moment}});modifyMethod(g.Text, "setFont");var pathRenderers = {M: "_moveToA", m: "_moveToR",L: "_lineToA", l: "_lineToR",H: "_hLineToA", h: "_hLineToR",V: "_vLineToA", v: "_vLineToR",C: "_curveToA", c: "_curveToR",S: "_smoothCurveToA", s: "_smoothCurveToR",Q: "_qCurveToA", q: "_qCurveToR",T: "_qSmoothCurveToA", t: "_qSmoothCurveToR",A: "_arcTo", a: "_arcTo",Z: "_closePath", z: "_closePath"};dojo.declare("dojox.gfx.Path", g.path.Path, {// summary: a path shape (Canvas)constructor: function(){this.last = {};this.lastControl = {};},setShape: function(){this.canvasPath = [];return g.Path.superclass.setShape.apply(this, arguments);},_updateWithSegment: function(segment){var last = dojo.clone(this.last);this[pathRenderers[segment.action]](this.canvasPath, segment.action, segment.args);this.last = last;g.Path.superclass._updateWithSegment.apply(this, arguments);},_renderShape: function(/* Object */ ctx){var r = this.canvasPath;ctx.beginPath();for(var i = 0; i < r.length; i += 2){ctx[r[i]].apply(ctx, r[i + 1]);}},_moveToA: function(result, action, args){result.push("moveTo", [args[0], args[1]]);for(var i = 2; i < args.length; i += 2){result.push("lineTo", [args[i], args[i + 1]]);}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];this.lastControl = {};},_moveToR: function(result, action, args){if("x" in this.last){result.push("moveTo", [this.last.x += args[0], this.last.y += args[1]]);}else{result.push("moveTo", [this.last.x = args[0], this.last.y = args[1]]);}for(var i = 2; i < args.length; i += 2){result.push("lineTo", [this.last.x += args[i], this.last.y += args[i + 1]]);}this.lastControl = {};},_lineToA: function(result, action, args){for(var i = 0; i < args.length; i += 2){result.push("lineTo", [args[i], args[i + 1]]);}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];this.lastControl = {};},_lineToR: function(result, action, args){for(var i = 0; i < args.length; i += 2){result.push("lineTo", [this.last.x += args[i], this.last.y += args[i + 1]]);}this.lastControl = {};},_hLineToA: function(result, action, args){for(var i = 0; i < args.length; ++i){result.push("lineTo", [args[i], this.last.y]);}this.last.x = args[args.length - 1];this.lastControl = {};},_hLineToR: function(result, action, args){for(var i = 0; i < args.length; ++i){result.push("lineTo", [this.last.x += args[i], this.last.y]);}this.lastControl = {};},_vLineToA: function(result, action, args){for(var i = 0; i < args.length; ++i){result.push("lineTo", [this.last.x, args[i]]);}this.last.y = args[args.length - 1];this.lastControl = {};},_vLineToR: function(result, action, args){for(var i = 0; i < args.length; ++i){result.push("lineTo", [this.last.x, this.last.y += args[i]]);}this.lastControl = {};},_curveToA: function(result, action, args){for(var i = 0; i < args.length; i += 6){result.push("bezierCurveTo", args.slice(i, i + 6));}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];this.lastControl.x = args[args.length - 4];this.lastControl.y = args[args.length - 3];this.lastControl.type = "C";},_curveToR: function(result, action, args){for(var i = 0; i < args.length; i += 6){result.push("bezierCurveTo", [this.last.x + args[i],this.last.y + args[i + 1],this.lastControl.x = this.last.x + args[i + 2],this.lastControl.y = this.last.y + args[i + 3],this.last.x + args[i + 4],this.last.y + args[i + 5]]);this.last.x += args[i + 4];this.last.y += args[i + 5];}this.lastControl.type = "C";},_smoothCurveToA: function(result, action, args){for(var i = 0; i < args.length; i += 4){var valid = this.lastControl.type == "C";result.push("bezierCurveTo", [valid ? 2 * this.last.x - this.lastControl.x : this.last.x,valid ? 2 * this.last.y - this.lastControl.y : this.last.y,args[i],args[i + 1],args[i + 2],args[i + 3]]);this.lastControl.x = args[i];this.lastControl.y = args[i + 1];this.lastControl.type = "C";}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];},_smoothCurveToR: function(result, action, args){for(var i = 0; i < args.length; i += 4){var valid = this.lastControl.type == "C";result.push("bezierCurveTo", [valid ? 2 * this.last.x - this.lastControl.x : this.last.x,valid ? 2 * this.last.y - this.lastControl.y : this.last.y,this.last.x + args[i],this.last.y + args[i + 1],this.last.x + args[i + 2],this.last.y + args[i + 3]]);this.lastControl.x = this.last.x + args[i];this.lastControl.y = this.last.y + args[i + 1];this.lastControl.type = "C";this.last.x += args[i + 2];this.last.y += args[i + 3];}},_qCurveToA: function(result, action, args){for(var i = 0; i < args.length; i += 4){result.push("quadraticCurveTo", args.slice(i, i + 4));}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];this.lastControl.x = args[args.length - 4];this.lastControl.y = args[args.length - 3];this.lastControl.type = "Q";},_qCurveToR: function(result, action, args){for(var i = 0; i < args.length; i += 4){result.push("quadraticCurveTo", [this.lastControl.x = this.last.x + args[i],this.lastControl.y = this.last.y + args[i + 1],this.last.x + args[i + 2],this.last.y + args[i + 3]]);this.last.x += args[i + 2];this.last.y += args[i + 3];}this.lastControl.type = "Q";},_qSmoothCurveToA: function(result, action, args){for(var i = 0; i < args.length; i += 2){var valid = this.lastControl.type == "Q";result.push("quadraticCurveTo", [this.lastControl.x = valid ? 2 * this.last.x - this.lastControl.x : this.last.x,this.lastControl.y = valid ? 2 * this.last.y - this.lastControl.y : this.last.y,args[i],args[i + 1]]);this.lastControl.type = "Q";}this.last.x = args[args.length - 2];this.last.y = args[args.length - 1];},_qSmoothCurveToR: function(result, action, args){for(var i = 0; i < args.length; i += 2){var valid = this.lastControl.type == "Q";result.push("quadraticCurveTo", [this.lastControl.x = valid ? 2 * this.last.x - this.lastControl.x : this.last.x,this.lastControl.y = valid ? 2 * this.last.y - this.lastControl.y : this.last.y,this.last.x + args[i],this.last.y + args[i + 1]]);this.lastControl.type = "Q";this.last.x += args[i];this.last.y += args[i + 1];}},_arcTo: function(result, action, args){var relative = action == "a";for(var i = 0; i < args.length; i += 7){var x1 = args[i + 5], y1 = args[i + 6];if(relative){x1 += this.last.x;y1 += this.last.y;}var arcs = ga.arcAsBezier(this.last, args[i], args[i + 1], args[i + 2],args[i + 3] ? 1 : 0, args[i + 4] ? 1 : 0,x1, y1);dojo.forEach(arcs, function(p){result.push("bezierCurveTo", p);});this.last.x = x1;this.last.y = y1;}this.lastControl = {};},_closePath: function(result, action, args){result.push("closePath", []);this.lastControl = {};}});dojo.forEach(["moveTo", "lineTo", "hLineTo", "vLineTo", "curveTo","smoothCurveTo", "qCurveTo", "qSmoothCurveTo", "arcTo", "closePath"],function(method){ modifyMethod(g.Path, method); });dojo.declare("dojox.gfx.TextPath", g.path.TextPath, {// summary: a text shape (Canvas)_renderShape: function(/* Object */ ctx){var s = this.shape;// nothing for the moment}});dojo.declare("dojox.gfx.Surface", gs.Surface, {// summary: a surface object to be used for drawings (Canvas)constructor: function(){gs.Container._init.call(this);this.pendingImageCount = 0;this.makeDirty();},setDimensions: function(width, height){// summary: sets the width and height of the rawNode// width: String: width of surface, e.g., "100px"// height: String: height of surface, e.g., "100px"this.width = g.normalizedLength(width); // in pixelsthis.height = g.normalizedLength(height); // in pixelsif(!this.rawNode) return this;this.rawNode.width = width;this.rawNode.height = height;this.makeDirty();return this; // self},getDimensions: function(){// summary: returns an object with properties "width" and "height"return this.rawNode ? {width: this.rawNode.width, height: this.rawNode.height} : null; // Object},render: function(){// summary: render the all shapesif(this.pendingImageCount){ return; }var ctx = this.rawNode.getContext("2d");ctx.save();ctx.clearRect(0, 0, this.rawNode.width, this.rawNode.height);for(var i = 0; i < this.children.length; ++i){this.children[i].render(ctx);}ctx.restore();if("pendingRender" in this){clearTimeout(this.pendingRender);delete this.pendingRender;}},makeDirty: function(){// summary: internal method, which is called when we may need to redrawif(!this.pendingImagesCount && !("pendingRender" in this)){this.pendingRender = setTimeout(dojo.hitch(this, this.render), 0);}},downloadImage: function(img, url){// summary:// internal method, which starts an image download and renders, when it is ready// img: Image:// the image object// url: String:// the url of the imagevar handler = dojo.hitch(this, this.onImageLoad);if(!this.pendingImageCount++ && "pendingRender" in this){clearTimeout(this.pendingRender);delete this.pendingRender;}img.onload = handler;img.onerror = handler;img.onabort = handler;img.src = url;},onImageLoad: function(){if(!--this.pendingImageCount){ this.render(); }},// events are not implementedgetEventSource: function(){ return null; },connect: function(){},disconnect: function(){}});g.createSurface = function(parentNode, width, height){// summary: creates a surface (Canvas)// parentNode: Node: a parent node// width: String: width of surface, e.g., "100px"// height: String: height of surface, e.g., "100px"if(!width){ width = "100%"; }if(!height){ height = "100%"; }var s = new g.Surface(),p = dojo.byId(parentNode),c = p.ownerDocument.createElement("canvas");c.width = width;c.height = height;p.appendChild(c);s.rawNode = c;s.surface = s;return s; // dojox.gfx.Surface};// Extendersvar C = gs.Container, Container = {add: function(shape){this.surface.makeDirty();return C.add.apply(this, arguments);},remove: function(shape, silently){this.surface.makeDirty();return C.remove.apply(this, arguments);},clear: function(){this.surface.makeDirty();return C.clear.apply(this, arguments);},_moveChildToFront: function(shape){this.surface.makeDirty();return C._moveChildToFront.apply(this, arguments);},_moveChildToBack: function(shape){this.surface.makeDirty();return C._moveChildToBack.apply(this, arguments);}};dojo.mixin(gs.Creator, {// summary: Canvas shape creatorscreateObject: function(shapeType, rawShape) {// summary: creates an instance of the passed shapeType class// shapeType: Function: a class constructor to create an instance of// rawShape: Object: properties to be passed in to the classes "setShape" method// overrideSize: Boolean: set the size explicitly, if truevar shape = new shapeType();shape.surface = this.surface;shape.setShape(rawShape);this.add(shape);return shape; // dojox.gfx.Shape}});dojo.extend(g.Group, Container);dojo.extend(g.Group, gs.Creator);dojo.extend(g.Surface, Container);dojo.extend(g.Surface, gs.Creator);})();}