diff options
| author | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
|---|---|---|
| committer | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
| commit | b62676ca5d3d6f6ba3f019ea3f99722e165a98d8 (patch) | |
| tree | 86722cb80f07d4569f90088eeaea2fc2f6e2ef94 /js/dojo/dojox/drawing/stencil | |
Diffstat (limited to 'js/dojo/dojox/drawing/stencil')
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Ellipse.js | 104 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Image.js | 159 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Line.js | 122 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Path.js | 173 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Rect.js | 86 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/Text.js | 232 | ||||
| -rw-r--r-- | js/dojo/dojox/drawing/stencil/_Base.js | 1212 |
7 files changed, 2088 insertions, 0 deletions
diff --git a/js/dojo/dojox/drawing/stencil/Ellipse.js b/js/dojo/dojox/drawing/stencil/Ellipse.js new file mode 100644 index 0000000..66ecad7 --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Ellipse.js @@ -0,0 +1,104 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Ellipse", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Ellipse"); + +/*===== +__StencilData = { + // summary: + // the data used to create the dojox.gfx Shape + // + + // cx: Number + // Center point x + cx:0, + // cy: Number + // Center point y + cy:0, + // rx: Number + // Horizontal radius + rx:0, + // ry: Number + // Vertical radius + ry:0 +} +=====*/ + +dojox.drawing.stencil.Ellipse = dojox.drawing.util.oo.declare( + // summary: + // Creates a dojox.gfx Ellipse based on data or points provided. + // + dojox.drawing.stencil._Base, + function(options){ + // summary: + // constructor + }, + { + + type:"dojox.drawing.stencil.Ellipse", + anchorType: "group", + baseRender:true, + dataToPoints: function(/*Object*/o){ + //summary: + // Converts data to points. + o = o || this.data; + var x = o.cx - o.rx, + y = o.cy - o.ry, + w = o.rx*2, + h = o.ry*2 + this.points = [ + {x:x, y:y}, // TL + {x:x+w, y:y}, // TR + {x:x+w, y:y+h}, // BR + {x:x, y:y+h} // BL + ]; + return this.points; //Array + }, + + pointsToData: function(/*Array*/p){ + // summary: + // Converts points to data + p = p || this.points; + var s = p[0]; + var e = p[2]; + this.data = { + cx: s.x + (e.x - s.x)/2, + cy: s.y + (e.y - s.y)/2, + rx: (e.x - s.x)*.5, + ry: (e.y - s.y)*.5 + }; + return this.data; //Object + + }, + + _create: function(/*String*/shp, /*__StencilData*/d, /*Object*/sty){ + // summary: + // Creates a dojox.gfx.shape based on passed arguments. + // Can be called many times by implementation to create + // multiple shapes in one stencil. + // + this.remove(this[shp]); + this[shp] = this.container.createEllipse(d) + .setStroke(sty) + .setFill(sty.fill); + this._setNodeAtts(this[shp]); + }, + + render: function(){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). + // + this.onBeforeRender(this); + this.renderHit && this._create("hit", this.data, this.style.currentHit); + this._create("shape", this.data, this.style.current); + } + + } +); + +dojox.drawing.register({ + name:"dojox.drawing.stencil.Ellipse" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/Image.js b/js/dojo/dojox/drawing/stencil/Image.js new file mode 100644 index 0000000..6b23db7 --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Image.js @@ -0,0 +1,159 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Image", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Image"); + + +dojox.drawing.stencil.Image = dojox.drawing.util.oo.declare( + // summary: + // Creates an dojox.gfx Image based on the data + // provided. + // + dojox.drawing.stencil._Base, + function(options){ + // summary: + // constructor + }, + { + type:"dojox.drawing.stencil.Image", + anchorType: "group", + baseRender:true, + +/*===== +StencilData: { + // summary: + // The data used to create the dojox.gfx Shape + // x: Number + // Left point x + // y: Number + // Top point y + // width: ? Number + // Optional width of Image. If not provided, it is obtained + // height: ? Number + // Optional height of Image. If not provided, it is obtained + // src: String + // The location of the source image +}, + +StencilPoints: [ + // summary: + // An Array of dojox.__StencilPoint objects that describe the Stencil + // 0: Object + // Top left point + // 1: Object + // Top right point + // 2: Object + // Bottom right point + // 3: Object + // Bottom left point +], +=====*/ + + dataToPoints: function(/*Object*/o){ + //summary: + // Converts data to points. + o = o || this.data; + this.points = [ + {x:o.x, y:o.y}, // TL + {x:o.x + o.width, y:o.y}, // TR + {x:o.x + o.width, y:o.y + o.height}, // BR + {x:o.x, y:o.y + o.height} // BL + ]; + return this.points; + }, + + pointsToData: function(/*Array*/p){ + // summary: + // Converts points to data + p = p || this.points; + var s = p[0]; + var e = p[2]; + this.data = { + x: s.x, + y: s.y, + width: e.x-s.x, + height: e.y-s.y, + src: this.src || this.data.src + }; + return this.data; + + }, + + _createHilite: function(){ + // summary: + // Create the hit and highlight area + // for the Image. + this.remove(this.hit); + this.hit = this.container.createRect(this.data) + .setStroke(this.style.current) + .setFill(this.style.current.fill); + this._setNodeAtts(this.hit); + }, + _create: function(/*String*/shp, /*StencilData*/d, /*Object*/sty){ + // summary: + // Creates a dojox.gfx.shape based on passed arguments. + // Can be called many times by implementation to create + // multiple shapes in one stencil. + // + this.remove(this[shp]); + var s = this.container.getParent(); + this[shp] = s.createImage(d) + this.container.add(this[shp]); + this._setNodeAtts(this[shp]); + }, + + render: function(dbg){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). Image is slightly different than other + // implementations. Instead of calling render twice, it calls + // _createHilite for the 'hit' + // + if(this.data.width == "auto" || isNaN(this.data.width)){ + this.getImageSize(true); + console.warn("Image size not provided. Acquiring...") + return; + } + this.onBeforeRender(this); + this.renderHit && this._createHilite(); + this._create("shape", this.data, this.style.current); + }, + getImageSize: function(render){ + // summary: + // Internal. If no image size is passed in with the data + // create a dom node, insert and image, gets its dimensions + // record them - then destroy everything. + // + if(this._gettingSize){ return; } // IE gets it twice (will need to mod if src changes) + this._gettingSize = true; + var img = dojo.create("img", {src:this.data.src}, dojo.body()); + var err = dojo.connect(img, "error", this, function(){ + dojo.disconnect(c); + dojo.disconnect(err); + console.error("Error loading image:", this.data.src) + console.warn("Error image:", this.data) + + }); + var c = dojo.connect(img, "load", this, function(){ + var dim = dojo.marginBox(img); + this.setData({ + x:this.data.x, + y:this.data.y, + src:this.data.src, + width:dim.w, + height:dim.h + }); + dojo.disconnect(c); + dojo.destroy(img); + render && this.render(true); + }); + } + } +); + + +dojox.drawing.register({ + name:"dojox.drawing.stencil.Image" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/Line.js b/js/dojo/dojox/drawing/stencil/Line.js new file mode 100644 index 0000000..78bfbec --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Line.js @@ -0,0 +1,122 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Line", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Line"); + +dojox.drawing.stencil.Line = dojox.drawing.util.oo.declare( + // summary: + // Creates a dojox.gfx Line based on data or points provided. + // + dojox.drawing.stencil._Base, + function(options){ + // summary: + // constructor + }, + { + type:"dojox.drawing.stencil.Line", + anchorType: "single", + baseRender:true, + +/*===== +StencilData: { + // summary: + // The data used to create the dojox.gfx Shape + // x1: Number + // First point x + // y1: Number + // First point y + // x2: Number + // Second point x + // y2: Number + // Second point y + + // ALTERNATIVE: + + // x: Number + // First point x + // y: Number + // First point y + // angle: Number + // angle of line + // radius: Number + // length of line +}, + +StencilPoints: [ + // summary: + // An Array of dojox.__StencilPoint objects that describe the Stencil + // 0: Object + // First point + // 1: Object + // Second point +], +=====*/ + + dataToPoints: function(o){ + //summary: + // Converts data to points. + o = o || this.data; + if(o.radius || o.angle){ + // instead of using x1,x2,y1,y1, + // it's been set as x,y,angle,radius + + var pt = this.util.pointOnCircle(o.x,o.y,o.radius,o.angle); + //console.log(" ---- pts:", pt.x, pt.y); + this.data = o = { + x1:o.x, + y1:o.y, + x2:pt.x, + y2:pt.y + } + + } + this.points = [ + {x:o.x1, y:o.y1}, + {x:o.x2, y:o.y2} + ]; + return this.points; + }, + pointsToData: function(p){ + // summary: + // Converts points to data + p = p || this.points; + this.data = { + x1: p[0].x, + y1: p[0].y, + x2: p[1].x, + y2: p[1].y + }; + return this.data; + }, + + _create: function(/*String*/shp, /*StencilData*/d, /*Object*/sty){ + // summary: + // Creates a dojox.gfx.shape based on passed arguments. + // Can be called many times by implementation to create + // multiple shapes in one stencil. + // + this.remove(this[shp]); + this[shp] = this.container.createLine(d) + .setStroke(sty); + this._setNodeAtts(this[shp]); + }, + + render: function(){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). + // + this.onBeforeRender(this); + this.renderHit && this._create("hit", this.data, this.style.currentHit); + this._create("shape", this.data, this.style.current); + + } + + } +); + +dojox.drawing.register({ + name:"dojox.drawing.stencil.Line" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/Path.js b/js/dojo/dojox/drawing/stencil/Path.js new file mode 100644 index 0000000..8bc3dde --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Path.js @@ -0,0 +1,173 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Path", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Path"); + + +dojox.drawing.stencil.Path = dojox.drawing.util.oo.declare( + // summary: + // Creates a dojox.gfx Path based on points provided. + // + dojox.drawing.stencil._Base, + function(options){ + dojo.disconnect(this._postRenderCon); + }, + { + type:"dojox.drawing.stencil.Path", + closePath: true, + baseRender:true, + closeRadius:10, + closeColor:{r:255,g:255,b:0,a:.5}, + +/*===== +StencilData: { + // NOT SUPPORTED FOR PATH +}, + +StencilPoints: [ + // summary: + // An Array of StencilPoint objects that describe the Stencil + // 0: Object + // First point + // [1, 2, 3...] more points +], +=====*/ + + _create: function(/*String*/shp, /*Object*/sty){ + // summary: + // Creates a dojox.gfx.shape based on passed arguments. + // Can be called many times by implementation to create + // multiple shapes in one stencil. + // + this.remove(this[shp]); + if(!this.points.length){ return; } + + if(dojox.gfx.renderer=="svg"){ + // NOTE: + // In order to avoid the Safari d="" errors, + // we'll need to build a string and set that. + var strAr = []; + dojo.forEach(this.points, function(o, i){ + if(!o.skip){ + if(i==0){ + strAr.push("M " + o.x +" "+ o.y); + }else{ + var cmd = (o.t || "") + " "; + if(o.x===undefined){// Z + undefined works here, but checking anyway + strAr.push(cmd); + }else{ + strAr.push(cmd + o.x +" "+ o.y); + } + } + } + }, this); + if(this.closePath){ + strAr.push("Z"); + } + + this.stringPath = strAr.join(" "); + + this[shp] = this.container.createPath(strAr.join(" ")).setStroke(sty); + this.closePath && this[shp].setFill(sty.fill); + + }else{ + // Leaving this code for VML. It seems slightly faster but times vary. + this[shp] = this.container.createPath({}).setStroke(sty); + + this.closePath && this[shp].setFill(sty.fill); + + dojo.forEach(this.points, function(o, i){ + if(!o.skip){ + if(i==0 || o.t=="M"){ + this[shp].moveTo(o.x, o.y); + }else if(o.t=="Z"){ + this.closePath && this[shp].closePath(); + }else{ + this[shp].lineTo(o.x, o.y); + } + } + }, this); + + this.closePath && this[shp].closePath(); + } + + this._setNodeAtts(this[shp]); + }, + + render: function(){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). + // + this.onBeforeRender(this); + this.renderHit && this._create("hit", this.style.currentHit); + this._create("shape", this.style.current); + //console.log("path render") + + + //console.log("---------------------rend hit", this.renderHit, this.id) + }, + getBounds: function(/* ? Boolean*/absolute){ + // summary: + // Overwriting _Base.getBounds. Not sure how absolute should + // work for a path. + var minx = 10000, miny = 10000, maxx = 0, maxy = 0; + dojo.forEach(this.points, function(p){ + if(p.x!==undefined && !isNaN(p.x)){ + minx = Math.min(minx, p.x); + miny = Math.min(miny, p.y); + maxx = Math.max(maxx, p.x); + maxy = Math.max(maxy, p.y); + } + }); + + return { + x1:minx, + y1:miny, + x2:maxx, + y2:maxy, + x:minx, + y:miny, + w:maxx-minx, + h:maxy-miny + }; + }, + + checkClosePoint: function(/*Object*/firstPt, /*Object*/currPt, /*Boolean*/remove){ + // summary: + // Checks if points are close enough to indicate that + // path should be close. Provides a visual cue. + // description: + // Not actually used in stencil.path - this is used for + // drawable tools that extend it. Note that those tools + // need to remove the shape created: this.closeGuide, or + // add arg: remove + // + var dist = this.util.distance(firstPt.x, firstPt.y, currPt.x, currPt.y); + if(this.points.length>1){ + if(dist<this.closeRadius && !this.closeGuide && !remove){ + var c = { + cx:firstPt.x, + cy:firstPt.y, + rx:this.closeRadius, + ry:this.closeRadius + } + this.closeGuide = this.container.createEllipse(c) + .setFill(this.closeColor); + + }else if(remove || dist > this.closeRadius && this.closeGuide){ + this.remove(this.closeGuide); + this.closeGuide = null; + } + } + // return if we are within close distance + return dist < this.closeRadius; // Boolean + } + } +); + +dojox.drawing.register({ + name:"dojox.drawing.stencil.Path" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/Rect.js b/js/dojo/dojox/drawing/stencil/Rect.js new file mode 100644 index 0000000..454c7d8 --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Rect.js @@ -0,0 +1,86 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Rect", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Rect"); + + +dojox.drawing.stencil.Rect = dojox.drawing.util.oo.declare( + // summary: + // Creates a dojox.gfx rectangle based on data or points provided. + // + dojox.drawing.stencil._Base, + function(options){ + // summary: + // constructor + if(this.points.length){ + //this.render(); + } + }, + { + type:"dojox.drawing.stencil.Rect", + anchorType: "group", + baseRender:true, + + dataToPoints: function(/*Object*/d){ + //summary: + // Converts data to points. + d = d || this.data; + this.points = [ + {x:d.x, y:d.y}, // TL + {x:d.x + d.width, y:d.y}, // TR + {x:d.x + d.width, y:d.y + d.height}, // BR + {x:d.x, y:d.y + d.height} // BL + ]; + return this.points; + }, + + pointsToData: function(/*Array*/p){ + // summary: + // Converts points to data + p = p || this.points; + var s = p[0]; + var e = p[2]; + this.data = { + x: s.x, + y: s.y, + width: e.x-s.x, + height: e.y-s.y, + r:this.data.r || 0 + }; + return this.data; + + }, + + _create: function(/*String*/shp, /*StencilData*/d, /*Object*/sty){ + // summary: + // Creates a dojox.gfx.shape based on passed arguments. + // Can be called many times by implementation to create + // multiple shapes in one stencil. + // + //console.log("render rect", d) + //console.log("rect sty:", sty) + this.remove(this[shp]); + this[shp] = this.container.createRect(d) + .setStroke(sty) + .setFill(sty.fill); + + this._setNodeAtts(this[shp]); + }, + + render: function(){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). + // + this.onBeforeRender(this); + this.renderHit && this._create("hit", this.data, this.style.currentHit); + this._create("shape", this.data, this.style.current); + } + } +); + +dojox.drawing.register({ + name:"dojox.drawing.stencil.Rect" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/Text.js b/js/dojo/dojox/drawing/stencil/Text.js new file mode 100644 index 0000000..a46e69f --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/Text.js @@ -0,0 +1,232 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/Text", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil.Text"); + +dojox.drawing.stencil.Text = dojox.drawing.util.oo.declare( + // summary: + // Creates a dojox.gfx Text (SVG or VML) based on data provided. + // description: + // There are two text classes. TextBlock extends this one and + // adds editable functionality, discovers text width etc. + // This class displays text only. There is no line wrapping. + // Multiple lines can be acheived by inserting \n linebreaks + // in the text. + // + dojox.drawing.stencil._Base, + function(options){ + // summary: + // constructor. + }, + { + type:"dojox.drawing.stencil.Text", + anchorType:"none", + baseRender:true, + + // align: String + // Text horizontal alignment. + // Options: start, middle, end + align:"start", + // + // valign:String + // Text vertical alignment + // Options: top, middle, bottom (FIXME: bottom not supported) + valign:"top", + // + // _lineHeight: [readonly] Number + // The height of each line of text. Based on style information + // and font size. + _lineHeight:1, + +/*===== +StencilData: { + // summary: + // The data used to create the dojox.gfx Text + // x: Number + // Left point x + // y: Number + // Top point y + // width: ? Number + // Optional width of Text. Not required but reccommended. + // for auto-sizing, use TextBlock + // height: ? Number + // Optional height of Text. If not provided, _lineHeight is used. + // text: String + // The string content. If not provided, may auto-delete depending on defaults. +}, + +StencilPoints: [ + // summary: + // An Array of dojox.__StencilPoint objects that describe the Stencil + // 0: Object + // Top left point + // 1: Object + // Top right point + // 2: Object + // Bottom right point + // 3: Object + // Bottom left point +], +=====*/ + + typesetter: function(text){ + // summary: + // Register raw text, returning typeset form. + // Uses function dojox.drawing.stencil.Text.typeset + // for typesetting, if it exists. + // + if(dojox.drawing.util.typeset){ + this._rawText = text; + return dojox.drawing.util.typeset.convertLaTeX(text); + } + return text; + }, + + setText: function(text){ + // summary: + // Setter for text. + // + // Only apply typesetting to objects that the user can modify. + // Else, it is assumed that typesetting is done elsewhere. + if(this.enabled){ + text = this.typesetter(text); + } + // This only has an effect if text is null or this.created is false. + this._text = text; + + this._textArray = []; + this.created && this.render(text); + }, + + getText: function(){ + // summary: + // Getter for text. + // + return this._rawText || this._text; + }, + + dataToPoints: function(/*Object*/o){ + //summary: + // Converts data to points. + o = o || this.data; + var w = o.width =="auto" ? 1 : o.width; + var h = o.height || this._lineHeight; + this.points = [ + {x:o.x, y:o.y}, // TL + {x:o.x + w, y:o.y}, // TR + {x:o.x + w, y:o.y + h}, // BR + {x:o.x, y:o.y + h} // BL + ]; + return this.points; + }, + pointsToData: function(/*Array*/p){ + // summary: + // Converts points to data + p = p || this.points; + var s = p[0]; + var e = p[2]; + this.data = { + x: s.x, + y: s.y, + width: e.x-s.x, + height: e.y-s.y + }; + return this.data; + }, + + render: function(/* String*/text){ + // summary: + // Renders the 'hit' object (the shape used for an expanded + // hit area and for highlighting) and the'shape' (the actual + // display object). Text is slightly different than other + // implementations. Instead of calling render twice, it calls + // _createHilite for the 'hit' + // arguments: + // text String + // Changes text if sent. Be sure to use the setText and + // not to call this directly. + // + this.remove(this.shape, this.hit); + //console.log("text render, outline:", !this.annotation, this.renderHit, (!this.annotation && this.renderHit)) + !this.annotation && this.renderHit && this._renderOutline(); + if(text!=undefined){ + this._text = text; + this._textArray = this._text.split("\n"); + } + + var d = this.pointsToData(); + var h = this._lineHeight; + var x = d.x + this.style.text.pad*2; + var y = d.y + this._lineHeight - (this.textSize*.4); + if(this.valign=="middle"){ + y -= h/2; + } + this.shape = this.container.createGroup(); + + /*console.log(" render ", this.type, this.id) + console.log(" render Y:", d.y, "textSize:", this.textSize, "LH:", this._lineHeight) + console.log(" render text:", y, " ... ", this._text, "enabled:", this.enabled); + console.log(" render text:", this.style.currentText); + */ + dojo.forEach(this._textArray, function(txt, i){ + var tb = this.shape.createText({x: x, y: y+(h*i), text: unescape(txt), align: this.align}) + .setFont(this.style.currentText) + .setFill(this.style.currentText.color); + + this._setNodeAtts(tb); + + }, this); + + this._setNodeAtts(this.shape); + + }, + _renderOutline: function(){ + // summary: + // Create the hit and highlight area + // for the Text. + // + if(this.annotation){ return; } + var d = this.pointsToData(); + + if(this.align=="middle"){ + d.x -= d.width/2 - this.style.text.pad * 2; + }else if(this.align=="start"){ + d.x += this.style.text.pad; + }else if(this.align=="end"){ + d.x -= d.width - this.style.text.pad * 3; + } + + if(this.valign=="middle"){ + d.y -= (this._lineHeight )/2 - this.style.text.pad; + } + + this.hit = this.container.createRect(d) + .setStroke(this.style.currentHit) + .setFill(this.style.currentHit.fill); + //.setFill("#ffff00"); + + this._setNodeAtts(this.hit); + this.hit.moveToBack(); + }, + makeFit: function(text, w){ + var span = dojo.create('span', {innerHTML:text, id:"foo"}, document.body); + var sz = 1; + dojo.style(span, "fontSize", sz+"px"); + var cnt = 30; + while(dojo.marginBox(span).w<w){ + sz++; + dojo.style(span, "fontSize", sz+"px"); + if(cnt--<=0) break; + } + sz--; + var box = dojo.marginBox(span); + dojo.destroy(span); + + return {size:sz, box:box}; + } + } +); +dojox.drawing.register({ + name:"dojox.drawing.stencil.Text" +}, "stencil"); +}); diff --git a/js/dojo/dojox/drawing/stencil/_Base.js b/js/dojo/dojox/drawing/stencil/_Base.js new file mode 100644 index 0000000..3b77e52 --- /dev/null +++ b/js/dojo/dojox/drawing/stencil/_Base.js @@ -0,0 +1,1212 @@ +//>>built +// wrapped by build app +define("dojox/drawing/stencil/_Base", ["dijit","dojo","dojox","dojo/require!dojo/fx/easing"], function(dijit,dojo,dojox){ +dojo.provide("dojox.drawing.stencil._Base"); +dojo.require("dojo.fx.easing"); + +/*===== +StencilArgs = { +// container: [readonly] dojo.gfx.group +// The parent shape that contains all +// shapes used in a Stencil +container:null, +// +// anchorType: String +// Optionally blank or 'group'. 'group' tells +// an anchor point that it must constrain +// itself to other anchor points. +anchorType:"", +// +// isText: Boolean +// Whether this is a text object or not +// (either stencil.text or tools.TextBlock) +isText:false, +// +// shortType: String +// The type of stencil that corresponds with the types and +// constructors used in Drawing.registerTool +shortType:"", +// +// annotation: Boolean +// A Stencil used within a Stencil. An annotation +// is not selectable or clickable. A Label would +// be one example. +annotation:false, +// +// subShape: Boolean +// A Stencil used within a Stencil. A subShape +// is clickable. An arrow head would be an example. +subShape:false, +// +// style: Object +// An instance of the styles and defaults used within +// the Stencil. +style:null, +// +// util: Object +// Pointer to util.common +util:null, +// +// mouse: Object +// Pointer to the mouse instance +mouse:null, +// +// keys: Object +// Pointer to the keys class +keys:null, +// +// points: StencilPoints +// Points is an array of objects that make up the +// description of a Stencil. The points to a Rect +// that is 100x100 and at x:10 and y:10 would look like: +// [{x:10,y:10}, {x:110, y:10}, {x:110, y:110}, {x:10, y:110}] +// Points go clockwise from the top left. In the case of Paths, +// they would go in the order that the Stencil would be drawn. +// Always when the points Array is set, a data Object is created +// as well. So never set points directly, always use setPoints(). +// See: +// setPoints() +points:[], +// +// data: StencilData +// A data object typically (but not always) resembles the data +// that is used to create the dojox.gfx Shape. The same Rect +// example shown in points above would look like: +// {x:10, y:10, width:100, height:100} +// And an Ellipse with the same coordinates: +// {cx:55, cy:55, rx:50, ry:50} +// The only Stencil that does not support data (at this time) +// is the Path. While x1,x2,x3... culd be used in a data object +// it doesn't provide much benefit. +// Always when a data object is set, a set of points is created +// as well. So never set data directly, always use setData(). +// See: +// setData() +data:null, +// +// marginZero [readonly] Number +// How closely shape can get to y:0 or x:0. Less than zero has +// bugs in VML. This is set with defaults, and should be equal +// to half the size of an anchor point (5 px) +marginZero:0, +// +// created [readonly] Boolean +// Whether the Stencil has been rendered for the first time or +// not. +created: false, +// +// highlighted [readonly] Boolean +// Whether the Stencil is highlighted or not. +highlighted:false, +// +// selected [readonly] Boolean +// Whether the Stencil is selected or not. +selected:false, +// +// draws [readonly] Boolean +// Whether the Stencil can draw with a mouse drag or can just +// be created programmtically. If the Stencil comes from the +// stencil package, it should be draw:false. If it comes from +// the tools package it should be draw:true. +draws:false +} + +StencilPoint = { +// summary: +// One point Object in the points Array +// x: Number +// x position of point +// y: Number +// y position of point +} + +ToolsSetup = { +// summary: +// An object attached to a Tool's constructor +// used to inform the toolbar of its information +// and properties. +// description: +// This object is inserted into the *function* of +// a tool (not a stencil). Like: function.ToolsSetup +// It must be attached after constructr creation, so +// this object is found at the botton of the file. +// +// name:String +// Fully qualified name of constructor +// tooltip: Stirng +// Text to display on toolbar button hover +// iconClass: String +// CSS class with icon information to attach +// to toolbar button. +} +=====*/ + +dojox.drawing.stencil._Base = dojox.drawing.util.oo.declare( + // summary: + // The base class used for all Stencils. + // description: + // All stencils extend this base class. + // Most methods and events can be found here. + // + function(options){ + //console.log("______Base", this.type, options) + // clone style so changes are reflected in future shapes + dojo.mixin(this, options); + this.style = options.style || dojox.drawing.defaults.copy(); + if(options.stencil){ + this.stencil = options.stencil; + this.util = options.stencil.util; + this.mouse = options.stencil.mouse; + this.container = options.stencil.container; + this.style = options.stencil.style; + } + + // don't use the 'g' on these, it affects + // the global RegExp + var lineTypes = /Line|Vector|Axes|Arrow/; + var textTypes = /Text/; + + this.shortType = this.util.abbr(this.type); + this.isText = textTypes.test(this.type); + this.isLine = lineTypes.test(this.type); + + this.renderHit = this.style.renderHitLayer; + if(!this.renderHit && this.style.renderHitLines && this.isLine){ + this.renderHit = true; + } + if(!this.renderHit && this.style.useSelectedStyle){ + this.useSelectedStyle = true; + this.selCopy = dojo.clone(this.style.selected); + for(var nm in this.style.norm){ + if(this.style.selected[nm]===undefined){ + this.style.selected[nm] = this.style.norm[nm]; + } + } + this.textSelected = dojo.clone(this.style.text); + this.textSelected.color = this.style.selected.fill; + + } + + + this.angleSnap = this.style.angleSnap || 1; + + this.marginZero = options.marginZero || this.style.anchors.marginZero; + this.id = options.id || this.util.uid(this.type); + this._cons = []; + + if(!this.annotation && !this.subShape){ + this.util.attr(this.container, "id", this.id); + } + + this.connect(this, "onBeforeRender", "preventNegativePos"); + + this._offX = this.mouse.origin.x; + this._offY = this.mouse.origin.y; + + if(this.isText){ + this.align = options.align || this.align; + this.valign = options.valign || this.valign; + if(options.data && options.data.makeFit){ + var textObj = this.makeFit(options.data.text, options.data.width); + this.textSize = this.style.text.size = textObj.size; + this._lineHeight = textObj.box.h; + }else{ + this.textSize = parseInt(this.style.text.size, 10); + this._lineHeight = this.textSize * 1.4; + } + + + // TODO: thinner text selection + //this.style.hitSelected.width *= 0.5; + // + // ouch. how verbose. My mixin is weak.... + this.deleteEmptyCreate = options.deleteEmptyCreate!==undefined ? options.deleteEmptyCreate : this.style.text.deleteEmptyCreate; + this.deleteEmptyModify = options.deleteEmptyModify!==undefined ? options.deleteEmptyModify : this.style.text.deleteEmptyModify; + } + + //this.drawingType + + this.attr(options.data); + + // make truthy + // add to renders below + // this.baseRender && render() + //if(this.type == "dojox.drawing.tools.TextBlock"){ + if(this.noBaseRender){ + // TextBlock will handle rendering itself + return; + } + + //console.log("BASE OPTS:", options) + if(options.points){ + //console.log("__________Base.constr >>>> ", this.type, "points", options.points) + if(options.data && options.data.closePath===false){ + this.closePath = false; + } + this.setPoints(options.points); + this.connect(this, "render", this, "onRender", true); + this.baseRender && this.enabled && this.render(); + options.label && this.setLabel(options.label); + options.shadow && this.addShadow(options.shadow); + + }else if(options.data){ + //console.log("___________Base.constr", this.type, "options data", options.data) + options.data.width = options.data.width ? options.data.width : this.style.text.minWidth; + options.data.height = options.data.height ? options.data.height : this._lineHeight; + this.setData(options.data); + this.connect(this, "render", this, "onRender", true); + this.baseRender && this.enabled && this.render(options.data.text); + this.baseRender && options.label && this.setLabel(options.label); + this.baseRender && options.shadow && this.addShadow(options.shadow); + + }else if(this.draws){ + //console.log("_____________Base.constr", this.type, "draws") + this.points = []; + this.data = {}; + this.connectMouse(); + this._postRenderCon = dojo.connect(this, "render", this, "_onPostRender"); + } + if(this.showAngle){ + this.angleLabel = new dojox.drawing.annotations.Angle({stencil:this}); + } + + if(!this.enabled){ + this.disable(); + this.moveToBack(); + // some things render some don't... + this.render(options.data.text); + } + + }, + { + + // type: String + // The type of Stencil this is. Should be overridden + // by extending classes. + // FIXME: should this be declaredClass? + type:"dojox.drawing.stencil", + // + // minimumSize: Number + // The minimum size allowed for a render. If the size + // is less, the shape is destroyed. + minimumSize:10, + // + // enabled [readonly] Boolean + // Whether the Stencil is enabled or not. + enabled:true, + + + drawingType:"stencil", + + //points:[], + + setData: function(/*StencilData*/data){ + // summary: + // Setter for Stencil data; also converts + // data to points. See individual Stencils + // for specific data properties. + this.data = data; + this.points = this.dataToPoints(); + }, + + setPoints: function(/*StencilPoints*/points){ + // summary: + // Setter for Stencil points; also converts + // points to data. See individual Stencils + // for specific points properties. + this.points = points; + // Path doesn't do data + if(this.pointsToData){ + this.data = this.pointsToData(); + } + }, + + onDelete: function(/* Stencil */ stencil){ + // summary: + // Stub - fires before this is destroyed + console.info("onDelete", this.id); + }, + + onBeforeRender: function(/*Object*/ stencil){ + // summary: + // Stub - Fires before render occurs. + }, + + onModify: function(/*Object*/stencil){ + // summary: + // Stub - fires on change of any property, + // including style properties + + }, + + onChangeData: function(/*Object*/ stencil){ + // summary: + // Stub - fires on change of dimensional + // properties or a text change + }, + + onChangeText: function(value){ // value or 'this' ? + // summary: + // Stub - fires on change of text in a + // TextBlock tool only + }, + + onRender: function(/*Object*/ stencil){ + // summary: + // Stub - Fires on creation. + // Drawing connects to this (once!) to be + // notified of drag completion. But only if it + // was registered as a Tool. Creating Stencil in and of + // itself does not register it. + // + // This should fire + // at the *end* of creation (not during drag) + // + // FIXME: + // This should probably be onCreate. It should + // only fire once. But the mechanism for determining + // this is more complicated than it sounds. + // + this._postRenderCon = dojo.connect(this, "render", this, "_onPostRender"); + this.created = true; + this.disconnectMouse(); + + // for Silverlight + if(this.shape){ + this.shape.superClass = this; + }else{ + this.container.superClass = this; + } + this._setNodeAtts(this); + //console.warn("ONRENDER", this.id, this) + }, + + onChangeStyle: function(/*Object*/stencil){ + // summary: + // Fires when styles of shape has changed + // + this._isBeingModified = true; // need this to prevent onRender + if(!this.enabled){ + this.style.current = this.style.disabled; + this.style.currentText = this.style.textDisabled; + this.style.currentHit = this.style.hitNorm; + + }else{ + this.style.current = this.style.norm; + this.style.currentHit = this.style.hitNorm; + this.style.currentText = this.style.text; + } + + if(this.selected){ + if(this.useSelectedStyle){ + this.style.current = this.style.selected; + this.style.currentText = this.textSelected; + } + this.style.currentHit = this.style.hitSelected; + + }else if(this.highlighted){ + //this.style.current = this.style.highlighted; + this.style.currentHit = this.style.hitHighlighted; + //this.style.currentText = this.style.textHighlighted; + } + + // NOTE: Can't just change props like setStroke + // because Silverlight throws error + this.render(); + }, + + animate: function(options, create){ + console.warn("ANIMATE..........................") + var d = options.d || options.duration || 1000; + var ms = options.ms || 20; + var ease = options.ease || dojo.fx.easing.linear; + var steps = options.steps; + var ts = new Date().getTime(); + var w = 100; + var cnt = 0; + var isArray = true; + var sp, ep; + + if(dojo.isArray(options.start)){ + sp = options.start; + ep = options.end; + + }else if(dojo.isObject(options.start)){ + sp = options.start; + ep = options.end; + isArray = false; + }else{ + + console.warn("No data provided to animate") + } + + var v = setInterval(dojo.hitch(this, function(){ + var t = new Date().getTime() - ts; + var p = ease(1-t/d); + if(t > d || cnt++ > 100){ + clearInterval(v); + return; + } + + if(isArray){ + var pnts = []; + dojo.forEach(sp, function(pt, i){ + + var o = { + x: (ep[i].x-sp[i].x)*p + sp[i].x, + y: (ep[i].y-sp[i].y)*p + sp[i].y + }; + pnts.push(o); + }); + this.setPoints(pnts); + this.render(); + + }else{ + + var o = {}; + for(var nm in sp){ + o[nm] = (ep[nm] - sp[nm]) * p + sp[nm]; + } + + this.attr(o); + + } + //console.dir(pnts) + + + //this.attr("height", w); + ////console.log("W:", w) + //w += 5; + + }), ms); + }, + + attr: function(/*String | Object*/key, /* ? String | Number */value){ + // summary + // Changes properties in the style or disabled styles, + // depending on whether the object is enabled. + // Also can be used to change most position and size props. + + // NOTE: JUST A SETTTER!! TODO! + + // WARNING: + // Not doing any Stencil-type checking here. Setting a height + // on a line or an angle on a rectangle will just not render. + + // FIXME + // 'width' attr is used for line width. How to change the width of a stencil? + var n = this.enabled?this.style.norm:this.style.disabled; + var t = this.enabled?this.style.text:this.style.textDisabled; + var ts = this.textSelected || {}, + o, + nm, + width, + styleWas = dojo.toJson(n), + textWas = dojo.toJson(t); + + var coords = { + x:true, + y:true, + r:true, + height:true, + width:true, + radius:true, + angle:true + }; + var propChange = false; + if(typeof(key)!="object"){ + o = {}; + o[key] = value; + }else{ + // prevent changing actual data + o = dojo.clone(key); + } + + if(o.width){ + // using width for size, + // borderWidth should be used + // for line thickness + width = o.width; + delete o.width; + } + + for(nm in o){ + if(nm in n){ n[nm] = o[nm]; } + if(nm in t){ t[nm] = o[nm]; } + if(nm in ts){ ts[nm] = o[nm]; } + + if(nm in coords){ + coords[nm] = o[nm]; + propChange = true; + if(nm == "radius" && o.angle===undefined){ + o.angle = coords.angle = this.getAngle(); + }else if(nm == "angle" && o.radius===undefined){ + o.radius = coords.radius = this.getRadius(); + } + + } + if(nm == "text"){ + this.setText(o.text); + } + if(nm == "label"){ + this.setLabel(o.label); + } + } + if(o.borderWidth!==undefined){ + n.width = o.borderWidth; + } + + if(this.useSelectedStyle){ + // using the orginal selected style copy as + // a reference map of what props to copy + for(nm in this.style.norm){ + if(this.selCopy[nm]===undefined){ + this.style.selected[nm] = this.style.norm[nm]; + } + } + this.textSelected.color = this.style.selected.color; + + } + + if(!this.created){ + return; + } + + // basic transform + if(o.x!==undefined || o.y!==undefined){ + var box = this.getBounds(true); + var mx = { dx:0, dy:0 }; + for(nm in o){ + if(nm=="x" || nm =="y" || nm =="r"){ + mx["d"+nm] = o[nm] - box[nm]; + } + } + this.transformPoints(mx); + } + + + var p = this.points; + if(o.angle!==undefined){ + this.dataToPoints({ + x:this.data.x1, + y:this.data.y1, + angle:o.angle, + radius:o.radius + }); + + } else if(width!==undefined){ + p[1].x = p[2].x = p[0].x + width; + this.pointsToData(p); + } + + if(o.height!==undefined && o.angle===undefined){ + console.log("Doing P2D-2"); + p[2].y = p[3].y = p[0].y + o.height; + this.pointsToData(p); + } + + if(o.r!==undefined){ + this.data.r = Math.max(0, o.r); + } + + //console.dir(this.data); + if(propChange || textWas!=dojo.toJson(t) || styleWas != dojo.toJson(n)){ + // to trigger the render + // other events will be called post render + this.onChangeStyle(this); + } + o.width = width; + + if(o.cosphi!=undefined){ + !this.data? this.data = {cosphi:o.cosphi} : this.data.cosphi = o.cosphi; + this.style.zAxis = o.cosphi!=0 ? true : false; + } + }, + + exporter: function(){ + // summary: + // Exports Stencil data + // + var type = this.type.substring(this.type.lastIndexOf(".")+1).charAt(0).toLowerCase() + + this.type.substring(this.type.lastIndexOf(".")+2); + var o = dojo.clone(this.style.norm); + o.borderWidth = o.width; + delete o.width; + if(type=="path"){ + o.points = this.points; + }else{ + o = dojo.mixin(o, this.data); + } + o.type = type; + if(this.isText){ + o.text = this.getText(); + o = dojo.mixin(o, this.style.text); + delete o.minWidth; + delete o.deleteEmptyCreate; + delete o.deleteEmptyModify; + } + var lbl = this.getLabel(); + if(lbl){ + o.label = lbl; + } + return o; + }, + + + // TODO: + // Makes these all called by att() + // Should points and data be? + // + disable: function(){ + // summary: + // Disables Stencil so it is not selectable. + // Changes the color to the disabled style. + this.enabled = false; + this.renderHit = false; + this.onChangeStyle(this); + }, + + enable: function(){ + // summary: + // Enables Stencil so it is not selectable (if + // it was selectable to begin with). Changes the + // color to the current style. + this.enabled = true; + this.renderHit = true; + this.onChangeStyle(this); + }, + + select: function(){ + // summary: + // Called when the Stencil is selected. + // NOTE: Calling this will not select the Stencil + // calling this just sets the style to the 'selected' + // theme. 'manager.Stencil' should be used for selecting + // Stencils. + // + this.selected = true; + this.onChangeStyle(this); + }, + + deselect: function(/*Boolean*/useDelay){ + // summary: + // Called when the Stencil is deselected. + // NOTE: Calling this will not deselect the Stencil + // calling this just sets the style to the current + // theme. 'manager.Stencil' should be used for selecting + // and deselecting Stencils. + // + // arguments: + // useDelay: Boolean + // Adds slight delay before the style is set. + // + // should not have to render here because the deselection + // re-renders after the transform + // but... oh well. + if(useDelay){ + setTimeout(dojo.hitch(this, function(){ + this.selected = false; + this.onChangeStyle(this); + }),200); + }else{ + this.selected = false; + this.onChangeStyle(this); + } + }, + _toggleSelected: function(){ + if(!this.selected){ return; } + this.deselect(); + setTimeout(dojo.hitch(this, "select"), 0); + }, + + highlight: function(){ + // summary: + // Changes style to the highlight theme. + this.highlighted = true; + this.onChangeStyle(this); + }, + + unhighlight: function(){ + // summary: + // Changes style to the current theme. + this.highlighted = false; + this.onChangeStyle(this); + }, + + moveToFront: function(){ + // summary: + // Moves Stencil to the front of all other items + // on the canvas. + this.container && this.container.moveToFront(); + }, + + moveToBack: function(){ + // summary: + // Moves Stencil to the back of all other items + // on the canvas. + this.container && this.container.moveToBack(); + }, + + onTransformBegin: function(/* ? manager.Anchor */anchor){ + // summary: + // Fired at the start of a transform. This would be + // an anchor drag or a selection. + // + this._isBeingModified = true; + }, + + onTransformEnd: function(/* manager.Anchor */anchor){ + // summary: + // Called from anchor point up mouse up + this._isBeingModified = false; + this.onModify(this); + }, + + onTransform: function(/* ? manager.Anchor */anchor){ + // summary: + // Called from anchor point mouse drag + // also called from plugins.Pan.checkBounds + if(!this._isBeingModified){ + this.onTransformBegin(); + } + // this is not needed for anchor moves, but it + // is for stencil move: + this.setPoints(this.points); + this.render(); + }, + + transformPoints: function(mx){ + // summary: + // Moves object to a new X Y location + // mx is additive. So mx.dx=1 will move the stencil + // 1 pixel to the right from wherever it was. + // + // An attempt is made to prevent < 0 errors, but + // this won't work on all shapes (like Axes) + // + if(!mx.dx && !mx.dy){ + // no change + return; + } + var backup = dojo.clone(this.points), abort = false; + dojo.forEach(this.points, function(o){ + o.x += mx.dx; + o.y += mx.dy; + if(o.x<this.marginZero || o.y<this.marginZero){ + abort = true; + } + }); + if(abort){ + this.points = backup; + console.error("Attempt to set object '"+this.id+"' to less than zero."); + return; + } + this.onTransform(); + this.onTransformEnd(); + }, + + applyTransform: function(mx){ + // summary: + // Applies the transform to the stencil + // NOTE: PARTIALLY IMPLEMENTED + // Only applies x y coords + this.transformPoints(mx); + }, + + setTransform: function(/*Object*/mx){ + // summary: + // Sets the transform to the stencil + // NOTE: PARTIALLY IMPLEMENTED + // Only applies x y coords + this.attr({ + x:mx.dx, + y:mx.dy + }); + }, + + getTransform: function(){ + // summary: + // Returns the current transform (position) of the Stencil's + // container + return this.selected ? this.container.getParent().getTransform() : {dx:0, dy:0}; // Object + }, + + addShadow: function(/*Object*/args){ + args = args===true ? {} : args; + args.stencil = this; + this.shadow = new dojox.drawing.annotations.BoxShadow(args); + }, + + removeShadow: function(){ + this.shadow.destroy(); + }, + + setLabel: function(/*String*/text){ + // summary: + // Creates and sets a label annotation for the Stencil. + // If Stencil contains a labelPosition method, that will + // be used for positioning. Otherwise + // dojox.drawing.util.positioning.label is used. + // arguments: + // text: String + // The text to set as the label. + // + if(!this._label){ + this._label = new dojox.drawing.annotations.Label({ + text:text, + util:this.util, + mouse:this.mouse, + stencil:this, + annotation:true, + container:this.container, + labelPosition:this.labelPosition + }); + }else if(text!=undefined){ + this._label.setLabel(text); + } + }, + + getLabel: function(){ + // summary: + // Get the text of the label. + // + if(this._label){ + return this._label.getText(); // String + } + return null; //null + }, + + getAngle: function(){ + // summary: + // Gets angle of Stencil + // NOTE: Only works for Lines, Arrows, Vectors and Axes + // (works on points, not transforms) + var d = this.pointsToData(); + var obj = { + start:{ + x:d.x1, + y:d.y1 + }, + x:d.x2, + y:d.y2 + }; + var angle = this.util.angle(obj, this.angleSnap); + // converting the angle for display: -180 -> 180, -90 -> 270 + angle<0 ? angle = 360 + angle : angle; + return angle; + }, + getRadius: function(){ + // summary: + // Gets radius (length) of Stencil + // NOTE: Only works for Lines, Arrows and Vectors + // (not for Ellipse, Axes has its own version) + // + var box = this.getBounds(true); + var line = {start:{x:box.x1, y:box.y1}, x:box.x2, y:box.y2}; + return this.util.length(line); + }, + getBounds: function(/* ? Boolean*/absolute){ + // summary: + // Returns the coordinates of the Stencil. This is often + // different than the data or the points. + // arguments: + // absolute: Boolean + // Keeps lines from flipping (see note). + // + // NOTE: Won't work for paths or annotations (labels, Axes, arrow tips) + // They should overwrite. + // NOTE: Primarily used for checking for if shape is off + // canvas. Therefore Lines could get flipped. Use absolute + // to prevent this. + // + var p = this.points, x1, y1, x2, y2; + if(p.length==2){ + if(absolute){ + x1 = p[0].x; + y1 = p[0].y; + x2 = p[1].x; + y2 = p[1].y + }else{ + x1 = p[0].x < p[1].x ? p[0].x : p[1].x; + y1 = p[0].y < p[1].y ? p[0].y : p[1].y; + x2 = p[0].x < p[1].x ? p[1].x : p[0].x; + y2 = p[0].y < p[1].y ? p[1].y : p[0].y; + } + return { + x1:x1, + y1:y1, + x2:x2, + y2:y2, + x:x1, + y:y1, + w:x2-x1, + h:y2-y1 + }; // Object + }else{ + return { + x1:p[0].x, + y1:p[0].y, + x2:p[2].x, + y2:p[2].y, + x:p[0].x, + y:p[0].y, + w:p[2].x - p[0].x, + h:p[2].y - p[0].y + }; // Object + } + }, + + + preventNegativePos: function(){ + // summary: + // Internal. Prevent item from being drawn/rendered less + // than zero on the X or Y. + // + // if being modified anchors will prevent less than zero. + if(this._isBeingModified){ return; } + // FIXME: why is this sometimes empty? + if(!this.points || !this.points.length){ return; } + + if(this.type=="dojox.drawing.tools.custom.Axes"){ + // this scenario moves all points if < 0 + var minY = this.marginZero, minX = this.marginZero; + dojo.forEach(this.points, function(p){ minY = Math.min(p.y, minY); }); + dojo.forEach(this.points, function(p){ minX = Math.min(p.x, minX); }); + + if(minY<this.marginZero){ + dojo.forEach(this.points, function(p, i){ + p.y = p.y + (this.marginZero-minY) + }, this); + } + if(minX<this.marginZero){ + dojo.forEach(this.points, function(p){ + p.x += (this.marginZero-minX) + }, this); + } + + }else{ + // this scenario moves just the one point that is < 0 + dojo.forEach(this.points, function(p){ + p.x = p.x < 0 ? this.marginZero : p.x; + p.y = p.y < 0 ? this.marginZero : p.y; + }); + } + this.setPoints(this.points); + }, + + _onPostRender: function(/*Object*/data){ + // summary: + // Drag-create or programmatic create calls onRender + // and afterwards, _onPostRender is called and + // manages further events. + // + // TODO: can this be onModify? Is that more clear? + // + //console.info("...........post render....."); + + if(this._isBeingModified){ + this.onModify(this); + this._isBeingModified = false; + }else if(!this.created){ + //this.onCreate(this); + //this.onRender(this); + } + + if(!this.editMode && !this.selected && this._prevData && dojo.toJson(this._prevData) != dojo.toJson(this.data)){ + //console.info("_Base data changed ----> : this.editMode:", this.editMode) + this.onChangeData(this); + this._prevData = dojo.clone(this.data); + + }else if(!this._prevData && (!this.isText || this.getText())){ + //console.info("_Base no prevData.........................."); + this._prevData = dojo.clone(this.data); + + } + + }, + + _setNodeAtts: function(shape){ + // summary: + // Internal. Sets the rawNode attribute. (Or in Silverlight + // an "object attribute". "stencil" is + // used by the application to determine if + // something is selectable or not. This also + // sets the mouse custom events like: + // "onStencilUp". To disable the selectability, + // make the att "", which causes a standard + // mouse event. + // Labels are special and used to select master stencils. + var att = this.enabled && (!this.annotation || this.drawingType=="label") ? this.drawingType : ""; + this.util.attr(shape, "drawingType", att); + }, + + + destroy: function(){ + // summary: + // Destroys this Stencil + // Note: + // Can connect to this, but it's better to + // connect to onDelete + // + // prevent loops: + if(this.destroyed){ return; } + if(this.data || this.points && this.points.length){ + this.onDelete(this); + } + + this.disconnectMouse(); + this.disconnect(this._cons); + dojo.disconnect(this._postRenderCon); + this.remove(this.shape, this.hit); + this.destroyed = true; + }, + + remove: function(/*Shape...*/){ + // summary: + // Removes shape(s), typically before a re-render + // No args defaults to this.shape + // Pass in multiple args to remove multiple shapes + // + // FIXME: Use an Array of all shapes + // + var a = arguments; + if(!a.length){ + if(!this.shape){ return; } + a = [this.shape]; + } + for(var i=0;i<a.length;i++){ + if(a[i]){ + a[i].removeShape(); + } + } + }, + + connectMult: function(/*dojo.connect args */){ + // summary: + // Convenience method for batches of quick connects + // Handles are not returned and therefore cannot be + // disconnected until Shape destroy time + // + if(arguments.length>1){ + // arguments are the connect params + this._cons.push(this.connect.apply(this, arguments)); + }else if(dojo.isArray(arguments[0][0])){ + // an array of arrays of params + dojo.forEach(arguments[0], function(ar){ + this._cons.push(this.connect.apply(this, ar)); + }, this); + }else{ + //one array of params + this._cons.push(this.connect.apply(this, arguments[0])); + } + + }, + + // TODO: connect to a Shape event from outside class + connect: function(o, e, s, m, /* Boolean*/once){ + // summary: + // Convenience method for quick connects + // See comments below for possiblities + // functions can be strings + // once: + // If true, the connection happens only + // once then disconnects. Five args are required + // for this functionality. + // + var c; + if(typeof(o)!="object"){ + if(s){ + // ** function object function ** + m = s; s = e; e=o; o = this; + }else{ + // ** function function ** + m = e; e = o; o = s = this; + } + }else if(!m){ + // ** object function function ** + m = s; s = this; + }else if(once){ + // ** object function object function Boolean ** + c = dojo.connect(o, e, function(evt){ + dojo.hitch(s, m)(evt); + dojo.disconnect(c); + }); + this._cons.push(c); + return c; + }else{ + // ** object function object function ** + } + c = dojo.connect(o, e, s, m); + this._cons.push(c); + return c; + }, + + disconnect: function(/*handle | Array*/handles){ + // summary: + // Removes connections based on passed + // handles arguments + if(!handles){ return } + if(!dojo.isArray(handles)){ handles=[handles]; } + dojo.forEach(handles, dojo.disconnect, dojo); + }, + + connectMouse: function(){ + // summary: + // Internal. Registers this Stencil to receive + // mouse events. + this._mouseHandle = this.mouse.register(this); + }, + disconnectMouse: function(){ + // summary: + // Internal. Unregisters this Stencil from receiving + // mouse events. + this.mouse.unregister(this._mouseHandle); + }, + + // Should be overwritten by sub class: + render: function(){ + // summary: + // This Stencil's render description. Often + // calls 'sub render' methods. + }, + //renderOutline: function(){}, + dataToPoints: function(/*Object*/data){ + // summary: + // Converts data to points. + }, + pointsToData: function(/*Array*/points){ + // summary: + // Converts points to data + }, + onDown: function(/*EventObject*/obj){ + // summary: + // Mouse event, fired on mousedown on canvas + // + // by default, object is ready to accept data + // turn this off for dragging or onRender will + // keep firing and register the shape + // NOTE: Not needed for all stencils. Axes needs it. + this._downOnCanvas = true; + dojo.disconnect(this._postRenderCon); + this._postRenderCon = null; + }, + onMove: function(/*EventObject*/obj){ + // summary: + // Mouse event, fired on mousemove while mouse + // is not down. + // NOTE: Not currently implemented + }, + onDrag: function(/*EventObject*/obj){ + // summary: + // Mouse event, fired on mousemove while mouse + // is down on canvas + }, + onUp: function(/*EventObject*/obj){ + // summary: + // Mouse event, fired on mouseup + } + } +); + + +}); |
