Annotation.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.sketch.Annotation"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.sketch.Annotation"] = true;
  8. dojo.provide("dojox.sketch.Annotation");
  9. dojo.require("dojox.sketch.Anchor");
  10. dojo.require("dojox.sketch._Plugin");
  11. (function(){
  12. var ta=dojox.sketch;
  13. dojo.declare("dojox.sketch.AnnotationTool", ta._Plugin, {
  14. onMouseDown: function(e){
  15. this._omd=true;
  16. },
  17. onMouseMove: function(e,rect){
  18. if(!this._omd){
  19. return;
  20. }
  21. if(this._cshape){
  22. this._cshape.setShape(rect);
  23. } else {
  24. this._cshape=this.figure.surface.createRect(rect)
  25. .setStroke({color:"#999", width:1, style:"ShortDot"})
  26. .setFill([255,255,255,0.7]);
  27. this._cshape.getEventSource().setAttribute("shape-rendering","crispEdges");
  28. }
  29. },
  30. onMouseUp: function(e){
  31. if(!this._omd){
  32. return;
  33. }
  34. this._omd=false;
  35. var f=this.figure;
  36. if(this._cshape){
  37. f.surface.remove(this._cshape);
  38. delete this._cshape;
  39. }
  40. if(!(f._startPoint.x==e.pageX&&f._startPoint.y==e.pageY)){
  41. // The minimum number of pixels one has to travel before a shape
  42. // gets drawn.
  43. var limit=10;
  44. if(Math.max(
  45. limit,
  46. Math.abs(f._absEnd.x-f._start.x),
  47. Math.abs(f._absEnd.y-f._start.y)
  48. )>limit){
  49. this._create(f._start, f._end);
  50. }
  51. }
  52. },
  53. _create: function(start,end){
  54. // create a new shape, needs to be accessible from the
  55. // dragging functions.
  56. var f=this.figure;
  57. var _=f.nextKey();
  58. var a=new (this.annotation)(f, _);
  59. a.transform={
  60. dx:f._calCol(start.x/f.zoomFactor),
  61. dy:f._calCol(start.y/f.zoomFactor)
  62. };
  63. a.end={
  64. x:f._calCol(end.x/f.zoomFactor),
  65. y:f._calCol(end.y/f.zoomFactor)
  66. };
  67. if(a.control){
  68. a.control={
  69. x:f._calCol((end.x/2)/f.zoomFactor),
  70. y:f._calCol((end.y/2)/f.zoomFactor)
  71. };
  72. }
  73. f.onBeforeCreateShape(a);
  74. a.initialize();
  75. f.select(a);
  76. f.onCreateShape(a);
  77. f.history.add(ta.CommandTypes.Create,a);
  78. }
  79. });
  80. ta.Annotation=function(figure, id){
  81. // for editing stuff.
  82. this.id=this._key=id;
  83. this.figure=figure;
  84. this.mode=ta.Annotation.Modes.View;
  85. this.shape=null; // dojox.gfx.Group
  86. this.boundingBox=null; // rect for boundaries
  87. this.hasAnchors=true;
  88. this.anchors={}; // ta.Anchor
  89. this._properties={
  90. 'stroke':{ color:"blue", width:2 },
  91. 'font': {family:"Arial", size:16, weight:"bold"},
  92. 'fill': "blue",
  93. 'label': ""
  94. };
  95. if(this.figure){
  96. this.figure.add(this);
  97. }
  98. };
  99. var p=ta.Annotation.prototype;
  100. p.constructor=ta.Annotation;
  101. p.type=function(){ return ''; };
  102. p.getType=function(){ return ta.Annotation; };
  103. p.onRemove=function(noundo){
  104. //this.figure._delete([this],noundo);
  105. this.figure.history.add(ta.CommandTypes.Delete, this, this.serialize());
  106. };
  107. p.property=function(name,/*?*/value){
  108. var r;
  109. name=name.toLowerCase();
  110. if(this._properties[name]!==undefined){
  111. r=this._properties[name];
  112. }
  113. if(arguments.length>1){
  114. this._properties[name]=value;
  115. if(r!=value){
  116. this.onPropertyChange(name,r);
  117. }
  118. }
  119. return r;
  120. };
  121. p.onPropertyChange=function(name,oldvalue){};
  122. p.onCreate=function(){
  123. this.figure.history.add(ta.CommandTypes.Create,this);
  124. }
  125. p.onDblClick=function(e){
  126. var l=prompt('Set new text:',this.property('label'));
  127. if(l!==false){
  128. this.beginEdit(ta.CommandTypes.Modify);
  129. this.property('label',l);
  130. this.draw();
  131. this.endEdit();
  132. }
  133. }
  134. p.initialize=function(){ };
  135. p.destroy=function(){ };
  136. p.draw=function(){ };
  137. p.apply=function(obj){ };
  138. p.serialize=function(){ };
  139. p.getBBox=function(){ };
  140. p.beginEdit=function(type){
  141. if(!this._type){
  142. this._type=type||ta.CommandTypes.Move;
  143. this._prevState=this.serialize();
  144. }
  145. };
  146. p.endEdit=function(){
  147. if(this._prevState!=this.serialize()){
  148. this.figure.history.add(this._type,this,this._prevState);
  149. }
  150. this._type=this._prevState='';
  151. };
  152. p.calculate={
  153. slope:function(p1, p2){
  154. if(!(p1.x-p2.x)){ return 0; }
  155. return ((p1.y-p2.y)/(p1.x-p2.x));
  156. },
  157. dx:function(p1, p2, dy){
  158. var s=this.slope(p1,p2);
  159. if(s==0){ return s; }
  160. return dy/s;
  161. },
  162. dy:function(p1, p2, dx){
  163. return this.slope(p1,p2)*dx;
  164. }
  165. };
  166. p.drawBBox=function(){
  167. var r=this.getBBox();
  168. if(!this.boundingBox){
  169. this.boundingBox=this.shape.createRect(r)
  170. .moveToBack()
  171. .setStroke({color:"#999", width:1, style:"Dash"})
  172. .setFill([238,238,238,0.3]);
  173. this.boundingBox.getEventSource().setAttribute("id",this.id+"-boundingBox");
  174. this.boundingBox.getEventSource().setAttribute("shape-rendering","crispEdges");
  175. this.figure._add(this);
  176. } else {
  177. this.boundingBox.setShape(r);
  178. }
  179. };
  180. p.setBinding=function(pt){
  181. this.transform.dx+=pt.dx;
  182. this.transform.dy+=pt.dy;
  183. this.draw();
  184. };
  185. //p.doChange=function(pt){ };
  186. p.getTextBox=function(zoomfactor){
  187. var fp=this.property('font');
  188. //_getTextBox expect style camlCase properties, do it manually here
  189. var f = {fontFamily:fp.family,fontSize:fp.size,fontWeight:fp.weight};
  190. if(zoomfactor){
  191. f.fontSize = Math.floor(f.fontSize/zoomfactor);
  192. }
  193. return dojox.gfx._base._getTextBox(this.property('label'),f);
  194. };
  195. p.setMode=function(m){
  196. if(this.mode==m){ return; }
  197. this.mode=m;
  198. var method="disable";
  199. if(m==ta.Annotation.Modes.Edit){ method="enable"; }
  200. if(method=="enable"){
  201. // draw the bounding box
  202. this.drawBBox();
  203. this.figure._add(this);
  204. } else {
  205. if(this.boundingBox){
  206. if(this.shape){ this.shape.remove(this.boundingBox); }
  207. this.boundingBox=null;
  208. }
  209. }
  210. for(var p in this.anchors){
  211. this.anchors[p][method]();
  212. }
  213. };
  214. p.zoom=function(pct){
  215. pct = pct || this.figure.zoomFactor;
  216. if(this.labelShape){
  217. var f=dojo.clone(this.property('font'));
  218. f.size=Math.ceil(f.size/pct)+"px";
  219. this.labelShape.setFont(f);
  220. }
  221. for(var n in this.anchors){
  222. this.anchors[n].zoom(pct);
  223. }
  224. //In VML, path are always the same width no matter scaling factors,
  225. //so aways use 1 for VML
  226. if(dojox.gfx.renderer=='vml'){
  227. pct=1;
  228. }
  229. if(this.pathShape){
  230. var s=dojo.clone(this.property('stroke'));
  231. s.width=pct>1?s.width:Math.ceil(s.width/pct)+"px";
  232. this.pathShape.setStroke(s);
  233. }
  234. };
  235. p.writeCommonAttrs=function(){
  236. return 'id="' + this.id + '" dojoxsketch:type="' + this.type() + '"'
  237. + ' transform="translate('+ this.transform.dx + "," + this.transform.dy + ')"'
  238. + (this.data?(' ><![CDATA[data:'+dojo.toJson(this.data)+']]'):'');
  239. };
  240. p.readCommonAttrs=function(obj){
  241. var i=0,cs=obj.childNodes,c;
  242. while((c=cs[i++])){
  243. if(c.nodeType==4){ //CDATA
  244. if(c.nodeValue.substr(0,11)=='properties:'){
  245. this._properties=dojo.fromJson(c.nodeValue.substr(11));
  246. }else if(c.nodeValue.substr(0,5)=='data:'){
  247. this.data=dojo.fromJson(c.nodeValue.substr(5));
  248. }else{
  249. console.error('unknown CDATA node in node ',obj);
  250. }
  251. }
  252. }
  253. if(obj.getAttribute('transform')){
  254. var t=obj.getAttribute('transform').replace("translate(","");
  255. var pt=t.split(",");
  256. this.transform.dx=parseFloat(pt[0],10);
  257. this.transform.dy=parseFloat(pt[1],10);
  258. }
  259. };
  260. ta.Annotation.Modes={ View:0, Edit:1 };
  261. ta.Annotation.register=function(name,toolclass){
  262. var cls=ta[name+'Annotation'];
  263. ta.registerTool(name, function(p){
  264. dojo.mixin(p, {
  265. shape: name,
  266. annotation:cls
  267. });
  268. return new (toolclass || ta.AnnotationTool)(p);
  269. });
  270. };
  271. })();
  272. }