diff options
Diffstat (limited to 'includes/js/dojox/sketch/Figure.js')
-rw-r--r-- | includes/js/dojox/sketch/Figure.js | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/includes/js/dojox/sketch/Figure.js b/includes/js/dojox/sketch/Figure.js new file mode 100644 index 0000000..ae573bb --- /dev/null +++ b/includes/js/dojox/sketch/Figure.js @@ -0,0 +1,493 @@ +if(!dojo._hasResource["dojox.sketch.Figure"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojox.sketch.Figure"] = true; +dojo.provide("dojox.sketch.Figure"); +dojo.experimental("dojox.sketch"); + +dojo.require("dojox.gfx"); +dojo.require("dojox.sketch.UndoStack"); + +(function(){ + var ta=dojox.sketch; + ta.tools={}; + ta.registerTool=function(type, fn){ ta.tools[type]=fn; }; + ta.Figure = function(){ + var self=this; + var annCounter=1; + + this.shapes=[]; + this.image=null; + this.imageSrc=null; + this.size={ w:0, h:0 }; + this.surface=null; + this.group=null; + this.node=null; + + this.zoomFactor=1; // multiplier for zooming. + + this.tools=null; // toolbar reference. + this.nextKey=function(){ return annCounter++; }; + + this.obj={}; // lookup table for shapes. Not keen on this solution. + + this.initUndoStack(); + + // 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._click=function(e){ + if(self._c){ + dojo.stopEvent(e); + return; + } + var o=self._fromEvt(e); + if(!o){ + self.clearSelections(); + dojo.stopEvent(e); + } else if(!o.setMode){ + // skip me. + } else self.select(o); + }; + 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){ //ctrl+z + self.undo(); + prevent = true; + }else if(e.keyCode==89){ //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){ + var o=self._fromEvt(e); + self._startPoint={ x:e.pageX, y:e.pageY }; + var win = dijit.getDocumentWindow(self.node.ownerDocument); + // figure out the coordinates within the iframe + self._ctr=dojo._abs(self.node); + 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"){ + self.select(o); + } + 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:Math.round(dx/self.zoomFactor), dy:Math.round(dy/self.zoomFactor)}); + self._c.setBinding({dx:Math.round(dx/self.zoomFactor), dy:Math.round(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) + } + 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._delete=function(arr,noundo){ + for(var i=0; i<arr.length; i++){ + //var before=arr[i].serialize(); + if(!noundo){ + arr[i].remove(); + } + arr[i].setMode(ta.Annotation.Modes.View); + arr[i].destroy(); + self.remove(arr[i]); + self._remove(arr[i]); + } + arr.splice(0,arr.length); + }; + }; + + var p=ta.Figure.prototype; + p.initUndoStack=function(){ + this.history=new ta.UndoStack(this); + }; + p.setTool=function(/*dojox.sketch._Plugin*/t){ + this._ctool=t; + }; + 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.surface.createRect({ x:0, y:0, width:this.size.w, height:this.size.h }) + .setFill("white"); + this.group=this.surface.createGroup(); + + // kill any dragging events. + this._cons=[]; + this._cons.push(dojo.connect(this.node, "ondragstart", dojo, "stopEvent")); + this._cons.push(dojo.connect(this.node, "onselectstart", dojo, "stopEvent")); + + // hook up the drag system. + this._cons.push(dojo.connect(this.surface.getEventSource(), 'onmousedown', this._md)); + this._cons.push(dojo.connect(this.surface.getEventSource(), 'onmousemove', this._mm)); + this._cons.push(dojo.connect(this.surface.getEventSource(), 'onmouseup', this._mu)); + + this._cons.push(dojo.connect(this.surface.getEventSource(), 'ondblclick', this._dblclick)); + this._cons.push(dojo.connect(this.surface.getEventSource().ownerDocument, 'onkeydown', this._keydown)); + + // rect hack. Fcuking VML> + this.group.createRect({ x:0, y:0, width:this.size.w, height:this.size.h }); + this.image=this.group.createImage({ width:this.size.w, height:this.size.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=[]; + + this.node.removeChild(this.surface.getEventSource()); + this.group=this.surface=null; + this.obj={}; + this.shapes=[]; + }; + 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)); + if(dojo.isIE){ + this.image.rawNode.style.width=Math.max(w,this.size.w); + this.image.rawNode.style.height=Math.max(h,this.size.h); + } + //this.rect.setShape({width:w,height:h}); + }; + 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.clientWidth-5)/this.size.w; + var hF=(this.node.parentNode.clientHeight-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",""); + return this.obj[key]; + }; + p._fromEvt=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 this._get(key); + }; + + 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.get=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.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._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; +})(); + +} |