diff options
Diffstat (limited to 'js/dojo/dojox/sketch')
| -rw-r--r-- | js/dojo/dojox/sketch/Anchor.js | 70 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/Annotation.js | 276 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/DoubleArrowAnnotation.js | 233 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/Figure.js | 533 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/LeadAnnotation.js | 162 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/PreexistingAnnotation.js | 164 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/README | 58 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/SingleArrowAnnotation.js | 227 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/Slider.js | 43 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/Toolbar.js | 104 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/UnderlineAnnotation.js | 145 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/UndoStack.js | 106 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/_Plugin.js | 82 | ||||
| -rw-r--r-- | js/dojo/dojox/sketch/resources/images/icons.gif | bin | 0 -> 600 bytes | |||
| -rw-r--r-- | js/dojo/dojox/sketch/resources/sketch.css | 17 |
15 files changed, 2220 insertions, 0 deletions
diff --git a/js/dojo/dojox/sketch/Anchor.js b/js/dojo/dojox/sketch/Anchor.js new file mode 100644 index 0000000..f1e6b57 --- /dev/null +++ b/js/dojo/dojox/sketch/Anchor.js @@ -0,0 +1,70 @@ +//>>built +define("dojox/sketch/Anchor", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "../gfx" +], function(dojo){ + dojo.getObject("sketch", true, dojox); + + dojox.sketch.Anchor=function(an, id, isControl){ + var self=this; + var size=4; // .5 * size of anchor. + var rect=null; + + this.type=function(){ return "Anchor"; }; + this.annotation=an; + + this.id=id; + this._key="anchor-" + dojox.sketch.Anchor.count++; + this.shape=null; + this.isControl=(isControl!=null)?isControl:true; + + this.beginEdit=function(){ + this.annotation.beginEdit(dojox.sketch.CommandTypes.Modify); + }; + this.endEdit=function(){ + this.annotation.endEdit(); + }; + this.zoom=function(pct){ + if(this.shape){ + var rs=Math.floor(size/pct); + var width=dojox.gfx.renderer=='vml'?1:1/pct + this.shape.setShape({ x:an[id].x-rs, y:an[id].y-rs, width:rs*2, height:rs*2 }).setStroke({ color:"black", width:width }); //For IE, maybe we need Math.ceil(1/pct)||1 + } + } + /*this.doChange=function(pt){ + if(this.isControl){ + this.shape.applyTransform(pt); + } else{ + an.transform.dx+=pt.dx; + an.transform.dy+=pt.dy; + } + };*/ + this.setBinding=function(pt){ + an[id]={ x: an[id].x+pt.dx, y:an[id].y+pt.dy }; + an.draw(); + an.drawBBox(); + }; + this.setUndo=function(){ an.setUndo(); }; + + this.enable=function(){ + if(!an.shape){ return; } + an.figure._add(this); + rect={ x:an[id].x-size, y:an[id].y-size, width:size*2, height:size*2 }; + this.shape=an.shape.createRect(rect) + //.setStroke({ color:"black", width:1 }) + .setFill([255,255,255,0.35]); + this.shape.getEventSource().setAttribute("id", self._key); + this.shape.getEventSource().setAttribute("shape-rendering", "crispEdges"); + this.zoom(an.figure.zoomFactor); + }; + this.disable=function(){ + an.figure._remove(this); + if(an.shape){ an.shape.remove(this.shape); } + this.shape=null; + rect=null; + }; + }; + dojox.sketch.Anchor.count=0; + return dojox.sketch.Anchor; +}); diff --git a/js/dojo/dojox/sketch/Annotation.js b/js/dojo/dojox/sketch/Annotation.js new file mode 100644 index 0000000..b062a4d --- /dev/null +++ b/js/dojo/dojox/sketch/Annotation.js @@ -0,0 +1,276 @@ +//>>built +define("dojox/sketch/Annotation", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/declare", + "dojo/_base/json", + "./Anchor", + "./_Plugin" +], function(dojo){ + dojo.declare("dojox.sketch.AnnotationTool", dojox.sketch._Plugin, { + onMouseDown: function(e){ + this._omd=true; + }, + onMouseMove: function(e,rect){ + if(!this._omd){ + return; + } + if(this._cshape){ + this._cshape.setShape(rect); + } else { + this._cshape=this.figure.surface.createRect(rect) + .setStroke({color:"#999", width:1, style:"ShortDot"}) + .setFill([255,255,255,0.7]); + this._cshape.getEventSource().setAttribute("shape-rendering","crispEdges"); + } + }, + onMouseUp: function(e){ + if(!this._omd){ + return; + } + this._omd=false; + var f=this.figure; + if(this._cshape){ + f.surface.remove(this._cshape); + delete this._cshape; + } + if(!(f._startPoint.x==e.pageX&&f._startPoint.y==e.pageY)){ + // The minimum number of pixels one has to travel before a shape + // gets drawn. + var limit=10; + if(Math.max( + limit, + Math.abs(f._absEnd.x-f._start.x), + Math.abs(f._absEnd.y-f._start.y) + )>limit){ + this._create(f._start, f._end); + } + } + }, + _create: function(start,end){ + // create a new shape, needs to be accessible from the + // dragging functions. + var f=this.figure; + var _=f.nextKey(); + var a=new (this.annotation)(f, _); + a.transform={ + dx:f._calCol(start.x/f.zoomFactor), + dy:f._calCol(start.y/f.zoomFactor) + }; + a.end={ + x:f._calCol(end.x/f.zoomFactor), + y:f._calCol(end.y/f.zoomFactor) + }; + if(a.control){ + a.control={ + x:f._calCol((end.x/2)/f.zoomFactor), + y:f._calCol((end.y/2)/f.zoomFactor) + }; + } + f.onBeforeCreateShape(a); + a.initialize(); + f.select(a); + f.onCreateShape(a); + f.history.add(dojox.sketch.CommandTypes.Create,a); + } + }); + + dojox.sketch.Annotation=function(figure, id){ + // for editing stuff. + this.id=this._key=id; + this.figure=figure; + this.mode=dojox.sketch.Annotation.Modes.View; + this.shape=null; // dojox.gfx.Group + this.boundingBox=null; // rect for boundaries + this.hasAnchors=true; + this.anchors={}; // dojox.sketch.Anchor + this._properties={ + 'stroke':{ color:"blue", width:2 }, + 'font': {family:"Arial", size:16, weight:"bold"}, + 'fill': "blue", + 'label': "" + }; + + if(this.figure){ + this.figure.add(this); + } + }; + + var p=dojox.sketch.Annotation.prototype; + p.constructor=dojox.sketch.Annotation; + p.type=function(){ return ''; }; + p.getType=function(){ return dojox.sketch.Annotation; }; + p.onRemove=function(noundo){ + //this.figure._delete([this],noundo); + this.figure.history.add(dojox.sketch.CommandTypes.Delete, this, this.serialize()); + }; + p.property=function(name,/*?*/value){ + var r; + name=name.toLowerCase(); + if(this._properties[name]!==undefined){ + r=this._properties[name]; + } + if(arguments.length>1){ + this._properties[name]=value; + if(r!=value){ + this.onPropertyChange(name,r); + } + } + return r; + }; + p.onPropertyChange=function(name,oldvalue){}; + p.onCreate=function(){ + this.figure.history.add(dojox.sketch.CommandTypes.Create,this); + } + p.onDblClick=function(e){ + var l=prompt('Set new text:',this.property('label')); + if(l!==false){ + this.beginEdit(dojox.sketch.CommandTypes.Modify); + this.property('label',l); + this.draw(); + this.endEdit(); + } + } + p.initialize=function(){ }; + p.destroy=function(){ }; + p.draw=function(){ }; + p.apply=function(obj){ }; + p.serialize=function(){ }; + p.getBBox=function(){ }; + p.beginEdit=function(type){ + if(!this._type){ + this._type=type||dojox.sketch.CommandTypes.Move; + this._prevState=this.serialize(); + } + }; + p.endEdit=function(){ + if(this._prevState!=this.serialize()){ + this.figure.history.add(this._type,this,this._prevState); + } + this._type=this._prevState=''; + }; + p.calculate={ + slope:function(p1, p2){ + if(!(p1.x-p2.x)){ return 0; } + return ((p1.y-p2.y)/(p1.x-p2.x)); + }, + dx:function(p1, p2, dy){ + var s=this.slope(p1,p2); + if(s==0){ return s; } + return dy/s; + }, + dy:function(p1, p2, dx){ + return this.slope(p1,p2)*dx; + } + }; + p.drawBBox=function(){ + var r=this.getBBox(); + if(!this.boundingBox){ + this.boundingBox=this.shape.createRect(r) + .moveToBack() + .setStroke({color:"#999", width:1, style:"Dash"}) + .setFill([238,238,238,0.3]); + this.boundingBox.getEventSource().setAttribute("id",this.id+"-boundingBox"); + this.boundingBox.getEventSource().setAttribute("shape-rendering","crispEdges"); + this.figure._add(this); + } else { + this.boundingBox.setShape(r); + } + }; + p.setBinding=function(pt){ + this.transform.dx+=pt.dx; + this.transform.dy+=pt.dy; + this.draw(); + }; + //p.doChange=function(pt){ }; + p.getTextBox=function(zoomfactor){ + var fp=this.property('font'); + //_getTextBox expect style camlCase properties, do it manually here + var f = {fontFamily:fp.family,fontSize:fp.size,fontWeight:fp.weight}; + if(zoomfactor){ + f.fontSize = Math.floor(f.fontSize/zoomfactor); + } + return dojox.gfx._base._getTextBox(this.property('label'),f); + }; + p.setMode=function(m){ + if(this.mode==m){ return; } + this.mode=m; + var method="disable"; + if(m==dojox.sketch.Annotation.Modes.Edit){ method="enable"; } + if(method=="enable"){ + // draw the bounding box + this.drawBBox(); + this.figure._add(this); + } else { + if(this.boundingBox){ + if(this.shape){ this.shape.remove(this.boundingBox); } + this.boundingBox=null; + } + } + for(var p in this.anchors){ + this.anchors[p][method](); + } + }; + p.zoom=function(pct){ + pct = pct || this.figure.zoomFactor; + if(this.labelShape){ + var f=dojo.clone(this.property('font')); + f.size=Math.ceil(f.size/pct)+"px"; + this.labelShape.setFont(f); + } + + for(var n in this.anchors){ + this.anchors[n].zoom(pct); + } + + //In VML, path are always the same width no matter scaling factors, + //so aways use 1 for VML + if(dojox.gfx.renderer=='vml'){ + pct=1; + } + if(this.pathShape){ + var s=dojo.clone(this.property('stroke')); + s.width=pct>1?s.width:Math.ceil(s.width/pct)+"px"; + this.pathShape.setStroke(s); + } + }; + p.writeCommonAttrs=function(){ + return 'id="' + this.id + '" dojoxsketch:type="' + this.type() + '"' + + ' transform="translate('+ this.transform.dx + "," + this.transform.dy + ')"' + + (this.data?(' ><![CDATA[data:'+dojo.toJson(this.data)+']]'):''); + }; + p.readCommonAttrs=function(obj){ + var i=0,cs=obj.childNodes,c; + while((c=cs[i++])){ + if(c.nodeType==4){ //CDATA + if(c.nodeValue.substr(0,11)=='properties:'){ + this._properties=dojo.fromJson(c.nodeValue.substr(11)); + }else if(c.nodeValue.substr(0,5)=='data:'){ + this.data=dojo.fromJson(c.nodeValue.substr(5)); + }else{ + console.error('unknown CDATA node in node ',obj); + } + } + } + + if(obj.getAttribute('transform')){ + var t=obj.getAttribute('transform').replace("translate(",""); + var pt=t.split(","); + this.transform.dx=parseFloat(pt[0],10); + this.transform.dy=parseFloat(pt[1],10); + } + }; + dojox.sketch.Annotation.Modes={ View:0, Edit:1 }; + dojox.sketch.Annotation.register=function(name,toolclass){ + var cls=dojox.sketch[name+'Annotation']; + dojox.sketch.registerTool(name, function(p){ + dojo.mixin(p, { + shape: name, + annotation:cls + }); + return new (toolclass || dojox.sketch.AnnotationTool)(p); + }); + }; + + return dojox.sketch.Annotation; +}); diff --git a/js/dojo/dojox/sketch/DoubleArrowAnnotation.js b/js/dojo/dojox/sketch/DoubleArrowAnnotation.js new file mode 100644 index 0000000..fa1ba1c --- /dev/null +++ b/js/dojo/dojox/sketch/DoubleArrowAnnotation.js @@ -0,0 +1,233 @@ +//>>built +define("dojox/sketch/DoubleArrowAnnotation", ["dojo/_base/kernel", "dojo/_base/lang", "./Annotation", "./Anchor"], function(dojo){ + dojo.getObject("sketch", true, dojox); + var ta=dojox.sketch; + console.log(ta); + ta.DoubleArrowAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={ dx:0, dy:0 }; + this.start={x:0, y:0}; + this.control={x:100, y:-50}; + this.end={x:200, y:0}; + this.textPosition={ x:0, y:0 }; + this.textOffset=6; + this.textYOffset=10; + this.textAlign="middle"; + this.startRotation=0; + this.endRotation=0; + +// this.property('label',this.id); + this.labelShape=null; + this.pathShape=null; + this.startArrow=null; + this.startArrowGroup=null; + this.endArrow=null; + this.endArrowGroup=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.control=new ta.Anchor(this, "control"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.DoubleArrowAnnotation.prototype=new ta.Annotation; + var p=ta.DoubleArrowAnnotation.prototype; + p.constructor=ta.DoubleArrowAnnotation; + + p.type=function(){ return 'DoubleArrow'; }; + p.getType=function(){ return ta.DoubleArrowAnnotation; }; + + p._rot=function(){ + // arrowhead rotation + var opp=this.control.y-this.start.y; + var adj=this.control.x-this.start.x; + this.startRotation=Math.atan2(opp,adj); + + opp=this.end.y-this.control.y; + adj=this.end.x-this.control.x; + this.endRotation=Math.atan2(opp,adj); + }; + p._pos=function(){ + // text position + var offset=this.textOffset; + + // figure out the pull of the curve and place accordingly + if(this.control.y<this.end.y){ offset*=-1; } + else { offset+=this.textYOffset; } + var ab={ + x:((this.control.x-this.start.x)*.5)+this.start.x, + y:((this.control.y-this.start.y)*.5)+this.start.y + }; + var bc={ + x:((this.end.x-this.control.x)*.5)+this.control.x, + y:((this.end.y-this.control.y)*.5)+this.control.y + }; + this.textPosition={ + x:((bc.x-ab.x)*.5)+ab.x, + y:(((bc.y-ab.y)*.5)+ab.y)+offset + }; + }; + + p.apply=function(obj){ + if(!obj){ return; } + if(obj.documentElement){ obj=obj.documentElement; } + this.readCommonAttrs(obj); + + for(var i=0; i<obj.childNodes.length; i++){ + var c=obj.childNodes[i]; + if(c.localName=="text"){ this.property('label',c.childNodes.length?c.childNodes[0].nodeValue:''); } + else if(c.localName=="path"){ + // the line + var d=c.getAttribute('d').split(" "); + var s=d[0].split(","); + this.start.x=parseFloat(s[0].substr(1),10); + this.start.y=parseFloat(s[1],10); + s=d[1].split(","); + this.control.x=parseFloat(s[0].substr(1),10); + this.control.y=parseFloat(s[1],10); + s=d[2].split(","); + this.end.x=parseFloat(s[0],10); + this.end.y=parseFloat(s[1],10); + var stroke=this.property('stroke'); + var style=c.getAttribute('style'); + var m=style.match(/stroke:([^;]+);/); + if(m){ + stroke.color=m[1]; + this.property('fill',m[1]); + } + m=style.match(/stroke-width:([^;]+);/); + if(m){ + stroke.width=m[1]; + } + this.property('stroke',stroke); + } + } + }; + p.initialize=function(obj){ + // create, based on passed DOM node if available. + var font=(ta.Annotation.labelFont)?ta.Annotation.labelFont:{family:"Times", size:"16px"}; + this.apply(obj); + + // calculate the other positions + this._rot(); + this._pos(); + + // rotation matrix + var rot=this.startRotation; + var startRot=dojox.gfx.matrix.rotate(rot); + + rot=this.endRotation; + var endRot=dojox.gfx.matrix.rotateAt(rot, this.end.x, this.end.y); + + // draw the shapes + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + //if(this.transform.dx||this.transform.dy){ this.shape.setTransform(this.transform); } + + this.pathShape=this.shape.createPath("M"+this.start.x+" "+this.start.y+"Q"+this.control.x+" "+this.control.y+" "+this.end.x+" "+this.end.y + " l0,0") + //.setStroke(this.property('stroke')); + + this.startArrowGroup=this.shape.createGroup().setTransform({ dx:this.start.x, dy:this.start.y }); + this.startArrowGroup.applyTransform(startRot); + this.startArrow=this.startArrowGroup.createPath();//"M0,0 l20,-5 -3,5 3,5 Z").setFill(this.property('fill')); + + this.endArrowGroup=this.shape.createGroup().setTransform(endRot); + this.endArrow=this.endArrowGroup.createPath();//("M" + this.end.x + "," + this.end.y + " l-20,-5 3,5 -3,5 Z").setFill(this.property('fill')); + + this.labelShape=this.shape.createText({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label'), + align:this.textAlign + }) + //.setFont(font) + .setFill(this.property('fill')); + this.labelShape.getEventSource().setAttribute('id',this.id+"-labelShape"); + this.draw(); + }; + p.destroy=function(){ + if(!this.shape){ return; } + this.startArrowGroup.remove(this.startArrow); + this.endArrowGroup.remove(this.endArrow); + this.shape.remove(this.startArrowGroup); + this.shape.remove(this.endArrowGroup); + this.shape.remove(this.pathShape); + this.shape.remove(this.labelShape); + this.figure.group.remove(this.shape); + this.shape=this.pathShape=this.labelShape=this.startArrowGroup=this.startArrow=this.endArrowGroup=this.endArrow=null; + }; + p.draw=function(obj){ + this.apply(obj); + this._rot(); + this._pos(); + + // rotation matrix + var rot=this.startRotation; + var startRot=dojox.gfx.matrix.rotate(rot); + rot=this.endRotation; + var endRot=dojox.gfx.matrix.rotateAt(rot, this.end.x, this.end.y); + + this.shape.setTransform(this.transform); + this.pathShape.setShape("M"+this.start.x+" "+this.start.y+" Q"+this.control.x+" "+this.control.y+" "+this.end.x+" "+this.end.y + " l0,0") + //.setStroke(this.property('stroke')); + this.startArrowGroup.setTransform({ dx:this.start.x, dy:this.start.y }).applyTransform(startRot); + this.startArrow.setFill(this.property('fill')); + + this.endArrowGroup.setTransform(endRot); + this.endArrow.setFill(this.property('fill')); + this.labelShape.setShape({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label') + }) + .setFill(this.property('fill')); + this.zoom(); + }; + + p.zoom=function(pct){ + if(this.startArrow){ + pct = pct || this.figure.zoomFactor; + ta.Annotation.prototype.zoom.call(this,pct); + + var l=pct>1?20:Math.floor(20/pct), w=pct>1?5:Math.floor(5/pct),h=pct>1?3:Math.floor(3/pct); + this.startArrow.setShape("M0,0 l"+l+",-"+w+" -"+h+","+w+" "+h+","+w+" Z");//.setFill(this.property('fill')); + + this.endArrow.setShape("M" + this.end.x + "," + this.end.y + " l-"+l+",-"+w+" "+h+","+w+" -"+h+","+w+" Z"); + } + }; + + p.getBBox=function(){ + var x=Math.min(this.start.x, this.control.x, this.end.x); + var y=Math.min(this.start.y, this.control.y, this.end.y); + var w=Math.max(this.start.x, this.control.x, this.end.x)-x; + var h=Math.max(this.start.y, this.control.y, this.end.y)-y; + return { x:x, y:y, width:w, height:h }; + }; + + p.serialize=function(){ + var s=this.property('stroke'); + return '<g '+this.writeCommonAttrs()+'>' + + '<path style="stroke:'+s.color+';stroke-width:'+s.width+';fill:none;" d="' + + "M"+this.start.x+","+this.start.y+" " + + "Q"+this.control.x+","+this.control.y+" " + + this.end.x+","+this.end.y + + '" />' + + '<g transform="translate(' + this.start.x + "," + this.start.y + ") " + + 'rotate(' + (Math.round((this.startRotation*(180/Math.PI))*Math.pow(10,4))/Math.pow(10,4)) + ')">' + + '<path style="fill:'+s.color+';" d="M0,0 l20,-5, -3,5, 3,5 Z" />' + + '</g>' + + '<g transform="rotate(' + + (Math.round((this.endRotation*(180/Math.PI))*Math.pow(10,4))/Math.pow(10,4)) + + ", "+this.end.x+", "+this.end.y + + ')">' + + '<path style="fill:'+s.color+';" d="M'+this.end.x+","+this.end.y+' l-20,-5, 3,5, -3,5 Z" />' + + '</g>' + + '<text style="fill:'+s.color+';text-anchor:'+this.textAlign+'" font-weight="bold" ' + + 'x="' + this.textPosition.x + '" ' + + 'y="' + this.textPosition.y + '">' + + this.property('label') + + '</text>' + + '</g>'; + }; + + ta.Annotation.register("DoubleArrow"); + return dojox.sketch.DoubleArrowAnnotation; +}); diff --git a/js/dojo/dojox/sketch/Figure.js b/js/dojo/dojox/sketch/Figure.js new file mode 100644 index 0000000..81b5168 --- /dev/null +++ b/js/dojo/dojox/sketch/Figure.js @@ -0,0 +1,533 @@ +//>>built +define("dojox/sketch/Figure", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/connect", + "dojo/_base/html", + "../gfx", + "../xml/DomParser", + "./UndoStack" +], function(dojo){ + dojo.experimental("dojox.sketch"); + + var ta=dojox.sketch; + ta.tools={}; + ta.registerTool=function(type, fn){ ta.tools[type]=fn; }; + ta.Figure = function(mixin){ + var self=this; + this.annCounter=1; + + this.shapes=[]; + this.image=null; + this.imageSrc=null; + this.size={ w:0, h:0 }; + this.surface=null; + this.group=null; + //node should have tabindex set, otherwise keyboard action does not work + this.node=null; + + this.zoomFactor=1; // multiplier for zooming. + + this.tools=null; // toolbar reference. + + this.obj={}; // lookup table for shapes. Not keen on this solution. + + dojo.mixin(this,mixin); + + // what is selected. + this.selected=[]; + this.hasSelections=function(){ return this.selected.length>0 }; + this.isSelected=function(obj){ + for(var i=0; i<self.selected.length; i++){ + if(self.selected[i]==obj){ return true; } + } + return false; + }; + this.select=function(obj){ + // TODO: deal with multiple vs. single selections. + if(!self.isSelected(obj)){ + // force single select + self.clearSelections(); + self.selected=[ obj ]; + } + // force a bbox update, regardless + obj.setMode(ta.Annotation.Modes.View); + obj.setMode(ta.Annotation.Modes.Edit); + }; + this.deselect=function(obj){ + var idx=-1; + for(var i=0; i<self.selected.length; i++){ + if(self.selected[i]==obj){ + idx=i; + break; + } + } + if(idx>-1){ + obj.setMode(ta.Annotation.Modes.View); + self.selected.splice(idx,1); + } + return obj; + }; + this.clearSelections=function(){ + for(var i=0; i<self.selected.length; i++){ + self.selected[i].setMode(ta.Annotation.Modes.View); + } + self.selected=[]; + }; + this.replaceSelection=function(n, o){ + if(!self.isSelected(o)){ + self.select(n); + return; + } + var idx=-1; + for(var i=0; i<self.selected.length; i++){ + if(self.selected[i]==o){ + idx=i; + break; + } + } + if(idx>-1){ + self.selected.splice(idx,1,n); + } + }; + + // for the drag and drop handlers. + this._c=null; // current shape + this._ctr=null; // container measurements + this._lp=null; // last position + this._action=null; + this._prevState=null; + this._startPoint=null; // test to record a move. + + // if an object isn't selected and we're dragging anyways. + this._ctool=null; // hard code it. + this._start=null; + this._end=null; + this._absEnd=null; + this._cshape=null; + + this._dblclick=function(e){ + var o=self._fromEvt(e); + if(o){ + self.onDblClickShape(o,e); + } + }; + + this._keydown=function(e){ + var prevent=false; + if(e.ctrlKey){ + if(e.keyCode===90 || e.keyCode===122){ //ctrl+z + self.undo(); + prevent = true; + } + else if(e.keyCode===89 || e.keyCode===121){ //ctrl+y + self.redo(); + prevent = true; + } + } + + if(e.keyCode===46 || e.keyCode===8){ //delete or backspace + self._delete(self.selected); + prevent = true; + } + + if(prevent){ + dojo.stopEvent(e); + } + }; + + // drag handlers. + this._md=function(e){ + //in IE, when clicking into the drawing canvas, the node does not get focused, + //do it manually here to force it, otherwise the keydown event listener is + //never triggered in IE. + if(dojox.gfx.renderer=='vml'){ + self.node.focus(); + } + var o=self._fromEvt(e); + self._startPoint={ x:e.pageX, y:e.pageY }; + + self._ctr=dojo.position(self.node); + // figure out the coordinates taking scroll into account + var scroll={x:self.node.scrollLeft,y:self.node.scrollTop}; + //var win = dojo.window.get(self.node.ownerDocument); + //var scroll=dojo.withGlobal(win,dojo._docScroll); + self._ctr={x:self._ctr.x-scroll.x, y:self._ctr.y-scroll.y}; + var X=e.clientX-self._ctr.x, Y=e.clientY-self._ctr.y; + self._lp={ x:X, y:Y }; + + // capture it separately + self._start={ x:X, y:Y }; + self._end={ x:X, y:Y }; + self._absEnd={ x:X, y:Y }; + if(!o){ + self.clearSelections(); + self._ctool.onMouseDown(e); + }else{ + if(o.type && o.type()!="Anchor"){ + if(!self.isSelected(o)){ + self.select(o); + self._sameShapeSelected=false; + }else{ + self._sameShapeSelected=true; + } + } + o.beginEdit(); + self._c=o; + } + }; + this._mm=function(e){ + if(!self._ctr){ return; } + var x=e.clientX-self._ctr.x; + var y=e.clientY-self._ctr.y; + var dx=x-self._lp.x; + var dy=y-self._lp.y; + self._absEnd={x:x, y:y}; + if(self._c){ + //self._c.doChange({dx:dx, dy:dy}); + self._c.setBinding({dx:dx/self.zoomFactor, dy:dy/self.zoomFactor}); + self._lp={x:x, y:y}; + } else { + self._end={x:dx, y:dy}; + var rect={ + x:Math.min(self._start.x,self._absEnd.x), + y:Math.min(self._start.y,self._absEnd.y), + width:Math.abs(self._start.x-self._absEnd.x), + height:Math.abs(self._start.y-self._absEnd.y) + } + if(rect.width && rect.height){ + self._ctool.onMouseMove(e,rect); + } + } + }; + this._mu=function(e){ + if(self._c){ + // record the event. + self._c.endEdit(); + }else{ + self._ctool.onMouseUp(e); + } + + // clear the stuff out. + self._c=self._ctr=self._lp=self._action=self._prevState=self._startPoint=null; + self._cshape=self._start=self._end=self._absEnd=null; + }; + + this.initUndoStack(); + }; + + var p=ta.Figure.prototype; + p.initUndoStack=function(){ + this.history=new ta.UndoStack(this); + }; + p.setTool=function(/*dojox.sketch._Plugin*/t){ + this._ctool=t; + }; + //gridSize: int + // if it is greater than 0, all new shapes placed on the drawing will have coordinates + // snapped to the gridSize. For example, if gridSize is set to 10, all coordinates + // (only including coordinates which specifies the x/y position of shape are affected + // by this parameter) will be dividable by 10 + p.gridSize=0; + p._calCol=function(v){ + return this.gridSize?(Math.round(v/this.gridSize)*this.gridSize):v; + }; + p._delete=function(arr,noundo){ + for(var i=0; i<arr.length; i++){ + //var before=arr[i].serialize(); + arr[i].setMode(ta.Annotation.Modes.View); + arr[i].destroy(noundo); + this.remove(arr[i]); + this._remove(arr[i]); + if(!noundo){ + arr[i].onRemove(); + } + } + arr.splice(0,arr.length); + }; + p.onDblClickShape=function(shape,e){ + if(shape['onDblClick']){ + shape.onDblClick(e); + } + }; + + p.onCreateShape=function(shape){}; + p.onBeforeCreateShape=function(shape){}; + p.initialize=function(node){ + this.node=node; + this.surface=dojox.gfx.createSurface(node, this.size.w, this.size.h); + //this.backgroundRect=this.surface.createRect({ x:0, y:0, width:this.size.w, height:this.size.h }) + // .setFill("white"); + this.group=this.surface.createGroup(); + + this._cons=[]; + var es=this.surface.getEventSource(); + this._cons.push( + // kill any dragging events. + // for FF + dojo.connect(es, "ondraggesture", dojo.stopEvent), + dojo.connect(es, "ondragenter", dojo.stopEvent), + dojo.connect(es, "ondragover", dojo.stopEvent), + dojo.connect(es, "ondragexit", dojo.stopEvent), + dojo.connect(es, "ondragstart", dojo.stopEvent), + // for IE + dojo.connect(es, "onselectstart", dojo.stopEvent), + // hook up the drag system. + dojo.connect(es, 'onmousedown', this._md), + dojo.connect(es, 'onmousemove', this._mm), + dojo.connect(es, 'onmouseup', this._mu), + // misc hooks + dojo.connect(es, 'onclick', this, 'onClick'), + dojo.connect(es, 'ondblclick', this._dblclick), + dojo.connect(node, 'onkeydown', this._keydown)); + + this.image=this.group.createImage({ width:this.imageSize.w, height:this.imageSize.h, src:this.imageSrc }); + }; + + p.destroy=function(isLoading){ + if(!this.node){ return; } + if(!isLoading){ + if(this.history){ this.history.destroy(); } + if(this._subscribed){ + dojo.unsubscribe(this._subscribed); + delete this._subscribed; + } + } + dojo.forEach(this._cons, dojo.disconnect); + this._cons=[]; + + //TODO: how to destroy a surface properly? + dojo.empty(this.node); + + //this.node.removeChild(this.surface.getEventSource()); + this.group=this.surface=null; + this.obj={}; + this.shapes=[]; + }; + p.nextKey=function(){ return "annotation-"+this.annCounter++; }; + p.draw=function(){ }; + p.zoom=function(pct){ + // first get the new dimensions + this.zoomFactor=pct/100; + var w=this.size.w*this.zoomFactor; + var h=this.size.h*this.zoomFactor; + this.surface.setDimensions(w, h); + // then scale it. + this.group.setTransform(dojox.gfx.matrix.scale(this.zoomFactor, this.zoomFactor)); + + for(var i=0; i<this.shapes.length; i++){ + this.shapes[i].zoom(this.zoomFactor); + } + }; + p.getFit=function(){ + // assume fitting the parent node. +// var box=dojo.html.getContentBox(this.node.parentNode); + //the following should work under IE and FF, not sure about others though + var wF=(this.node.parentNode.offsetWidth-5)/this.size.w; + var hF=(this.node.parentNode.offsetHeight-5)/this.size.h; + return Math.min(wF, hF)*100; + }; + p.unzoom=function(){ + // restore original size. + this.zoomFactor=1; + this.surface.setDimensions(this.size.w, this.size.h); + this.group.setTransform(); + }; + + // object registry for drag handling. + p._add=function(obj){ this.obj[obj._key]=obj; }; + p._remove=function(obj){ + if(this.obj[obj._key]){ + delete this.obj[obj._key]; + } + }; + p._get=function(key){ + if(key&&key.indexOf("bounding")>-1){ + key=key.replace("-boundingBox",""); + }else if(key&&key.indexOf("-labelShape")>-1){ + key=key.replace("-labelShape",""); + } + return this.obj[key]; + }; + p._keyFromEvt=function(e){ + var key=e.target.id+""; + if(key.length==0){ + // ancestor tree until you get to the end (meaning this.surface) + var p=e.target.parentNode; + var node=this.surface.getEventSource(); + while(p && p.id.length==0 && p!=node){ + p=p.parentNode; + } + key=p.id; + } + return key; + }; + p._fromEvt=function(e){ + return this._get(this._keyFromEvt(e)); + }; + + p.add=function(annotation){ + for(var i=0; i<this.shapes.length; i++){ + if(this.shapes[i]==annotation){ return true; } + } + this.shapes.push(annotation); + return true; + }; + p.remove=function(annotation){ + var idx=-1; + for(var i=0; i<this.shapes.length; i++){ + if(this.shapes[i]==annotation){ + idx=i; + break; + } + } + if(idx>-1){ this.shapes.splice(idx, 1); } + return annotation; + }; + p.getAnnotator=function(id){ + for(var i=0; i<this.shapes.length; i++){ + if(this.shapes[i].id==id) { + return this.shapes[i]; + } + } + return null; + }; + + p.convert=function(ann, t){ + // convert an existing annotation to a different kind of annotation + var ctor=t+"Annotation"; + if(!ta[ctor]){ return; } + var type=ann.type(), id=ann.id, label=ann.label, mode=ann.mode, tokenId=ann.tokenId; + var start, end, control, transform; + switch(type){ + case "Preexisting": + case "Lead":{ + transform={dx:ann.transform.dx, dy:ann.transform.dy }; + start={x:ann.start.x, y:ann.start.y}; + end={x:ann.end.x, y:ann.end.y }; + var cx=end.x-((end.x-start.x)/2); + var cy=end.y-((end.y-start.y)/2); + control={x:cx, y:cy}; + break; + } + case "SingleArrow": + case "DoubleArrow":{ + transform={dx:ann.transform.dx, dy:ann.transform.dy }; + start={x:ann.start.x, y:ann.start.y}; + end={x:ann.end.x, y:ann.end.y }; + control={x:ann.control.x, y:ann.control.y}; + break; + } + case "Underline":{ + transform={dx:ann.transform.dx, dy:ann.transform.dy }; + start={x:ann.start.x, y:ann.start.y}; + control={x:start.x+50, y:start.y+50 }; + end={x:start.x+100, y:start.y+100 }; + break; + } + case "Brace":{ } + } + var n=new ta[ctor](this, id); + + if(n.type()=="Underline"){ + // special handling, since we never move the start point. + n.transform={dx:transform.dx+start.x, dy:transform.dy+start.y }; + } else { + if(n.transform){ n.transform=transform; } + if(n.start){ n.start=start; } + } + if(n.end){ n.end=end; } + if(n.control){ n.control=control; } + n.label=label; + n.token=dojo.lang.shallowCopy(ann.token); + n.initialize(); + + this.replaceSelection(n, ann); + this._remove(ann); + this.remove(ann); + ann.destroy(); + + // this should do all the things we need it to do for getting it registered. + n.setMode(mode); + }; + p.setValue=function(text){ + var obj=dojox.xml.DomParser.parse(text); + var node=this.node; + this.load(obj,node); + //this.zoom(this.zoomFactor*100); //zoom to orignal scale + }; + p.load=function(obj, n){ + // create from pseudo-DOM + if(this.surface){ this.destroy(true); } + var node=obj.documentElement; // should be either the document or the docElement + this.size={ + w:parseFloat(node.getAttribute('width'),10), + h:parseFloat(node.getAttribute('height'),10) + }; + var g=node.childrenByName("g")[0]; + var img=g.childrenByName("image")[0]; + this.imageSize={ + w:parseFloat(img.getAttribute('width'),10), + h:parseFloat(img.getAttribute('height'),10) + }; + this.imageSrc=img.getAttribute("xlink:href"); + this.initialize(n); + + // now let's do the annotations. + var ann=g.childrenByName("g"); + for(var i=0; i<ann.length; i++){ this._loadAnnotation(ann[i]); } + if(this._loadDeferred){ + this._loadDeferred.callback(this); + this._loadDeferred=null; + } + this.onLoad(); + }; + p.onLoad=function(){}; + p.onClick=function(){}; + p._loadAnnotation=function(obj){ + var ctor=obj.getAttribute('dojoxsketch:type')+"Annotation"; + if(ta[ctor]){ + var a=new ta[ctor](this, obj.id); + a.initialize(obj); + this.nextKey(); + a.setMode(ta.Annotation.Modes.View); + this._add(a); + return a; + } + return null; + }; + + p.onUndo=function(){}; + p.onBeforeUndo=function(){}; + p.onRedo=function(){}; + p.onBeforeRedo=function(){}; + p.undo=function(){ + if(this.history){ + this.onBeforeUndo(); + this.history.undo(); + this.onUndo(); + } + }; + p.redo=function(){ + if(this.history){ + this.onBeforeRedo(); + this.history.redo(); + this.onRedo(); + } + }; + p.serialize=function(){ + var s='<svg xmlns="http://www.w3.org/2000/svg" ' + + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + + 'xmlns:dojoxsketch="http://dojotoolkit.org/dojox/sketch" ' + + 'width="' + this.size.w + '" height="' + this.size.h + '">' + + '<g>' + + '<image xlink:href="' + this.imageSrc + '" x="0" y="0" width="' + + this.size.w + '" height="' + this.size.h + '" />'; + for(var i=0; i<this.shapes.length; i++){ s+= this.shapes[i].serialize(); } + s += '</g></svg>'; + return s; + }; + p.getValue=p.serialize; + + return dojox.sketch.Figure; +}); diff --git a/js/dojo/dojox/sketch/LeadAnnotation.js b/js/dojo/dojox/sketch/LeadAnnotation.js new file mode 100644 index 0000000..5d0def6 --- /dev/null +++ b/js/dojo/dojox/sketch/LeadAnnotation.js @@ -0,0 +1,162 @@ +//>>built +define("dojox/sketch/LeadAnnotation", ["dojo/_base/kernel", "dojo/_base/lang", "./Annotation", "./Anchor"], function(dojo){ + dojo.getObject("sketch", true, dojox); + + var ta=dojox.sketch; + ta.LeadAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={dx:0, dy:0 }; + this.start={ x:0, y:0 }; + this.control={x:100, y:-50}; + this.end={ x:200, y:0 }; + this.textPosition={ x:0, y:0 }; + this.textOffset=4; + //this.textAlign="middle"; + this.textYOffset=10; + +// this.property('label',this.id); + this.pathShape=null; + this.labelShape=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.control=new ta.Anchor(this, "control"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.LeadAnnotation.prototype=new ta.Annotation; + var p=ta.LeadAnnotation.prototype; + p.constructor=ta.LeadAnnotation; + + p.type=function(){ return 'Lead'; } + p.getType=function(){ return ta.LeadAnnotation; }; + + p._pos=function(){ + var offset=this.textOffset, x=0, y=0; + var slope=this.calculate.slope(this.control, this.end); + this.textAlign="middle"; + if(Math.abs(slope)>=1){ + x=this.end.x+this.calculate.dx(this.control, this.end, offset); + if(this.control.y>this.end.y){ + y=this.end.y-offset; + } else { + y=this.end.y+offset+this.textYOffset; + } + } else if(slope==0){ + x=this.end.x+offset; + y=this.end.y+this.textYOffset; + } else { + if(this.start.x>this.end.x){ + x=this.end.x-offset; + this.textAlign="end"; + } else { + x=this.end.x+offset; + this.textAlign="start"; + } + if(this.start.y<this.end.y){ + y=this.end.y+this.calculate.dy(this.control, this.end, offset)+this.textYOffset; + } else { + y=this.end.y+this.calculate.dy(this.control, this.end, -offset); + } + } + this.textPosition={ x:x, y:y }; + }; + p.apply=function(obj){ + if(!obj){ return; } + if(obj.documentElement){ obj=obj.documentElement; } + this.readCommonAttrs(obj); + + for(var i=0; i<obj.childNodes.length; i++){ + var c=obj.childNodes[i]; + if(c.localName=="text"){ + this.property('label',c.childNodes.length?c.childNodes[0].nodeValue:''); + } + else if(c.localName=="path"){ + // the line + var d=c.getAttribute('d').split(" "); + var s=d[0].split(","); + this.start.x=parseFloat(s[0].substr(1),10); + this.start.y=parseFloat(s[1],10); + s=d[1].split(","); + this.control.x=parseFloat(s[0].substr(1),10); + this.control.y=parseFloat(s[1],10); + s=d[2].split(","); + this.end.x=parseFloat(s[0],10); + this.end.y=parseFloat(s[1],10); + var stroke=this.property('stroke'); + var style=c.getAttribute('style'); + var m=style.match(/stroke:([^;]+);/); + if(m){ + stroke.color=m[1]; + this.property('fill',m[1]); + } + m=style.match(/stroke-width:([^;]+);/); + if(m){ + stroke.width=m[1]; + } + this.property('stroke',stroke); + } + } + }; + + p.initialize=function(obj){ + this.apply(obj); + this._pos(); + + // create either from scratch or based on the passed node + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + this.pathShape=this.shape.createPath("M"+this.start.x+","+this.start.y+" Q"+this.control.x+","+this.control.y+" "+this.end.x+","+this.end.y+" l0,0"); + this.labelShape=this.shape.createText({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label'), + align:this.textAlign + }); + this.labelShape.getEventSource().setAttribute('id',this.id+"-labelShape"); + this.draw(); + }; + p.destroy=function(){ + if(!this.shape){ return; } + this.shape.remove(this.pathShape); + this.shape.remove(this.labelShape); + this.figure.group.remove(this.shape); + this.shape=this.pathShape=this.labelShape=null; + }; + p.getBBox=function(){ + var x=Math.min(this.start.x, this.control.x, this.end.x); + var y=Math.min(this.start.y, this.control.y, this.end.y); + var w=Math.max(this.start.x, this.control.x, this.end.x)-x; + var h=Math.max(this.start.y, this.control.y, this.end.y)-y; + return { x:x, y:y, width:w, height:h }; + }; + p.draw=function(obj){ + this.apply(obj); + this._pos(); + this.shape.setTransform(this.transform); + this.pathShape.setShape("M"+this.start.x+","+this.start.y+" Q"+this.control.x+","+this.control.y+" "+this.end.x+","+this.end.y+" l0,0"); + this.labelShape.setShape({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label') + }) + .setFill(this.property('fill')); + this.zoom(); + }; + p.serialize=function(){ + var stroke=this.property('stroke'); + return '<g '+this.writeCommonAttrs()+'>' + + '<path style="stroke:'+stroke.color+';stroke-width:'+stroke.width+';fill:none;" d="' + + "M"+this.start.x+","+this.start.y+" " + + "Q"+this.control.x+","+this.control.y+" " + + this.end.x+","+this.end.y + + '" />' + + '<text style="fill:'+stroke.color+';text-anchor:'+this.textAlign+'" font-weight="bold" ' + + 'x="' + this.textPosition.x + '" ' + + 'y="' + this.textPosition.y + '">' + + this.property('label') + + '</text>' + + '</g>'; + }; + + ta.Annotation.register("Lead"); + return dojox.sketch.LeadAnnotation; +}); diff --git a/js/dojo/dojox/sketch/PreexistingAnnotation.js b/js/dojo/dojox/sketch/PreexistingAnnotation.js new file mode 100644 index 0000000..68c1fe6 --- /dev/null +++ b/js/dojo/dojox/sketch/PreexistingAnnotation.js @@ -0,0 +1,164 @@ +//>>built +define("dojox/sketch/PreexistingAnnotation", ["dojo/_base/kernel", "dojo/_base/lang", "./Annotation", "./Anchor"], function(dojo){ + dojo.getObject("sketch", true, dojox); + + var ta=dojox.sketch; + ta.PreexistingAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={dx:0, dy:0}; + this.start={ x:0, y:0 }; + this.end={ x:200, y:200 }; + this.radius=8; + this.textPosition={ x:196, y:196 }; + this.textOffset=4; + this.textAlign="end"; + + //this.property('label',this.id); + this.rectShape=null; + this.labelShape=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.PreexistingAnnotation.prototype=new ta.Annotation; + var p=ta.PreexistingAnnotation.prototype; + p.constructor=ta.PreexistingAnnotation; + + p.type=function(){ return 'Preexisting' }; + p.getType=function(){ return ta.PreexistingAnnotation; }; + + p._pos=function(){ + var x=Math.min(this.start.x, this.end.x); + var y=Math.min(this.start.y, this.end.y); + var w=Math.max(this.start.x, this.end.x); + var h=Math.max(this.start.y, this.end.y); + this.start={ x:x, y:y }; + this.end={ x:w, y:h }; + this.textPosition={ x:this.end.x-this.textOffset, y:this.end.y-this.textOffset }; + }; + p.apply=function(obj){ + if(!obj){ return; } + if(obj.documentElement){ obj=obj.documentElement; } + this.readCommonAttrs(obj); + + for(var i=0; i<obj.childNodes.length; i++){ + var c=obj.childNodes[i]; + if(c.localName=="text"){ + this.property('label',c.childNodes.length?c.childNodes[0].nodeValue:''); + } + else if(c.localName=="rect"){ + if(c.getAttribute('x')!==null){ this.start.x=parseFloat(c.getAttribute('x'), 10); } + if(c.getAttribute('width')!==null){ this.end.x=parseFloat(c.getAttribute('width'), 10)+parseFloat(c.getAttribute('x'), 10); } + if(c.getAttribute('y')!==null){ this.start.y=parseFloat(c.getAttribute('y'), 10); } + if(c.getAttribute('height')!==null){ this.end.y=parseFloat(c.getAttribute('height'), 10)+parseFloat(c.getAttribute('y'), 10); } + if(c.getAttribute('r')!==null){ this.radius=parseFloat(c.getAttribute('r'),10); } + var stroke=this.property('stroke'); + var style=c.getAttribute('style'); + var m=style.match(/stroke:([^;]+);/); + if(m){ + stroke.color=m[1]; + this.property('fill',m[1]); + } + m=style.match(/stroke-width:([^;]+);/); + if(m){ + stroke.width=m[1]; + } + this.property('stroke',stroke); + } + } + }; + p.initialize=function(obj){ + this.apply(obj); + this._pos(); + + // create either from scratch or based on the passed node + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + //if(this.transform.dx || this.transform.dy){ this.shape.setTransform(this.transform); } + this.rectShape=this.shape.createRect({ + x:this.start.x, + y: this.start.y, + width: this.end.x-this.start.x, + height:this.end.y-this.start.y, + r:this.radius + }) + //.setStroke({color:this.property('fill'), width:1}) + .setFill([255,255,255,0.1]); + this.rectShape.getEventSource().setAttribute("shape-rendering","crispEdges"); + this.labelShape=this.shape.createText({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label'), + align:this.textAlign + }) + //.setFont(font) + .setFill(this.property('fill')); + this.labelShape.getEventSource().setAttribute('id',this.id+"-labelShape"); + this.draw(); + }; + p.destroy=function(){ + if(!this.shape){ return; } + this.shape.remove(this.rectShape); + this.shape.remove(this.labelShape); + this.figure.group.remove(this.shape); + this.shape=this.rectShape=this.labelShape=null; + }; + p.getBBox=function(){ + var x=Math.min(this.start.x, this.end.x); + var y=Math.min(this.start.y, this.end.y); + var w=Math.max(this.start.x, this.end.x)-x; + var h=Math.max(this.start.y, this.end.y)-y; + return { x:x-2, y:y-2, width:w+4, height:h+4 }; + }; + p.draw=function(obj){ + this.apply(obj); + this._pos(); + this.shape.setTransform(this.transform); + this.rectShape.setShape({ + x:this.start.x, + y: this.start.y, + width: this.end.x-this.start.x, + height:this.end.y-this.start.y, + r:this.radius + }) + //.setStroke({ color:this.property('fill'), width:1 }) + .setFill([255,255,255,0.1]); + + this.labelShape.setShape({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label') + }) + .setFill(this.property('fill')); + this.zoom(); + }; + p.zoom=function(pct){ + if(this.rectShape){ + pct = pct || this.figure.zoomFactor; + ta.Annotation.prototype.zoom.call(this,pct); + pct = dojox.gfx.renderer=='vml'?1:pct; + this.rectShape.setStroke({color:this.property('fill'), width:1/pct}); + } + }; + p.serialize=function(){ + var s=this.property('stroke'); + return '<g '+this.writeCommonAttrs()+'>' + + '<rect style="stroke:'+s.color+';stroke-width:1;fill:none;" ' + + 'x="' + this.start.x + '" ' + + 'width="' + (this.end.x-this.start.x) + '" ' + + 'y="' + this.start.y + '" ' + + 'height="' + (this.end.y-this.start.y) + '" ' + + 'rx="' + this.radius + '" ' + + 'ry="' + this.radius + '" ' + + ' />' + + '<text style="fill:'+s.color+';text-anchor:'+this.textAlign+'" font-weight="bold" ' + + 'x="' + this.textPosition.x + '" ' + + 'y="' + this.textPosition.y + '">' + + this.property('label') + + '</text>' + + '</g>'; + }; + + ta.Annotation.register("Preexisting"); + return dojox.sketch.PreexistingAnnotation; +}); diff --git a/js/dojo/dojox/sketch/README b/js/dojo/dojox/sketch/README new file mode 100644 index 0000000..217d3e9 --- /dev/null +++ b/js/dojo/dojox/sketch/README @@ -0,0 +1,58 @@ +------------------------------------------------------------------------------- +dojox.sketch +------------------------------------------------------------------------------- +Version 0.1 +Release date: 28/01/2008 +------------------------------------------------------------------------------- +Project state: +experimental +------------------------------------------------------------------------------- +Credits + Contributed by TeamPatent (supported by National Science Foundation grant 638334) + Tom Trenka (ttrenka@gmail.com) + Heng Liu/LiuCougar (heng@teampatent.com) +------------------------------------------------------------------------------- +Project description + +A cross-browser drawing editor based on dojox.gfx. +------------------------------------------------------------------------------- +Dependencies: + +dijit (Toolbar, Button, Slider) +dojox.gfx +dojox.xml +------------------------------------------------------------------------------- +Documentation + +Currently, 5 shapes are supported: line, single arrow line, double arrow line, +underline text and text. The first 3 shapes can have optinal text associated. + +Shapes can be added, deleted, moved and modified. All of these operations can +be undo-ed or redo-ed. + +TODO: + * provide UI to change various properties on shapes (fill, stroke, text) and +allow changing of background image + * serialize/unserialize in dojox.gfx to svg (and maybe vml as well?) (or another +simplier format? such as a json based one, which is easier to parse, and then +write a convertor to convert the json format to svg or any other format?) + * Move mousedown/up/move to each shape (to prepare for the following) + * Add shapes for other primitive shapes (needs to decide which primitive +dojox.gfx.shapes are useful), and add in support for user to group any +shapes/groups to form a single "compound shape" (need to add support to set +fill/stroke properties on the entire compound shape, which shallpropagate to +all children shapes) +------------------------------------------------------------------------------- +Installation instructions + +Install dijit, dojox.gfx and dojox.xml first + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/sketch.js +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/sketch/* + +Install into the following directory structure: +/dojox/sketch/ + +...which should be at the same level as your Dojo checkout. +------------------------------------------------------------------------------- diff --git a/js/dojo/dojox/sketch/SingleArrowAnnotation.js b/js/dojo/dojox/sketch/SingleArrowAnnotation.js new file mode 100644 index 0000000..42f17fb --- /dev/null +++ b/js/dojo/dojox/sketch/SingleArrowAnnotation.js @@ -0,0 +1,227 @@ +//>>built +define("dojox/sketch/SingleArrowAnnotation", ["dojo/_base/kernel", "dojo/_base/lang", "./Annotation", "./Anchor"], function(dojo){ + dojo.getObject("sketch", true, dojox); + + var ta=dojox.sketch; + ta.SingleArrowAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={ dx:0, dy:0 }; + this.start={x:0, y:0}; + this.control={x:100, y:-50}; + this.end={x:200, y:0}; + this.textPosition={ x:0, y:0 }; + this.textOffset=4; + //this.textAlign="middle"; + this.textYOffset=10; + this.rotation=0; + +// this.property('label',this.id); +// this.label=this.id; + this.pathShape=null; + this.arrowhead=null; + this.arrowheadGroup=null; + this.labelShape=null; + + this.anchors.start=new ta.Anchor(this, "start"); + this.anchors.control=new ta.Anchor(this, "control"); + this.anchors.end=new ta.Anchor(this, "end"); + }; + ta.SingleArrowAnnotation.prototype=new ta.Annotation; + var p=ta.SingleArrowAnnotation.prototype; + p.constructor=ta.SingleArrowAnnotation; + + p.type=function(){ return 'SingleArrow'; }; + p.getType=function(){ return ta.SingleArrowAnnotation; }; + + // helper functions + p._rot=function(){ + // arrowhead rotation + var opp=this.control.y-this.start.y; + var adj=this.control.x-this.start.x; + //if(!adj){ adj=1; } + this.rotation=Math.atan2(opp,adj); + }; + p._pos=function(){ + // text position + var offset=this.textOffset, x=0, y=0; + var slope=this.calculate.slope(this.control, this.end); + this.textAlign="middle"; + if(Math.abs(slope)>=1){ + x=this.end.x+this.calculate.dx(this.control, this.end, offset); + if(this.control.y>this.end.y){ y=this.end.y-offset; } + else{ y=this.end.y+offset+this.textYOffset; } + } else if(slope==0){ + x=this.end.x+offset; + y=this.end.y+this.textYOffset; + } else { + if(this.start.x>this.end.x){ + x=this.end.x-offset; + this.textAlign="end"; + } else { + x=this.end.x+offset; + this.textAlign="start"; + } + if(this.start.y<this.end.y){ + y=this.end.y+this.calculate.dy(this.control, this.end, offset)+this.textYOffset; + } else { + y=this.end.y+this.calculate.dy(this.control, this.end, -offset); + } + } + this.textPosition={ x:x, y:y }; + }; + + p.apply=function(obj){ + if(!obj){ return; } + if(obj.documentElement){ obj=obj.documentElement; } + this.readCommonAttrs(obj); + + for(var i=0; i<obj.childNodes.length; i++){ + var c=obj.childNodes[i]; + if(c.localName=="text"){ + this.property('label',c.childNodes.length?c.childNodes[0].nodeValue:''); + } + else if(c.localName=="path"){ + // the line + var d=c.getAttribute('d').split(" "); + var s=d[0].split(","); + this.start.x=parseFloat(s[0].substr(1),10); + this.start.y=parseFloat(s[1],10); + s=d[1].split(","); + this.control.x=parseFloat(s[0].substr(1),10); + this.control.y=parseFloat(s[1],10); + s=d[2].split(","); + this.end.x=parseFloat(s[0],10); + this.end.y=parseFloat(s[1],10); + var stroke=this.property('stroke'); + var style=c.getAttribute('style'); + var m=style.match(/stroke:([^;]+);/); + if(m){ + stroke.color=m[1]; + this.property('fill',m[1]); + } + m=style.match(/stroke-width:([^;]+);/); + if(m){ + stroke.width=m[1]; + } + this.property('stroke',stroke); + } + } + }; + p.initialize=function(obj){ + // create, based on passed DOM node if available. + var font=(ta.Annotation.labelFont)?ta.Annotation.labelFont:{family:"Times", size:"16px"}; + this.apply(obj); + + // calculate the other positions + this._rot(); + this._pos(); + + // rotation matrix + var rot=this.rotation; + var tRot=dojox.gfx.matrix.rotate(rot); + + // draw the shapes + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + //if(this.transform.dx||this.transform.dy){ this.shape.setTransform(this.transform); } + + this.pathShape=this.shape.createPath("M"+this.start.x+","+this.start.y+" Q"+this.control.x+","+this.control.y+" "+this.end.x+","+this.end.y+" l0,0") + //.setStroke(this.property('stroke')); + + this.arrowheadGroup=this.shape.createGroup();//.setTransform({ dx:this.start.x, dy:this.start.y }).applyTransform(tRot); + this.arrowhead=this.arrowheadGroup.createPath();//"M0,0 l50,-10 -6,10 6,10 Z").setFill(this.property('fill')); + + this.labelShape=this.shape.createText({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label'), + align:this.textAlign + }) + //.setFont(font) + //.setFill(this.property('fill')); + this.labelShape.getEventSource().setAttribute('id',this.id+"-labelShape"); + this.draw(); + }; + + p.destroy=function(){ + if(!this.shape){ return; } + this.arrowheadGroup.remove(this.arrowhead); + this.shape.remove(this.arrowheadGroup); + this.shape.remove(this.pathShape); + this.shape.remove(this.labelShape); + this.figure.group.remove(this.shape); + this.shape=this.pathShape=this.labelShape=this.arrowheadGroup=this.arrowhead=null; + }; + + p.draw=function(obj){ + this.apply(obj); + this._rot(); + this._pos(); + + // rotation matrix + var rot=this.rotation; + var tRot=dojox.gfx.matrix.rotate(rot); + + this.shape.setTransform(this.transform); + this.pathShape.setShape("M"+this.start.x+","+this.start.y+" Q"+this.control.x+","+this.control.y+" "+this.end.x+","+this.end.y+" l0,0") + //.setStroke(this.property('stroke')); + + this.arrowheadGroup.setTransform({dx:this.start.x,dy:this.start.y}).applyTransform(tRot); + this.arrowhead.setFill(this.property('fill')); + + this.labelShape.setShape({ + x:this.textPosition.x, + y:this.textPosition.y, + text:this.property('label'), + align:this.textAlign + }) + .setFill(this.property('fill')); + this.zoom(); + }; + + p.zoom=function(pct){ + if(this.arrowhead){ + pct = pct || this.figure.zoomFactor; + ta.Annotation.prototype.zoom.call(this,pct); + //pct = dojox.gfx.renderer=='vml'?1:pct; + if(this._curPct!==pct){ + this._curPct=pct; + var l=pct>1?20:Math.floor(20/pct), w=pct>1?5:Math.floor(5/pct),h=pct>1?3:Math.floor(3/pct); + this.arrowhead.setShape("M0,0 l"+l+",-"+w+" -"+h+","+w+" "+h+","+w+" Z"); + } + } + }; + + p.getBBox=function(){ + var x=Math.min(this.start.x, this.control.x, this.end.x); + var y=Math.min(this.start.y, this.control.y, this.end.y); + var w=Math.max(this.start.x, this.control.x, this.end.x)-x; + var h=Math.max(this.start.y, this.control.y, this.end.y)-y; + return { x:x, y:y, width:w, height:h }; + }; + + p.serialize=function(){ + var s=this.property('stroke'); + var r=this.rotation*(180/Math.PI); + r=Math.round(r*Math.pow(10,4))/Math.pow(10,4); + return '<g '+this.writeCommonAttrs()+'>' + + '<path style="stroke:'+s.color+';stroke-width:'+s.width+';fill:none;" d="' + + "M"+this.start.x+","+this.start.y+" " + + "Q"+this.control.x+","+this.control.y+" " + + this.end.x+","+this.end.y + + '" />' + + '<g transform="translate(' + this.start.x + "," + this.start.y + ") " + + 'rotate(' + r + ')">' + + '<path style="fill:'+s.color+';" d="M0,0 l20,-5, -3,5, 3,5 Z" />' + + '</g>' + + '<text style="fill:'+s.color+';text-anchor:'+this.textAlign+'" font-weight="bold" ' + + 'x="' + this.textPosition.x + '" ' + + 'y="' + this.textPosition.y + '">' + + this.property('label') + + '</text>' + + '</g>'; + }; + + ta.Annotation.register("SingleArrow"); + return dojox.sketch.SingleArrowAnnotation; +}); diff --git a/js/dojo/dojox/sketch/Slider.js b/js/dojo/dojox/sketch/Slider.js new file mode 100644 index 0000000..4c4b433 --- /dev/null +++ b/js/dojo/dojox/sketch/Slider.js @@ -0,0 +1,43 @@ +//>>built +define("dojox/sketch/Slider", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/declare", + "dijit/form/HorizontalSlider", + "./_Plugin" +], function(dojo){ + dojo.getObject("sketch", true, dojox); + dojo.declare("dojox.sketch.Slider", dojox.sketch._Plugin,{ + _initButton: function(){ + this.slider=new dijit.form.HorizontalSlider({minimum:5,maximum:100,style:"width:100px;",baseClass:'dijitInline dijitSlider'}); + this.slider._movable.node.title='Double Click to "Zoom to Fit"'; //I18N + this.connect(this.slider,'onChange','_setZoom'); + this.connect(this.slider.sliderHandle,'ondblclick','_zoomToFit'); + }, + _zoomToFit: function(){ + var r=this.figure.getFit(); + this.slider.attr('value',this.slider.maximum<r?this.slider.maximum:(this.slider.minimum>r?this.slider.minimum:r)); + }, + _setZoom: function(v){ + if(v && this.figure){ + this.figure.zoom(v); + } + }, + reset: function(){ + //reset slider to maximum so that onChange will be fired when _zoomToFit is called + this.slider.attr('value',this.slider.maximum); + this._zoomToFit(); + }, + setToolbar: function(t){ + this._initButton(); + t.addChild(this.slider); + if(!t._reset2Zoom){ + t._reset2Zoom=true; + this.connect(t,'reset','reset'); + } + } + }); + + dojox.sketch.registerTool("Slider", dojox.sketch.Slider); + return dojox.sketch.Slider; +}); diff --git a/js/dojo/dojox/sketch/Toolbar.js b/js/dojo/dojox/sketch/Toolbar.js new file mode 100644 index 0000000..5da42fc --- /dev/null +++ b/js/dojo/dojox/sketch/Toolbar.js @@ -0,0 +1,104 @@ +//>>built +define("dojox/sketch/Toolbar", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/declare", + "./Annotation", + "dijit/Toolbar", + "dijit/form/Button" +], function(dojo){ + dojo.getObject("sketch", true, dojox); + dojo.declare("dojox.sketch.ButtonGroup", null, { + constructor: function(){ + this._childMaps={}; + this._children=[]; + }, + add: function(/*_Plugin*/ plugin){ + this._childMaps[plugin]=plugin.connect(plugin,'onActivate',dojo.hitch(this,'_resetGroup',plugin)); + this._children.push(plugin); + }, + // remove: function(/*_Plugin*/ plugin){ + // widget.disconnect(this._childMaps[widget.id]); + // delete this._childMaps[widget.id]; + // this._children.splice(this._children.indexOf(widget.id),1); + // }, + _resetGroup: function(p){ + var cs=this._children; + dojo.forEach(cs,function(c){ + if(p!=c && c['attr']){ + c.attr('checked',false); + } + }); + } + }); + + dojo.declare("dojox.sketch.Toolbar", dijit.Toolbar, { + figure: null, + plugins: null, + postCreate: function(){ + this.inherited(arguments); + this.shapeGroup=new dojox.sketch.ButtonGroup; + + if(!this.plugins){ + this.plugins=['Lead','SingleArrow','DoubleArrow','Underline','Preexisting','Slider']; + } + this._plugins=[]; + + dojo.forEach(this.plugins,function(obj){ + var name=dojo.isString(obj)?obj:obj.name; + var p=new dojox.sketch.tools[name](obj.args||{}); + this._plugins.push(p); + p.setToolbar(this); + if(!this._defaultTool && p.button){ + this._defaultTool=p; + } + },this); + }, + setFigure: function(f){ + this.figure = f; + this.connect(f,'onLoad','reset'); + dojo.forEach(this._plugins, function(p){ + p.setFigure(f); + }); + }, + destroy: function(){ + dojo.forEach(this._plugins,function(p){ + p.destroy(); + }); + this.inherited(arguments); + delete this._defaultTool; + delete this._plugins; + }, + addGroupItem: function(/*_Plugin*/item,group){ + if(group!='toolsGroup'){ + console.error('not supported group '+group); + return; + } + + this.shapeGroup.add(item); + }, + reset: function(){ + this._defaultTool.activate(); + }, + _setShape: function(s){ + if(!this.figure.surface) return; + // now do the action. + if(this.figure.hasSelections()){ + for(var i=0; i<this.figure.selected.length; i++){ + var before=this.figure.selected[i].serialize(); + this.figure.convert(this.figure.selected[i], s); + this.figure.history.add(dojox.sketch.CommandTypes.Convert, this.figure.selected[i], before); + } + } + } + }); + + dojox.sketch.makeToolbar=function(node,figure){ + var toolbar=new dojox.sketch.Toolbar(); + toolbar.setFigure(figure); + node.appendChild(toolbar.domNode); + return toolbar; + }; + + return dojox.sketch.Toolbar; +}); diff --git a/js/dojo/dojox/sketch/UnderlineAnnotation.js b/js/dojo/dojox/sketch/UnderlineAnnotation.js new file mode 100644 index 0000000..e873074 --- /dev/null +++ b/js/dojo/dojox/sketch/UnderlineAnnotation.js @@ -0,0 +1,145 @@ +//>>built +define("dojox/sketch/UnderlineAnnotation", ["./Annotation", "./Anchor"], function(){ + var ta=dojox.sketch; + ta.UnderlineAnnotation=function(figure, id){ + ta.Annotation.call(this, figure, id); + this.transform={dx:0, dy:0}; + this.start={x:0, y:0}; + this.property('label','#'); + this.labelShape=null; + this.lineShape=null; + //this.anchors.start=new ta.Anchor(this, "start"); + }; + ta.UnderlineAnnotation.prototype=new ta.Annotation; + var p=ta.UnderlineAnnotation.prototype; + p.constructor=ta.UnderlineAnnotation; + + p.type=function(){ return 'Underline'; }; + p.getType=function(){ return ta.UnderlineAnnotation; }; + + p.apply=function(obj){ + if(!obj){ return; } + if(obj.documentElement){ obj=obj.documentElement; } + this.readCommonAttrs(obj); + + for(var i=0; i<obj.childNodes.length; i++){ + var c=obj.childNodes[i]; + if(c.localName=="text"){ + this.property('label',c.childNodes[0].nodeValue); + var style=c.getAttribute('style'); + var m=style.match(/fill:([^;]+);/); + if(m){ + var stroke=this.property('stroke'); + stroke.collor=m[1]; + this.property('stroke',stroke); + this.property('fill',stroke.collor); + } + }/*else if(c.localName=="line"){ + var stroke=this.property('stroke'); + var style=c.getAttribute('style'); + var m=style.match(/stroke:([^;]+);/)[1]; + if(m){ + stroke.color=m; + this.property('fill',m); + } + m=style.match(/stroke-width:([^;]+);/)[1]; + if(m){ + stroke.width=m; + } + this.property('stroke',stroke); + }*/ + } + }; + + p.initialize=function(obj){ + //var font=(ta.Annotation.labelFont)?ta.Annotation.labelFont:{family:"Times", size:"16px"}; + this.apply(obj); + + // create either from scratch or based on the passed node + this.shape=this.figure.group.createGroup(); + this.shape.getEventSource().setAttribute("id", this.id); + //if(this.transform.dx || this.transform.dy){ this.shape.setTransform(this.transform); } + + this.labelShape=this.shape.createText({ + x:0, + y:0, + text:this.property('label'), + decoration:"underline", + align:"start" + }) + //.setFont(font) + //.setFill(this.property('fill')); + this.labelShape.getEventSource().setAttribute('id',this.id+"-labelShape"); + + this.lineShape=this.shape.createLine({ + x1:1, + x2:this.labelShape.getTextWidth(), + y1:2, + y2:2 + }) + //.setStroke({ color:this.property('fill'), width:1 }); + this.lineShape.getEventSource().setAttribute("shape-rendering","crispEdges"); + this.draw(); + }; + p.destroy=function(){ + if(!this.shape){ return; } + this.shape.remove(this.labelShape); + this.shape.remove(this.lineShape); + this.figure.group.remove(this.shape); + this.shape=this.lineShape=this.labelShape=null; + }; + p.getBBox=function(){ + var b=this.getTextBox(); + var z=this.figure.zoomFactor; + + return { x:0, y:(b.h*-1+4)/z, width:(b.w+2)/z, height:b.h/z }; + }; + p.draw=function(obj){ + this.apply(obj); + this.shape.setTransform(this.transform); + this.labelShape.setShape({ x:0, y:0, text:this.property('label') }) + .setFill(this.property('fill')); + this.zoom(); + }; + p.zoom=function(pct){ + if(this.labelShape){ + pct = pct || this.figure.zoomFactor; + var textwidthadj=dojox.gfx.renderer=='vml'?0:2/pct; + ta.Annotation.prototype.zoom.call(this,pct); + pct = dojox.gfx.renderer=='vml'?1:pct; + this.lineShape.setShape({ x1:0, x2:this.getBBox().width-textwidthadj, y1:2, y2:2 }) + .setStroke({ color:this.property('fill'), width:1/pct }); + if(this.mode==ta.Annotation.Modes.Edit){ + this.drawBBox(); //the bbox is dependent on the size of the text, so need to update it here + } + } + }; + p.serialize=function(){ + var s=this.property('stroke'); + return '<g '+this.writeCommonAttrs()+'>' + //+ '<line x1="1" x2="'+this.labelShape.getTextWidth()+1+'" y1="5" y2="5" style="stroke:'+s.color+';stroke-width:'+s.width+';" />' + + '<text style="fill:'+this.property('fill')+';" font-weight="bold" text-decoration="underline" ' + + 'x="0" y="0">' + + this.property('label') + + '</text>' + + '</g>'; + }; + + //customize AnnotationTool to place a underlilne shape onmouseup, no need + //to drag a box (like other shapes) + dojo.declare("dojox.sketch.UnderlineAnnotationTool", ta.AnnotationTool, { + onMouseDown: function(){}, + onMouseUp: function(){ + var f=this.figure; + if(!f._start){ + return; + } + //zero out end so that the clickover is shown at the right pos + f._end={x:0,y:0}; + this._create(f._start,{x:f._start.x+10,y:f._start.y+10}); + }, + onMouseMove: function(){} + }); + ta.Annotation.register("Underline", ta.UnderlineAnnotationTool); + return dojox.sketch.UnderlineAnnotation; +}); diff --git a/js/dojo/dojox/sketch/UndoStack.js b/js/dojo/dojox/sketch/UndoStack.js new file mode 100644 index 0000000..5b8643c --- /dev/null +++ b/js/dojo/dojox/sketch/UndoStack.js @@ -0,0 +1,106 @@ +//>>built +define("dojox/sketch/UndoStack", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/declare", + "../xml/DomParser" +], function(dojo){ + dojo.getObject("sketch", true, dojox); + var ta=dojox.sketch; + ta.CommandTypes={ Create:"Create", Move:"Move", Modify:"Modify", Delete:"Delete", Convert:"Convert"}; + + dojo.declare("dojox.sketch.UndoStack",null,{ + constructor: function(figure){ + this.figure=figure; + this._steps=[]; + this._undoedSteps=[]; + }, + apply: function(state, from, to){ + // the key here is to neutrally move from one state to another. + // we let the individual functions (i.e. undo and redo) actually + // determine the from and to; all we do here is implement it. + + // check whether this is a fullText step + if(!from && !to && state.fullText){ + this.figure.setValue(state.fullText); + return; + } + + var fromText=from.shapeText; + var toText=to.shapeText; + + if(fromText.length==0&&toText.length==0){ + // nothing to reapply? + return; + } + if(fromText.length==0){ + // We are creating. + var o=dojox.xml.DomParser.parse(toText).documentElement; + var a=this.figure._loadAnnotation(o); + if(a) this.figure._add(a); + return; + } + if(toText.length==0){ + // we are deleting. + var ann=this.figure.getAnnotator(from.shapeId); + this.figure._delete([ann],true); + return; + } + + // we can simply reinit and draw from the shape itself, + // regardless of the actual command. + var nann=this.figure.getAnnotator(to.shapeId); + var no=dojox.xml.DomParser.parse(toText).documentElement; + nann.draw(no); + this.figure.select(nann); + return; + }, + // stack methods. + add: function(/*String*/cmd, /*ta.Annotation?*/ann, /*String?*/before){ + var id=ann?ann.id:''; + //var bbox=ann?ann.getBBox():{}; + var after=ann?ann.serialize():""; + if(cmd==ta.CommandTypes.Delete){ after=""; } + + /*if(ann){ + // fix the bbox x/y coords + var t=ann.transform; + bbox.x+=t.dx; + bbox.y+=t.dy; + }*/ + var state={ + cmdname:cmd, + //bbox:bbox, +// fullText:fullText, + before:{ + shapeId: id, + shapeText:before||'' + }, + after:{ + shapeId: id, + shapeText:after + } + }; + //console.log('dojox.sketch history add',state); + this._steps.push(state); + this._undoedSteps = []; + }, + destroy: function(){}, + undo: function(){ + var state=this._steps.pop(); + if(state){ + this._undoedSteps.push(state); + this.apply(state,state.after,state.before); + } + }, + redo: function(){ + var state=this._undoedSteps.pop(); + if(state){ + this._steps.push(state); + this.apply(state,state.before,state.after); + } + } + }); + + return dojox.sketch.UndoStack; +}); diff --git a/js/dojo/dojox/sketch/_Plugin.js b/js/dojo/dojox/sketch/_Plugin.js new file mode 100644 index 0000000..0e68d49 --- /dev/null +++ b/js/dojo/dojox/sketch/_Plugin.js @@ -0,0 +1,82 @@ +//>>built +define("dojox/sketch/_Plugin", [ + "dojo/_base/kernel", + "dojo/_base/lang", + "dojo/_base/array", + "dojo/_base/declare", + "dojo/_base/connect", + "dijit/form/ToggleButton" +], function(dojo){ + dojo.getObject("sketch", true, dojox); + dojo.declare("dojox.sketch._Plugin", null, { + // summary + // This represents a "plugin" to the dojox.sketch.Figure, which is basically + // a single button on the Toolbar and some associated code + constructor: function(/*Object?*/args){ + if(args){ + dojo.mixin(this, args); + } + this._connects=[]; + }, + + figure: null, + iconClassPrefix: "dojoxSketchIcon", + itemGroup: 'toolsGroup', + button: null, + queryCommand: null, + shape: "", + useDefaultCommand: true, + buttonClass: dijit.form.ToggleButton, + _initButton: function(){ + if(this.shape.length){ + //TODO: i18n + // var label = dojox.sketch.shapes[this.shape]; + var className = this.iconClassPrefix+" "+this.iconClassPrefix + this.shape.charAt(0).toUpperCase() + this.shape.substr(1); + if(!this.button){ + var props = { + label: this.shape, //I18N + showLabel: false, + iconClass: className, + dropDown: this.dropDown, + tabIndex: "-1" + }; + this.button = new this.buttonClass(props); + this.connect(this.button,'onClick','activate'); + } + } + }, + attr: function(name,/*?*/value){ + return this.button.attr(name,value); + }, + onActivate: function(){}, + activate: function(/*?*/e){ + this.onActivate(); + this.figure.setTool(this); + this.attr('checked',true); + }, + onMouseDown: function(e){}, + onMouseMove: function(e){}, + onMouseUp: function(e){}, + destroy: function(f){ + dojo.forEach(this._connects,dojo.disconnect); + }, + connect: function(o,f,tf){ + this._connects.push(dojo.connect(o,f,this,tf)); + }, + setFigure: function(/*dijit._Widget*/ figure){ + // FIXME: detatch from previous figure!! + this.figure = figure; + }, + setToolbar: function(/*dijit._Widget*/ toolbar){ + // FIXME: prevent creating this if we don't need to (i.e., figure can't handle our command) + this._initButton(); + if(this.button){ + toolbar.addChild(this.button); + } + if(this.itemGroup){ + toolbar.addGroupItem(this,this.itemGroup); + } + } + }); + return dojox.sketch._Plugin; +}); diff --git a/js/dojo/dojox/sketch/resources/images/icons.gif b/js/dojo/dojox/sketch/resources/images/icons.gif Binary files differnew file mode 100644 index 0000000..ab33b0a --- /dev/null +++ b/js/dojo/dojox/sketch/resources/images/icons.gif diff --git a/js/dojo/dojox/sketch/resources/sketch.css b/js/dojo/dojox/sketch/resources/sketch.css new file mode 100644 index 0000000..7451395 --- /dev/null +++ b/js/dojo/dojox/sketch/resources/sketch.css @@ -0,0 +1,17 @@ +.dojoxSketchIcon{ + background-repeat:no-repeat; + height:16px; + min-width:16px; + text-align:center; + width:16px; +} +.dojoxSketchIcon { background-image:url(images/icons.gif); } +.ShowCallouts{ background-position:0px 0px; } +.PreviousCallout{ background-position:0px -16px; } +.NextCallout{ background-position:0px -32px; } +.dojoxSketchIconLead{ background-position:0px -48px; } +.dojoxSketchIconUnderline{ background-position:0px -64px; } +.dojoxSketchIconSingleArrow{ background-position:0px -80px; } +.dojoxSketchIconBrace{ background-position:0px -96px; } +.dojoxSketchIconDoubleArrow{ background-position:0px -112px; } +.dojoxSketchIconPreexisting{ background-position:0px -128px; } |
