1 if(!dojo._hasResource["dojox.gfx.shape"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.gfx.shape"] = true;
3 dojo.provide("dojox.gfx.shape");
5 dojo.require("dojox.gfx._base");
7 dojo.declare("dojox.gfx.Shape", null, {
8 // summary: a Shape object, which knows how to apply
9 // graphical attributes and transformations
11 constructor: function(){
12 // rawNode: Node: underlying node
15 // shape: Object: an abstract shape object
16 // (see dojox.gfx.defaultPath,
17 // dojox.gfx.defaultPolyline,
18 // dojox.gfx.defaultRect,
19 // dojox.gfx.defaultEllipse,
20 // dojox.gfx.defaultCircle,
21 // dojox.gfx.defaultLine,
22 // or dojox.gfx.defaultImage)
25 // matrix: dojox.gfx.Matrix2D: a transformation matrix
28 // fillStyle: Object: a fill object
29 // (see dojox.gfx.defaultLinearGradient,
30 // dojox.gfx.defaultRadialGradient,
31 // dojox.gfx.defaultPattern,
33 this.fillStyle = null;
35 // strokeStyle: Object: a stroke object
36 // (see dojox.gfx.defaultStroke)
37 this.strokeStyle = null;
39 // bbox: dojox.gfx.Rectangle: a bounding box of this shape
40 // (see dojox.gfx.defaultRect)
43 // virtual group structure
45 // parent: Object: a parent or null
46 // (see dojox.gfx.Surface,
47 // dojox.gfx.shape.VirtualGroup,
48 // or dojox.gfx.Group)
51 // parentMatrix: dojox.gfx.Matrix2D
52 // a transformation matrix inherited from the parent
53 this.parentMatrix = null;
59 // summary: returns the current DOM Node or null
60 return this.rawNode; // Node
63 // summary: returns the current shape object or null
64 // (see dojox.gfx.defaultPath,
65 // dojox.gfx.defaultPolyline,
66 // dojox.gfx.defaultRect,
67 // dojox.gfx.defaultEllipse,
68 // dojox.gfx.defaultCircle,
69 // dojox.gfx.defaultLine,
70 // or dojox.gfx.defaultImage)
71 return this.shape; // Object
73 getTransform: function(){
74 // summary: returns the current transformation matrix or null
75 return this.matrix; // dojox.gfx.Matrix2D
78 // summary: returns the current fill object or null
79 // (see dojox.gfx.defaultLinearGradient,
80 // dojox.gfx.defaultRadialGradient,
81 // dojox.gfx.defaultPattern,
83 return this.fillStyle; // Object
85 getStroke: function(){
86 // summary: returns the current stroke object or null
87 // (see dojox.gfx.defaultStroke)
88 return this.strokeStyle; // Object
90 getParent: function(){
91 // summary: returns the parent or null
92 // (see dojox.gfx.Surface,
93 // dojox.gfx.shape.VirtualGroup,
94 // or dojox.gfx.Group)
95 return this.parent; // Object
97 getBoundingBox: function(){
98 // summary: returns the bounding box or null
99 // (see dojox.gfx.defaultRect)
100 return this.bbox; // dojox.gfx.Rectangle
102 getTransformedBoundingBox: function(){
103 // summary: returns an array of four points or null
104 // four points represent four corners of the untransformed bounding box
105 var b = this.getBoundingBox();
109 var m = this._getRealMatrix();
111 var g = dojox.gfx.matrix;
112 r.push(g.multiplyPoint(m, b.x, b.y));
113 r.push(g.multiplyPoint(m, b.x + b.width, b.y));
114 r.push(g.multiplyPoint(m, b.x + b.width, b.y + b.height));
115 r.push(g.multiplyPoint(m, b.x, b.y + b.height));
118 getEventSource: function(){
119 // summary: returns a Node, which is used as
120 // a source of events for this shape
122 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
124 return this.rawNode; // Node
129 setShape: function(shape){
130 // summary: sets a shape object
131 // (the default implementation simply ignores it)
132 // shape: Object: a shape object
133 // (see dojox.gfx.defaultPath,
134 // dojox.gfx.defaultPolyline,
135 // dojox.gfx.defaultRect,
136 // dojox.gfx.defaultEllipse,
137 // dojox.gfx.defaultCircle,
138 // dojox.gfx.defaultLine,
139 // or dojox.gfx.defaultImage)
141 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
143 this.shape = dojox.gfx.makeParameters(this.shape, shape);
147 setFill: function(fill){
148 // summary: sets a fill object
149 // (the default implementation simply ignores it)
150 // fill: Object: a fill object
151 // (see dojox.gfx.defaultLinearGradient,
152 // dojox.gfx.defaultRadialGradient,
153 // dojox.gfx.defaultPattern,
156 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
160 this.fillStyle = null;
164 if(typeof(fill) == "object" && "type" in fill){
165 // gradient or pattern
168 f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill);
171 f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
174 f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
179 f = dojox.gfx.normalizeColor(fill);
184 setStroke: function(stroke){
185 // summary: sets a stroke object
186 // (the default implementation simply ignores it)
187 // stroke: Object: a stroke object
188 // (see dojox.gfx.defaultStroke)
190 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
194 this.strokeStyle = null;
197 // normalize the stroke
198 if(typeof stroke == "string"){
199 stroke = {color: stroke};
201 var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke);
202 s.color = dojox.gfx.normalizeColor(s.color);
205 setTransform: function(matrix){
206 // summary: sets a transformation matrix
207 // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object
208 // (see an argument of dojox.gfx.Matrix2D
209 // constructor for a list of acceptable arguments)
211 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
213 this.matrix = dojox.gfx.matrix.clone(matrix ? dojox.gfx.matrix.normalize(matrix) : dojox.gfx.matrix.identity);
214 return this._applyTransform(); // self
217 _applyTransform: function(){
218 // summary: physically sets a matrix
220 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
227 moveToFront: function(){
228 // summary: moves a shape to front of its parent's list of shapes
229 var p = this.getParent();
231 p._moveChildToFront(this);
232 this._moveToFront(); // execute renderer-specific action
236 moveToBack: function(){
237 // summary: moves a shape to back of its parent's list of shapes
238 var p = this.getParent();
240 p._moveChildToBack(this);
241 this._moveToBack(); // execute renderer-specific action
245 _moveToFront: function(){
246 // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront()
248 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
250 _moveToBack: function(){
251 // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront()
253 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
256 // apply left & right transformation
258 applyRightTransform: function(matrix){
259 // summary: multiplies the existing matrix with an argument on right side
260 // (this.matrix * matrix)
261 // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object
262 // (see an argument of dojox.gfx.Matrix2D
263 // constructor for a list of acceptable arguments)
264 return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
266 applyLeftTransform: function(matrix){
267 // summary: multiplies the existing matrix with an argument on left side
268 // (matrix * this.matrix)
269 // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object
270 // (see an argument of dojox.gfx.Matrix2D
271 // constructor for a list of acceptable arguments)
272 return matrix ? this.setTransform([matrix, this.matrix]) : this; // self
274 applyTransform: function(matrix){
275 // summary: a shortcut for dojox.gfx.Shape.applyRightTransform
276 // matrix: dojox.gfx.Matrix2D: a matrix or a matrix-like object
277 // (see an argument of dojox.gfx.Matrix2D
278 // constructor for a list of acceptable arguments)
279 return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
282 // virtual group methods
284 removeShape: function(silently){
285 // summary: removes the shape from its parent's list of shapes
286 // silently: Boolean?: if true, do not redraw a picture yet
288 this.parent.remove(this, silently);
292 _setParent: function(parent, matrix){
293 // summary: sets a parent
294 // parent: Object: a parent or null
295 // (see dojox.gfx.Surface,
296 // dojox.gfx.shape.VirtualGroup,
297 // or dojox.gfx.Group)
298 // matrix: dojox.gfx.Matrix2D:
299 // a 2D matrix or a matrix-like object
300 this.parent = parent;
301 return this._updateParentMatrix(matrix); // self
303 _updateParentMatrix: function(matrix){
304 // summary: updates the parent matrix with new matrix
305 // matrix: dojox.gfx.Matrix2D:
306 // a 2D matrix or a matrix-like object
307 this.parentMatrix = matrix ? dojox.gfx.matrix.clone(matrix) : null;
308 return this._applyTransform(); // self
310 _getRealMatrix: function(){
311 // summary: returns the cumulative ("real") transformation matrix
312 // by combining the shape's matrix with its parent's matrix
317 m = dojox.gfx.matrix.multiply(p.matrix, m);
321 return m; // dojox.gfx.Matrix2D
325 dojox.gfx.shape._eventsProcessing = {
326 connect: function(name, object, method){
327 // summary: connects a handler to an event on this shape
329 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
331 return arguments.length > 2 ? // Object
332 dojo.connect(this.getEventSource(), name, object, method) :
333 dojo.connect(this.getEventSource(), name, object);
335 disconnect: function(token){
336 // summary: connects a handler by token from an event on this shape
338 // COULD BE RE-IMPLEMENTED BY THE RENDERER!
340 dojo.disconnect(token);
344 dojo.extend(dojox.gfx.Shape, dojox.gfx.shape._eventsProcessing);
346 dojox.gfx.shape.Container = {
347 // summary: a container of shapes, which can be used
348 // as a foundation for renderer-specific groups, or as a way
349 // to logically group shapes (e.g, to propagate matricies)
352 // children: Array: a list of children
358 add: function(shape){
359 // summary: adds a shape to the list
360 // shape: dojox.gfx.Shape: a shape
361 var oldParent = shape.getParent();
363 oldParent.remove(shape, true);
365 this.children.push(shape);
366 return shape._setParent(this, this._getRealMatrix()); // self
368 remove: function(shape, silently){
369 // summary: removes a shape from the list
370 // silently: Boolean?: if true, do not redraw a picture yet
371 for(var i = 0; i < this.children.length; ++i){
372 if(this.children[i] == shape){
376 shape._setParent(null, null);
378 this.children.splice(i, 1);
385 // summary: removes all shapes from a group/surface
390 // moving child nodes
392 _moveChildToFront: function(shape){
393 // summary: moves a shape to front of the list of shapes
394 for(var i = 0; i < this.children.length; ++i){
395 if(this.children[i] == shape){
396 this.children.splice(i, 1);
397 this.children.push(shape);
403 _moveChildToBack: function(shape){
404 // summary: moves a shape to back of the list of shapes
405 for(var i = 0; i < this.children.length; ++i){
406 if(this.children[i] == shape){
407 this.children.splice(i, 1);
408 this.children.unshift(shape);
416 dojo.declare("dojox.gfx.shape.Surface", null, {
417 // summary: a surface object to be used for drawings
418 constructor: function(){
422 getEventSource: function(){
423 // summary: returns a node, which can be used to attach event listeners
424 return this.rawNode; // Node
426 _getRealMatrix: function(){
427 // summary: always returns the identity matrix
428 return null; // dojox.gfx.Matrix2D
432 dojo.extend(dojox.gfx.shape.Surface, dojox.gfx.shape._eventsProcessing);
434 dojo.declare("dojox.gfx.Point", null, {
435 // summary: a hypothetical 2D point to be used for drawings - {x, y}
436 // description: This object is defined for documentation purposes.
437 // You should use the naked object instead: {x: 1, y: 2}.
440 dojo.declare("dojox.gfx.Rectangle", null, {
441 // summary: a hypothetical rectangle - {x, y, width, height}
442 // description: This object is defined for documentation purposes.
443 // You should use the naked object instead: {x: 1, y: 2, width: 100, height: 200}.
446 dojo.declare("dojox.gfx.shape.Rect", dojox.gfx.Shape, {
447 // summary: a generic rectangle
448 constructor: function(rawNode) {
449 // rawNode: Node: a DOM Node
450 this.shape = dojo.clone(dojox.gfx.defaultRect);
451 this.rawNode = rawNode;
453 getBoundingBox: function(){
454 // summary: returns the bounding box (its shape in this case)
455 return this.shape; // dojox.gfx.Rectangle
459 dojo.declare("dojox.gfx.shape.Ellipse", dojox.gfx.Shape, {
460 // summary: a generic ellipse
461 constructor: function(rawNode) {
462 // rawNode: Node: a DOM Node
463 this.shape = dojo.clone(dojox.gfx.defaultEllipse);
464 this.rawNode = rawNode;
466 getBoundingBox: function(){
467 // summary: returns the bounding box
469 var shape = this.shape;
470 this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry,
471 width: 2 * shape.rx, height: 2 * shape.ry};
473 return this.bbox; // dojox.gfx.Rectangle
477 dojo.declare("dojox.gfx.shape.Circle", dojox.gfx.Shape, {
478 // summary: a generic circle
479 // (this is a helper object, which is defined for convenience)
480 constructor: function(rawNode) {
481 // rawNode: Node: a DOM Node
482 this.shape = dojo.clone(dojox.gfx.defaultCircle);
483 this.rawNode = rawNode;
485 getBoundingBox: function(){
486 // summary: returns the bounding box
488 var shape = this.shape;
489 this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r,
490 width: 2 * shape.r, height: 2 * shape.r};
492 return this.bbox; // dojox.gfx.Rectangle
496 dojo.declare("dojox.gfx.shape.Line", dojox.gfx.Shape, {
497 // summary: a generic line
498 // (this is a helper object, which is defined for convenience)
499 constructor: function(rawNode) {
500 // rawNode: Node: a DOM Node
501 this.shape = dojo.clone(dojox.gfx.defaultLine);
502 this.rawNode = rawNode;
504 getBoundingBox: function(){
505 // summary: returns the bounding box
507 var shape = this.shape;
509 x: Math.min(shape.x1, shape.x2),
510 y: Math.min(shape.y1, shape.y2),
511 width: Math.abs(shape.x2 - shape.x1),
512 height: Math.abs(shape.y2 - shape.y1)
515 return this.bbox; // dojox.gfx.Rectangle
519 dojo.declare("dojox.gfx.shape.Polyline", dojox.gfx.Shape, {
520 // summary: a generic polyline/polygon
521 // (this is a helper object, which is defined for convenience)
522 constructor: function(rawNode) {
523 // rawNode: Node: a DOM Node
524 this.shape = dojo.clone(dojox.gfx.defaultPolyline);
525 this.rawNode = rawNode;
527 setShape: function(points, closed){
528 // summary: sets a polyline/polygon shape object
529 // points: Object: a polyline/polygon shape object
530 // closed: Boolean: close the polyline to make a polygon
531 if(points && points instanceof Array){
532 // points: Array: an array of points
533 dojox.gfx.Shape.prototype.setShape.call(this, {points: points});
534 if(closed && this.shape.points.length){
535 this.shape.points.push(this.shape.points[0]);
538 dojox.gfx.Shape.prototype.setShape.call(this, points);
542 getBoundingBox: function(){
543 // summary: returns the bounding box
544 if(!this.bbox && this.shape.points.length){
545 var p = this.shape.points;
548 var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
549 for(var i = 1; i < l; ++i){
551 if(bbox.l > t.x) bbox.l = t.x;
552 if(bbox.r < t.x) bbox.r = t.x;
553 if(bbox.t > t.y) bbox.t = t.y;
554 if(bbox.b < t.y) bbox.b = t.y;
559 width: bbox.r - bbox.l,
560 height: bbox.b - bbox.t
563 return this.bbox; // dojox.gfx.Rectangle
567 dojo.declare("dojox.gfx.shape.Image", dojox.gfx.Shape, {
568 // summary: a generic image
569 // (this is a helper object, which is defined for convenience)
570 constructor: function(rawNode) {
571 // rawNode: Node: a DOM Node
572 this.shape = dojo.clone(dojox.gfx.defaultImage);
573 this.rawNode = rawNode;
575 getBoundingBox: function(){
576 // summary: returns the bounding box (its shape in this case)
577 return this.shape; // dojox.gfx.Rectangle
579 setStroke: function(){
580 // summary: ignore setting a stroke style
584 // summary: ignore setting a fill style
589 dojo.declare("dojox.gfx.shape.Text", dojox.gfx.Shape, {
590 // summary: a generic text
591 constructor: function(rawNode) {
592 // rawNode: Node: a DOM Node
593 this.fontStyle = null;
594 this.shape = dojo.clone(dojox.gfx.defaultText);
595 this.rawNode = rawNode;
598 // summary: returns the current font object or null
599 return this.fontStyle; // Object
601 setFont: function(newFont){
602 // summary: sets a font for text
603 // newFont: Object: a font object (see dojox.gfx.defaultFont) or a font string
604 this.fontStyle = typeof newFont == "string" ? dojox.gfx.splitFontString(newFont) :
605 dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
611 dojox.gfx.shape.Creator = {
612 // summary: shape creators
613 createShape: function(shape){
614 // summary: creates a shape object based on its type; it is meant to be used
615 // by group-like objects
616 // shape: Object: a shape descriptor object
618 case dojox.gfx.defaultPath.type: return this.createPath(shape);
619 case dojox.gfx.defaultRect.type: return this.createRect(shape);
620 case dojox.gfx.defaultCircle.type: return this.createCircle(shape);
621 case dojox.gfx.defaultEllipse.type: return this.createEllipse(shape);
622 case dojox.gfx.defaultLine.type: return this.createLine(shape);
623 case dojox.gfx.defaultPolyline.type: return this.createPolyline(shape);
624 case dojox.gfx.defaultImage.type: return this.createImage(shape);
625 case dojox.gfx.defaultText.type: return this.createText(shape);
626 case dojox.gfx.defaultTextPath.type: return this.createTextPath(shape);
630 createGroup: function(){
631 // summary: creates an SVG group shape
632 return this.createObject(dojox.gfx.Group); // dojox.gfx.Group
634 createRect: function(rect){
635 // summary: creates an SVG rectangle shape
636 // rect: Object: a path object (see dojox.gfx.defaultRect)
637 return this.createObject(dojox.gfx.Rect, rect); // dojox.gfx.Rect
639 createEllipse: function(ellipse){
640 // summary: creates an SVG ellipse shape
641 // ellipse: Object: an ellipse object (see dojox.gfx.defaultEllipse)
642 return this.createObject(dojox.gfx.Ellipse, ellipse); // dojox.gfx.Ellipse
644 createCircle: function(circle){
645 // summary: creates an SVG circle shape
646 // circle: Object: a circle object (see dojox.gfx.defaultCircle)
647 return this.createObject(dojox.gfx.Circle, circle); // dojox.gfx.Circle
649 createLine: function(line){
650 // summary: creates an SVG line shape
651 // line: Object: a line object (see dojox.gfx.defaultLine)
652 return this.createObject(dojox.gfx.Line, line); // dojox.gfx.Line
654 createPolyline: function(points){
655 // summary: creates an SVG polyline/polygon shape
656 // points: Object: a points object (see dojox.gfx.defaultPolyline)
657 // or an Array of points
658 return this.createObject(dojox.gfx.Polyline, points); // dojox.gfx.Polyline
660 createImage: function(image){
661 // summary: creates an SVG image shape
662 // image: Object: an image object (see dojox.gfx.defaultImage)
663 return this.createObject(dojox.gfx.Image, image); // dojox.gfx.Image
665 createText: function(text){
666 // summary: creates an SVG text shape
667 // text: Object: a text object (see dojox.gfx.defaultText)
668 return this.createObject(dojox.gfx.Text, text); // dojox.gfx.Text
670 createPath: function(path){
671 // summary: creates an SVG path shape
672 // path: Object: a path object (see dojox.gfx.defaultPath)
673 return this.createObject(dojox.gfx.Path, path); // dojox.gfx.Path
675 createTextPath: function(text){
676 // summary: creates an SVG text shape
677 // text: Object: a textpath object (see dojox.gfx.defaultTextPath)
678 return this.createObject(dojox.gfx.TextPath, {}).setText(text); // dojox.gfx.TextPath
680 createObject: function(shapeType, rawShape){
681 // summary: creates an instance of the passed shapeType class
682 // shapeType: Function: a class constructor to create an instance of
683 // rawShape: Object: properties to be passed in to the classes "setShape" method
685 // SHOULD BE RE-IMPLEMENTED BY THE RENDERER!
687 return null; // dojox.gfx.Shape