/* Copyright (c) 2004-2006, The Dojo Foundation All Rights Reserved. Licensed under the Academic Free License version 2.1 or above OR the modified BSD license. For more information on Dojo licensing, see: http://dojotoolkit.org/community/licensing.shtml */ dojo.provide("dojo.gfx.shape"); dojo.require("dojo.lang.declare"); dojo.require("dojo.gfx.common"); dojo.declare("dojo.gfx.Shape", null, { // summary: a Shape object, which knows how to apply // graphical attributes and transformations initializer: function(){ // rawNode: Node: underlying node this.rawNode = null; // shape: Object: an abstract shape object // (see dojo.gfx.defaultPath, // dojo.gfx.defaultPolyline, // dojo.gfx.defaultRect, // dojo.gfx.defaultEllipse, // dojo.gfx.defaultCircle, // dojo.gfx.defaultLine, // or dojo.gfx.defaultImage) this.shape = null; // matrix: dojo.gfx.matrix.Matrix: a transformation matrix this.matrix = null; // fillStyle: Object: a fill object // (see dojo.gfx.defaultLinearGradient, // dojo.gfx.defaultRadialGradient, // dojo.gfx.defaultPattern, // or dojo.gfx.color.Color) this.fillStyle = null; // strokeStyle: Object: a stroke object // (see dojo.gfx.defaultStroke) this.strokeStyle = null; // bbox: dojo.gfx.Rectangle: a bounding box of this shape // (see dojo.gfx.defaultRect) this.bbox = null; // virtual group structure // parent: Object: a parent or null // (see dojo.gfx.Surface, // dojo.gfx.shape.VirtualGroup, // or dojo.gfx.Group) this.parent = null; // parentMatrix: dojo.gfx.matrix.Matrix // a transformation matrix inherited from the parent this.parentMatrix = null; }, // trivial getters getNode: function(){ // summary: returns the current DOM Node or null return this.rawNode; // Node }, getShape: function(){ // summary: returns the current shape object or null // (see dojo.gfx.defaultPath, // dojo.gfx.defaultPolyline, // dojo.gfx.defaultRect, // dojo.gfx.defaultEllipse, // dojo.gfx.defaultCircle, // dojo.gfx.defaultLine, // or dojo.gfx.defaultImage) return this.shape; // Object }, getTransform: function(){ // summary: returns the current transformation matrix or null return this.matrix; // dojo.gfx.matrix.Matrix }, getFill: function(){ // summary: returns the current fill object or null // (see dojo.gfx.defaultLinearGradient, // dojo.gfx.defaultRadialGradient, // dojo.gfx.defaultPattern, // or dojo.gfx.color.Color) return this.fillStyle; // Object }, getStroke: function(){ // summary: returns the current stroke object or null // (see dojo.gfx.defaultStroke) return this.strokeStyle; // Object }, getParent: function(){ // summary: returns the parent or null // (see dojo.gfx.Surface, // dojo.gfx.shape.VirtualGroup, // or dojo.gfx.Group) return this.parent; // Object }, getBoundingBox: function(){ // summary: returns the bounding box or null // (see dojo.gfx.defaultRect) return this.bbox; // dojo.gfx.Rectangle }, getEventSource: function(){ // summary: returns a Node, which is used as // a source of events for this shape return this.rawNode; // Node }, // empty settings setShape: function(shape){ // summary: sets a shape object // (the default implementation simply ignores it) // shape: Object: a shape object // (see dojo.gfx.defaultPath, // dojo.gfx.defaultPolyline, // dojo.gfx.defaultRect, // dojo.gfx.defaultEllipse, // dojo.gfx.defaultCircle, // dojo.gfx.defaultLine, // or dojo.gfx.defaultImage) return this; // self }, setFill: function(fill){ // summary: sets a fill object // (the default implementation simply ignores it) // fill: Object: a fill object // (see dojo.gfx.defaultLinearGradient, // dojo.gfx.defaultRadialGradient, // dojo.gfx.defaultPattern, // or dojo.gfx.color.Color) return this; // self }, setStroke: function(stroke){ // summary: sets a stroke object // (the default implementation simply ignores it) // stroke: Object: a stroke object // (see dojo.gfx.defaultStroke) return this; // self }, // z-index moveToFront: function(){ // summary: moves a shape to front of its parent's list of shapes // (the default implementation does nothing) return this; // self }, moveToBack: function(){ // summary: moves a shape to back of its parent's list of shapes // (the default implementation does nothing) return this; }, setTransform: function(matrix){ // summary: sets a transformation matrix // matrix: dojo.gfx.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojo.gfx.matrix.Matrix // constructor for a list of acceptable arguments) this.matrix = dojo.gfx.matrix.clone(matrix ? dojo.gfx.matrix.normalize(matrix) : dojo.gfx.identity, true); return this._applyTransform(); // self }, // apply left & right transformation applyRightTransform: function(matrix){ // summary: multiplies the existing matrix with an argument on right side // (this.matrix * matrix) // matrix: dojo.gfx.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojo.gfx.matrix.Matrix // constructor for a list of acceptable arguments) return matrix ? this.setTransform([this.matrix, matrix]) : this; // self }, applyLeftTransform: function(matrix){ // summary: multiplies the existing matrix with an argument on left side // (matrix * this.matrix) // matrix: dojo.gfx.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojo.gfx.matrix.Matrix // constructor for a list of acceptable arguments) return matrix ? this.setTransform([matrix, this.matrix]) : this; // self }, applyTransform: function(matrix){ // summary: a shortcut for dojo.gfx.Shape.applyRight // matrix: dojo.gfx.matrix.Matrix: a matrix or a matrix-like object // (see an argument of dojo.gfx.matrix.Matrix // constructor for a list of acceptable arguments) return matrix ? this.setTransform([this.matrix, matrix]) : this; // self }, // virtual group methods remove: function(silently){ // summary: removes the shape from its parent's list of shapes // silently: Boolean?: if true, do not redraw a picture yet if(this.parent){ this.parent.remove(this, silently); } return this; // self }, _setParent: function(parent, matrix){ // summary: sets a parent // parent: Object: a parent or null // (see dojo.gfx.Surface, // dojo.gfx.shape.VirtualGroup, // or dojo.gfx.Group) // matrix: dojo.gfx.matrix.Matrix: // a 2D matrix or a matrix-like object this.parent = parent; return this._updateParentMatrix(matrix); // self }, _updateParentMatrix: function(matrix){ // summary: updates the parent matrix with new matrix // matrix: dojo.gfx.matrix.Matrix: // a 2D matrix or a matrix-like object this.parentMatrix = matrix ? dojo.gfx.matrix.clone(matrix) : null; return this._applyTransform(); // self }, _getRealMatrix: function(){ // summary: returns the cumulative ("real") transformation matrix // by combining the shape's matrix with its parent's matrix return this.parentMatrix ? new dojo.gfx.matrix.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix; // dojo.gfx.matrix.Matrix } }); dojo.declare("dojo.gfx.shape.VirtualGroup", dojo.gfx.Shape, { // summary: a virtual group of shapes, which can be used // as a foundation for renderer-specific groups, or as a way // to logically group shapes (e.g, to propagate matricies) initializer: function() { // children: Array: a list of children this.children = []; }, // group management add: function(shape){ // summary: adds a shape to the list // shape: dojo.gfx.Shape: a shape var oldParent = shape.getParent(); if(oldParent){ oldParent.remove(shape, true); } this.children.push(shape); return shape._setParent(this, this._getRealMatrix()); // self }, remove: function(shape, silently){ // summary: removes a shape from the list // silently: Boolean?: if true, do not redraw a picture yet for(var i = 0; i < this.children.length; ++i){ if(this.children[i] == shape){ if(silently){ // skip for now }else{ shape._setParent(null, null); } this.children.splice(i, 1); break; } } return this; // self }, // apply transformation _applyTransform: function(){ // summary: applies a transformation matrix to a group var matrix = this._getRealMatrix(); for(var i = 0; i < this.children.length; ++i){ this.children[i]._updateParentMatrix(matrix); } return this; // self } }); dojo.declare("dojo.gfx.shape.Rect", dojo.gfx.Shape, { // summary: a generic rectangle initializer: function(rawNode) { // summary: creates a rectangle // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultRect, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box (its shape in this case) return this.shape; // dojo.gfx.Rectangle } }); dojo.declare("dojo.gfx.shape.Ellipse", dojo.gfx.Shape, { // summary: a generic ellipse initializer: function(rawNode) { // summary: creates an ellipse // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultEllipse, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box if(!this.bbox){ var shape = this.shape; this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry, width: 2 * shape.rx, height: 2 * shape.ry}; } return this.bbox; // dojo.gfx.Rectangle } }); dojo.declare("dojo.gfx.shape.Circle", dojo.gfx.Shape, { // summary: a generic circle // (this is a helper object, which is defined for convinience) initializer: function(rawNode) { // summary: creates a circle // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultCircle, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box if(!this.bbox){ var shape = this.shape; this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r, width: 2 * shape.r, height: 2 * shape.r}; } return this.bbox; // dojo.gfx.Rectangle } }); dojo.declare("dojo.gfx.shape.Line", dojo.gfx.Shape, { // summary: a generic line // (this is a helper object, which is defined for convinience) initializer: function(rawNode) { // summary: creates a line // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultLine, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box if(!this.bbox){ var shape = this.shape; this.bbox = { x: Math.min(shape.x1, shape.x2), y: Math.min(shape.y1, shape.y2), width: Math.abs(shape.x2 - shape.x1), height: Math.abs(shape.y2 - shape.y1) }; } return this.bbox; // dojo.gfx.Rectangle } }); dojo.declare("dojo.gfx.shape.Polyline", dojo.gfx.Shape, { // summary: a generic polyline/polygon // (this is a helper object, which is defined for convinience) initializer: function(rawNode) { // summary: creates a line // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultPolyline, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box if(!this.bbox && this.shape.points.length){ var p = this.shape.points; var l = p.length; var t = p[0]; var bbox = {l: t.x, t: t.y, r: t.x, b: t.y}; for(var i = 1; i < l; ++i){ t = p[i]; if(bbox.l > t.x) bbox.l = t.x; if(bbox.r < t.x) bbox.r = t.x; if(bbox.t > t.y) bbox.t = t.y; if(bbox.b < t.y) bbox.b = t.y; } this.bbox = { x: bbox.l, y: bbox.t, width: bbox.r - bbox.l, height: bbox.b - bbox.t }; } return this.bbox; // dojo.gfx.Rectangle } }); dojo.declare("dojo.gfx.shape.Image", dojo.gfx.Shape, { // summary: a generic image // (this is a helper object, which is defined for convinience) initializer: function(rawNode) { // summary: creates an image // rawNode: Node: a DOM Node this.shape = dojo.lang.shallowCopy(dojo.gfx.defaultImage, true); this.attach(rawNode); }, getBoundingBox: function(){ // summary: returns the bounding box if(!this.bbox){ var shape = this.shape; this.bbox = { x: 0, y: 0, width: shape.width, height: shape.height }; } return this.bbox; // dojo.gfx.Rectangle } });