source: Dev/branches/rest-dojo-ui/client/dojox/drawing/Drawing.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

  • Property svn:executable set to *
File size: 18.7 KB
Line 
1dojo.provide("dojox.drawing.Drawing");
2
3(function(){
4       
5        var _plugsInitialized = false;
6       
7        dojo.declare("dojox.drawing.Drawing", [], {
8                // summary:
9                //              Drawing is a project that sits on top of DojoX GFX and uses SVG and
10                //              VML vector graphics to draw and display.
11                // description:
12                //              Drawing is similar to DojoX Sketch, but is designed to be more versatile
13                //              extendable and customizable.
14                //              Drawing currently only initiates from HTML although it's technically not
15                //              a Dijit to keep the file size light. But if Dijit is available, Drawing
16                //              will register itself with it and can be accessed dijit.byId('myDrawing')
17                //
18                //      NOTES:
19                //              Although not Drawing and Toolbar, all other objects are created with a custom
20                //              declare. See dojox.drawing.util.oo
21                //
22                //The files are laid out as such:
23                //              - Drawing
24                //                      The master class. More than one instance of a Drawing can be placed
25                //                      on a page at one time (although this has not yet been tested). Plugins
26                //                      can be added in markup.
27                //      - Toolbar
28                //                      Like Drawing, Toolbar is a psudeo Dijit that does not need Dijit. It is
29                //                      optional. It can be oriented horizontal or vertical by placing one of
30                //                      those params in the class (at least one is required).  Plugins
31                //                      can be added in markup. A drawingId is required to point toolbar to
32                //                      the drawing.
33                //              - defaults
34                //                      Contains the default styles and dimensions for Stencils. An individual
35                //                      Stencil can be changed by calling stencil.att({color obj}); To change
36                //                      all styles, a custom defaults file should be used.
37                //              -Stencils
38                //                      Drawing uses a concept of 'Stencils' to avoid confusion between a
39                //                      Dojox Shape and a Drawing Shape. The classes in the 'stencils' package
40                //                      are display only, they are not used for actually drawing (see 'tools').
41                //                      This package contains _Base from which stencils inherit most of their
42                //                      methods.(Path and Image are display only and not found in Tools)
43                //              - Tools
44                //                      The Tools package contains Stencils that are attached to mouse events
45                //                      and can be used for drawing. Items in this package can also be selected
46                //                      and modified.
47                //              - Tools / Custom
48                //                      Holds tools that do not directly extend Stencil base classes and often
49                //                      have very custom code.
50                //              - Library (not implemented)
51                //                      The Library package, which is not yet implemented, will be the place to
52                //                      hold stencils that have very specific data points that result in a picture.
53                //                      Flag-like-banners, fancy borders, or other complex shapes would go here.
54                //              - Annotations
55                //                      Annotations 'decorate' and attach to other Stencils, such as a 'Label'
56                //                      that can show text on a stencil, or an 'Angle' that shows while dragging
57                //                      or modifying a Vector, or an Arrow head that is attached to the beginning
58                //                      or end of a line.
59                //              - Manager
60                //                      Contains classes that control functionality of a Drawing.
61                //              - Plugins
62                //                      Contains optional classes that are 'plugged into' a Drawing. There are two
63                //                      types: 'drawing' plugins that modify the canvas, and 'tools' which would
64                //                      show in the toolbar.
65                //              - Util
66                //                      A collection of common tasks.
67                //
68                // example:
69                //              |       <div dojoType="dojox.drawing.Drawing" id="drawing" defaults="myCustom.defaults"
70                //              |               plugins="[{'name':'dojox.drawing.plugins.drawing.Grid', 'options':{gap:100}}]">
71                //              |   </div>
72                //
73                //      example:
74                //              |       <div dojoType="dojox.drawing.Toolbar" drawingId="drawing" class="drawingToolbar vertical">
75                //              |               <div tool="dojox.drawing.tools.Line" selected="false">Line</div>
76                //              |               <div tool="dojox.drawing.tools.Rect" selected="false">Rect</div>
77                //              |               <div tool="dojox.drawing.tools.Ellipse" selected="false">Ellipse</div>
78                //              |               <div tool="dojox.drawing.tools.TextBlock" selected="false">Statement</div>
79                //              |               <div tool="dojox.drawing.tools.custom.Equation" selected="false">Equation</div>
80                //              |               <div plugin="dojox.drawing.plugins.tools.Pan" options="{}">Pan</div>
81                //              |               <div plugin="dojox.drawing.plugins.tools.Zoom" options="{zoomInc:.1,minZoom:.5,maxZoom:2}">Zoom</div>
82                //              |       </div>
83                //
84                //
85                // ready: Boolean
86                //      Whether or not the canvas has been created and Stencils can be added
87                ready:false,
88                // mode: [optional] String
89                //              Changes the functionality of the drawing
90                mode: "",
91                // width: Number
92                //              Width of the canvas
93                width:0,
94                //
95                // height: Number
96                //              Height of the canvas
97                height:0,
98                //
99                // defaults : Object
100                //              Optional replacements for native defaults.
101                // plugins: Object
102                //              Key values of plugins that apply to canvas.
103                //
104                constructor: function(/* Object */props, /* HTMLNode */node){
105                        // summary:
106                        //              Drawing is not a Dijit. This is the master method.
107                        //              NOTE:
108                        //                      props is always null since this is not a real widget
109                        //                      Will change when Drawing can be created programmatically.
110                        //
111                        var def = dojo.attr(node, "defaults");
112                        if(def){
113                                dojox.drawing.defaults =  dojo.getObject(def);
114                        }
115                        this.defaults =  dojox.drawing.defaults;
116                       
117                        this.id = node.id;
118                        dojox.drawing.register(this, "drawing");
119                        this.mode = (props.mode || dojo.attr(node, "mode") || "").toLowerCase();
120                        var box = dojo.contentBox(node);
121                        this.width = box.w;
122                        this.height = box.h;
123                        this.util = dojox.drawing.util.common;
124                        this.util.register(this); // So Toolbar can find this Drawing DEPRECATED
125                        this.keys = dojox.drawing.manager.keys;
126                        this.mouse = new dojox.drawing.manager.Mouse({util:this.util, keys:this.keys, id:this.mode=="ui"?"MUI":"mse"});
127                        this.mouse.setEventMode(this.mode);
128                       
129                        this.tools = {};
130                        this.stencilTypes = {};
131                        this.stencilTypeMap = {};
132                        this.srcRefNode = node; // need this?
133                        this.domNode = node;
134                        if(props.plugins){
135                                this.plugins = eval(props.plugins);
136                        }else{
137                                this.plugins = [];
138                        }
139                       
140                        this.widgetId = this.id;
141                        dojo.attr(this.domNode, "widgetId", this.widgetId);
142                        // If Dijit is available in the page, register with it
143                        if(dijit && dijit.registry){
144                                dijit.registry.add(this);
145                                console.log("using dijit")
146                        }else{
147                                // else fake dijit.byId
148                                // FIXME: This seems pretty hacky.
149                                // Maybe should just encourage jsId
150                                dijit.registry = {
151                                        objs:{},
152                                        add:function(obj){
153                                                this.objs[obj.id] = obj;
154                                        }
155                                };
156                                dijit.byId = function(id){
157                                        return dijit.registry.objs[id];
158                                };
159                                dijit.registry.add(this);
160                        }
161                       
162                        var stencils = dojox.drawing.getRegistered("stencil");
163                        for(var nm in stencils){
164                                this.registerTool(stencils[nm].name);
165                        }
166                        var tools = dojox.drawing.getRegistered("tool");
167                        for(nm in tools){
168                                this.registerTool(tools[nm].name);
169                        }
170                        var plugs = dojox.drawing.getRegistered("plugin");
171                        for(nm in plugs){
172                                this.registerTool(plugs[nm].name);
173                        }
174                        this._createCanvas();
175                       
176                },
177               
178                _createCanvas: function(){
179                        console.info("drawing create canvas...");
180                        this.canvas = new dojox.drawing.manager.Canvas({
181                                srcRefNode:this.domNode,
182                                util:this.util,
183                                mouse:this.mouse,
184                                callback: dojo.hitch(this, "onSurfaceReady")
185                        });
186                        this.initPlugins();
187                },
188               
189                resize: function(/* Object */box){
190                        // summary:
191                        //              Resizes the canvas.
192                        //              If within a ContentPane this will get called automatically.
193                        //              Can also be called directly.
194                        //
195                        box && dojo.style(this.domNode, {
196                                width:box.w+"px",
197                                height:box.h+"px"
198                        });
199                        if(!this.canvas){
200                                this._createCanvas();
201                        }else if(box){
202                                this.canvas.resize(box.w, box.h);
203                        }
204                },
205               
206                startup: function(){
207                        //console.info("drawing startup")
208                },
209               
210                getShapeProps: function(/* Object */data, mode){
211                        // summary:
212                        //              The common objects that are mixed into
213                        //              a new Stencil. Mostly internal, but could be used.
214                        //
215                        var surface = data.stencilType;
216                        var ui = this.mode=="ui" || mode=="ui";
217                        return dojo.mixin({
218                                container: ui && !surface ? this.canvas.overlay.createGroup() : this.canvas.surface.createGroup(),
219                                util:this.util,
220                                keys:this.keys,
221                                mouse:this.mouse,
222                                drawing:this,
223                                drawingType: ui && !surface ? "ui" : "stencil",
224                                style:this.defaults.copy()
225                        }, data || {});
226                },
227               
228                addPlugin: function(/* Object */plugin){
229                        // summary:
230                        //              Add a toolbar plugin object to plugins array
231                        //              to be parsed
232                        this.plugins.push(plugin);
233                        if(this.canvas.surfaceReady){
234                                this.initPlugins();
235                        }
236                },
237               
238                initPlugins: function(){
239                        // summary:
240                        //              Called from Toolbar after a plugin has been loaded
241                        //              The call to this coming from toobar is a bit funky as the timing
242                        //              of IE for canvas load is different than other browsers
243                        if(!this.canvas || !this.canvas.surfaceReady){
244                                var c = dojo.connect(this, "onSurfaceReady", this, function(){
245                                        dojo.disconnect(c);
246                                        this.initPlugins();
247                                });
248                                return;
249                        }
250                        dojo.forEach(this.plugins, function(p, i){
251                                var props = dojo.mixin({
252                                        util:this.util,
253                                        keys:this.keys,
254                                        mouse:this.mouse,
255                                        drawing:this,
256                                        stencils:this.stencils,
257                                        anchors:this.anchors,
258                                        canvas:this.canvas
259                                }, p.options || {});
260                                //console.log('drawing.plugin:::', p.name, props)
261                                this.registerTool(p.name, dojo.getObject(p.name));
262                                try{
263                                        this.plugins[i] = new this.tools[p.name](props);
264                                }catch(e){
265                                        console.error("Failed to initilaize plugin:     " +p.name + ". Did you require it?");
266                                }
267                        }, this);
268                        this.plugins = [];
269                        _plugsInitialized = true;
270                        // In IE, because the timing is different we have to get the
271                        // canvas position after everything has drawn. *sigh*
272                        this.mouse.setCanvas();
273                },
274               
275                onSurfaceReady: function(){
276                        // summary:
277                        //              Event that to which can be connected.
278                        //              Fired when the canvas is ready and can be drawn to.
279                        //
280                        this.ready = true;
281                        //console.info("Surface ready")
282                        this.mouse.init(this.canvas.domNode);
283                        this.undo = new dojox.drawing.manager.Undo({keys:this.keys});
284                        this.anchors = new dojox.drawing.manager.Anchors({drawing:this, mouse:this.mouse, undo:this.undo, util:this.util});
285                        if(this.mode == "ui"){
286                                this.uiStencils = new dojox.drawing.manager.StencilUI({canvas:this.canvas, surface:this.canvas.surface, mouse:this.mouse, keys:this.keys});
287                        }else{
288                                this.stencils = new dojox.drawing.manager.Stencil({canvas:this.canvas, surface:this.canvas.surface, mouse:this.mouse, undo:this.undo, keys:this.keys, anchors:this.anchors});
289                                this.uiStencils = new dojox.drawing.manager.StencilUI({canvas:this.canvas, surface:this.canvas.surface, mouse:this.mouse, keys:this.keys});
290                        }
291                        if(dojox.gfx.renderer=="silverlight"){
292                                try{
293                                new dojox.drawing.plugins.drawing.Silverlight({util:this.util, mouse:this.mouse, stencils:this.stencils, anchors:this.anchors, canvas:this.canvas});
294                                }catch(e){
295                                        throw new Error("Attempted to install the Silverlight plugin, but it was not found.");
296                                }
297                        }
298                        dojo.forEach(this.plugins, function(p){
299                                p.onSurfaceReady && p.onSurfaceReady();
300                        });
301               
302                },
303               
304                addUI: function(/* String */type, /* Object */options){
305                        // summary:
306                        //              Use this method to programmatically add Stencils that display on
307                        //              the canvas.
308                        //              FIXME: Currently only supports Stencils that have been registered,
309                        //                      which is items in the toolbar, and the additional Stencils at the
310                        //                      end of onSurfaceReady. This covers all Stencils, but you can't
311                        //                      use 'display only' Stencils for Line, Rect, and Ellipse.
312                        //              arguments:
313                        //                      type: String
314                        //                              The final name of the tool, lower case: 'image', 'line', 'textBlock'
315                        //              options:
316                        //                      type: Object
317                        //                              The parameters used to draw the object. See stencil._Base and each
318                        //                              tool for specific parameters of teh data or points objects.
319                        //
320                        if(!this.ready){
321                                var c = dojo.connect(this, "onSurfaceReady", this, function(){
322                                        dojo.disconnect(c);
323                                        this.addUI(type, options);
324                                });
325                                return false;
326                        }
327                        if(options && !options.data && !options.points){
328                                options = {data:options}
329                        }
330                        if(!this.stencilTypes[type]){
331                                if(type != "tooltip"){
332                                        console.warn("Not registered:", type);
333                                }
334                                return null;
335                        }
336                        var s = this.uiStencils.register( new this.stencilTypes[type](this.getShapeProps(options, "ui")));
337                        return s;
338                },
339               
340               
341                addStencil: function(/* String */type, /* Object */options){
342                        // summary:
343                        //              Use this method to programmatically add Stencils that display on
344                        //              the canvas.
345                        //              FIXME: Currently only supports Stencils that have been registered,
346                        //                      which is items in the toolbar, and the additional Stencils at the
347                        //                      end of onSurfaceReady. This covers all Stencils, but you can't
348                        //                      use 'display only' Stencils for Line, Rect, and Ellipse.
349                        //              arguments:
350                        //                      type: String
351                        //                              The final name of the tool, lower case: 'image', 'line', 'textBlock'
352                        //              options:
353                        //                      type: Object
354                        //                              The parameters used to draw the object. See stencil._Base and each
355                        //                              tool for specific parameters of teh data or points objects.
356                        //
357                        if(!this.ready){
358                                var c = dojo.connect(this, "onSurfaceReady", this, function(){
359                                        dojo.disconnect(c);
360                                        this.addStencil(type, options);
361                                });
362                                return false;
363                        }
364                        if(options && !options.data && !options.points){
365                                options = {data:options}
366                        }
367                        var s = this.stencils.register( new this.stencilTypes[type](this.getShapeProps(options)));
368                        // need this or not?
369                        //s.connect(s, "destroy", this, "onDeleteStencil");
370                        this.currentStencil && this.currentStencil.moveToFront();
371                        return s;
372                },
373               
374                removeStencil: function(/* Object */stencil){
375                        // summary:
376                        //              Use this method to programmatically remove Stencils from the canvas.
377                        //      arguments:
378                        //              Stencil: Object
379                        //                      The Stencil to be removed
380                        //
381                        this.stencils.unregister(stencil);
382                        stencil.destroy();
383                },
384               
385                removeAll: function(){
386                        // summary:
387                        //              Deletes all Stencils on the canvas.
388                        this.stencils.removeAll();
389                },
390               
391                selectAll: function(){
392                        // summary:
393                        //              Selects all stencils
394                        this.stencils.selectAll();
395                },
396               
397                toSelected: function(/*String*/func /*[args, ...]*/){
398                        // summary:
399                        //              Call a function within all selected Stencils
400                        //              like attr()
401                        // example:
402                        //              |       myDrawing.toSelected('attr', {x:10})
403                        //
404                        this.stencils.toSelected.apply(this.stencils, arguments);
405                },
406               
407                exporter: function(){
408                        // summary:
409                        //              Collects all Stencil data and returns an
410                        //              Array of objects.
411                        console.log("this.stencils", this.stencils);
412                        return this.stencils.exporter();  //Array
413                },
414               
415                importer: function(/* Array */objects){
416                        // summary:
417                        //              Handles an Array of stencil data and imports the objects
418                        //              to the drawing.
419                        dojo.forEach(objects, function(m){
420                                this.addStencil(m.type, m);
421                        }, this);
422                },
423               
424                changeDefaults: function(/*Object*/newStyle,/*boolean*/value){
425                        // summary:
426                        //              Change the defaults so that all Stencils from this
427                        //              point on will use the newly changed style.
428                        // arguments:
429                        //              newStyle: Object
430                        //                      An object that represents one of the objects in
431                        //                      drawing.style that will be mixed in. Not all
432                        //                      properties are necessary. Only one object may
433                        //                      be changed at a time. The object boolean parameter
434                        //                      is not required and if not set objects will automatically
435                        //                      be changed.
436                        //                      Changing non-objects like angleSnap requires value
437                        //                      to be true.
438                        // example:
439                        //              |       myDrawing.changeDefaults({
440                        //              |               norm:{
441                        //              |                       fill:"#0000ff",
442                        //              |                       width:5,
443                        //              |                       color:"#ffff00"
444                        //              |               }
445                        //              |       });
446                        //
447                        //console.log("----->>> changeDefault: ",newStyle, " value?: ",value);
448                        if(value!=undefined && value){
449                                for(var nm in newStyle){
450                                        this.defaults[nm] = newStyle[nm];
451                                }
452                        }else{
453                                for(var nm in newStyle){
454                                        for(var n in newStyle[nm]){
455                                                //console.log("  copy", nm, n, " to: ", newStyle[nm][n]);
456                                                this.defaults[nm][n] = newStyle[nm][n];
457                                        }
458                                }
459                        }
460                       
461                        if(this.currentStencil!=undefined && (!this.currentStencil.created || this.defaults.clickMode)){
462                                this.unSetTool();
463                                this.setTool(this.currentType);
464                        }
465                },
466               
467                onRenderStencil: function(/* Object */stencil){
468                        // summary:
469                        //              Event that fires when a stencil is drawn. Does not fire from
470                        //              'addStencil'.
471                        //
472                        //console.info("--------------------------------------dojox.drawing.onRenderStencil:", stencil.id);
473                       
474                        this.stencils.register(stencil);
475                        this.unSetTool();
476                        if(!this.defaults.clickMode){
477                                this.setTool(this.currentType);
478                        }else{
479                                this.defaults.clickable = true;
480                        }
481                },
482               
483                onDeleteStencil: function(/* Object */stencil){
484                        // summary:
485                        //              Event fired from a stencil that has destroyed itself
486                        //              will also be called when it is removed by "removeStencil"
487                        //              or stencils.onDelete.
488                        //
489                        this.stencils.unregister(stencil);
490                },
491               
492                registerTool: function(/* String */type){
493                        // summary:
494                        //               Registers a tool that can be accessed. Internal.
495                        if(this.tools[type]){ return; }
496                        var constr = dojo.getObject(type);
497                        //console.log("constr:", type)
498                        this.tools[type] = constr;
499                        var abbr = this.util.abbr(type);
500                        this.stencilTypes[abbr] = constr;
501                        this.stencilTypeMap[abbr] = type;
502                },
503               
504                getConstructor: function(/*String*/abbr){
505                        // summary:
506                        //              Returns a Stencil constructor base on
507                        //              abbreviation
508                        return this.stencilTypes[abbr];
509                },
510               
511                setTool: function(/* String */type){
512                        // summary:
513                        //              Sets up a new class to be used to draw. Called from Toolbar,
514                        //              and this class... after a tool is used a new one of the same
515                        //              type is initialized. Could be called externally.
516                        //
517                        if(this.mode=="ui"){ return; }
518                        if(!this.canvas || !this.canvas.surface){
519                                var c = dojo.connect(this, "onSurfaceReady", this, function(){
520                                        dojo.disconnect(c);
521                                        this.setTool(type);
522                                });
523                                return;
524                        }
525                        if(this.currentStencil){
526                                this.unSetTool();
527                        }
528                       
529                        this.currentType = this.tools[type] ? type : this.stencilTypeMap[type];
530                        //console.log("new tool arg:", type, "curr:", this.currentType, "mode:", this.mode, "tools:", this.tools)
531                       
532                        try{
533                                this.currentStencil = new this.tools[this.currentType]({container:this.canvas.surface.createGroup(), util:this.util, mouse:this.mouse, keys:this.keys});
534                                console.log("new tool is:", this.currentStencil.id, this.currentStencil);
535                                if(this.defaults.clickMode){ this.defaults.clickable = false; }
536                                this.currentStencil.connect(this.currentStencil, "onRender", this, "onRenderStencil");
537                                this.currentStencil.connect(this.currentStencil, "destroy", this, "onDeleteStencil");
538                        }catch(e){
539                                console.error("dojox.drawing.setTool Error:", e);
540                                console.error(this.currentType + " is not a constructor: ", this.tools[this.currentType]);
541                                //console.trace();
542                        }
543                },
544               
545                set: function(name, value){
546                        // summary:
547                        //              Drawing registers as a widget and needs to support
548                        //              widget's api.
549                        console.info("Attempting to set ",name," to: ",value,". Set currently not fully supported in Drawing");
550                },
551               
552                unSetTool: function(){
553                        // summary:
554                        //              Destroys current tool
555                        if(!this.currentStencil.created){
556                                this.currentStencil.destroy();
557                        }
558                       
559                }
560        });
561       
562})();
Note: See TracBrowser for help on using the repository browser.