1
/* This notice must be untouched at all times.
4
The latest version is available at
5
http://www.openjacob.org
7
Copyright (c) 2006 Andreas Herz. All rights reserved.
8
Created 5. 11. 2006 by Andreas Herz (Web: http://www.freegroup.de )
12
This library is free software; you can redistribute it and/or
13
modify it under the terms of the GNU Lesser General Public
14
License (LGPL) as published by the Free Software Foundation; either
15
version 2.1 of the License, or (at your option) any later version.
17
This library is distributed in the hope that it will be useful,
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
Lesser General Public License for more details.
22
You should have received a copy of the GNU Lesser General Public
23
License along with this library; if not, write to the Free Software
24
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
25
or see http://www.gnu.org/copyleft/lesser.html
31
* @author Andreas Herz
34
draw2d.Figure=function()
39
draw2d.Figure.prototype.type="Figure";
42
draw2d.Figure.ZOrderBaseIndex = 100;
45
* Set the common z-index of the window element. This method exists for
46
* compatibility reason to dojo or another UI javascript library.
47
* It is now possible to arange the draw2d elements behind/before other UI elements-
51
* @param {int} index The z-order for all new figure objects.
53
draw2d.Figure.setZOrderBaseIndex=function(/*:int*/ index)
55
draw2d.Figure.ZOrderBaseIndex = index;
61
draw2d.Figure.prototype.construct=function()
63
this.lastDragStartTime =0;
69
this.border=null; /*:draw2d.Border*/
70
this.setDimension(10,10);
72
this.id = this.generateUId(); /*:String*/
74
this.html = this.createHTMLElement(); /*:HTMLElement*/
76
this.canvas = null; /*:draw2d.Canvas*/
78
this.workflow = null; /*:draw2d.Workflow*/
80
this.draggable = null; /*:HTMLElement*/
82
this.parent = null; /*:draw2d.CompartmentFigure*/
84
this.isMoving = false; /*:boolean*/
86
this.canSnapToHelper = true; /*:boolean*/
88
this.snapToGridAnchor = new draw2d.Point(0,0);
90
this.timer = -1; // Fadein/Fadeout timer id.
92
// It is important to set the flags below. Otherwise the flags will be <null>
94
this.setDeleteable(true);
95
this.setCanDrag(true);
96
this.setResizeable(true);
97
this.setSelectable(true);
99
// a figure can store additional, user defined properties
101
this.properties = new Object(); /*:Map<name,value>*/
103
// Hier werden Object registriert welche informiert werden wollen wenn sich dieses
104
// Object bewegt hat.
106
this.moveListener = new draw2d.ArrayList();
110
* Override this method to free your resource too.
114
draw2d.Figure.prototype.dispose=function()
116
//this.id = null; don't dispose the id! This is important for deregistration
117
//this.html = null; don't dispose the html! This is important for deregistration
119
this.workflow = null;
120
this.moveListener = null;
121
if(this.draggable!=null)
123
this.draggable.removeEventListener("mouseenter", this.tmpMouseEnter);
124
this.draggable.removeEventListener("mouseleave", this.tmpMouseLeave);
125
this.draggable.removeEventListener("dragend", this.tmpDragend);
126
this.draggable.removeEventListener("dragstart",this.tmpDragstart );
127
this.draggable.removeEventListener("drag",this.tmpDrag);
128
this.draggable.removeEventListener("dblclick",this.tmpDoubleClick );
129
this.draggable.node = null;
131
this.draggable = null;
132
if(this.border!=null)
133
this.border.dispose();
136
// remove this figure from the parent CompartmentFigure
138
if(this.parent!=null)
139
this.parent.removeChild(this);
146
* A figure can store user defined attributes. This method returns all properties stored in this figure.<br>
149
* @returns All user defined properties of the figure
152
draw2d.Figure.prototype.getProperties=function()
154
return this.properties;
158
* A figure can store user defined attributes. This method returns the requested property.<br>
161
* @returns The user defined property of this figure.
164
draw2d.Figure.prototype.getProperty=function(/*:String*/ key)
166
return this.properties[key];
171
* A figure can store any type of information. You can use this to attach any String or Object to this
175
* @param {String} key The key of the property.
176
* @param {String} value The value of the property.
178
draw2d.Figure.prototype.setProperty=function(/*:String*/ key,/*:String*/ value)
180
this.properties[key]=value;
181
this.setDocumentDirty();
185
* Return the document unique id of this element. It is not an uuid or guid
188
draw2d.Figure.prototype.getId=function()
196
* @param {draw2d.Canvas} canvas
198
draw2d.Figure.prototype.setCanvas= function(/*:draw2d.Canvas*/ canvas)
200
this.canvas = canvas;
206
draw2d.Figure.prototype.getWorkflow=function()
208
return this.workflow;
213
* @param {draw2d.Workflow} workflow
215
draw2d.Figure.prototype.setWorkflow= function(/*:draw2d.Workflow*/ workflow)
217
// The parent is a Workflow class - now we create the Drag-Objekt
219
if(this.draggable==null)
221
// Firefox seems to need to have the tabindex="0" property set to some value
222
// so it knows this Div or Span is keyboard selectable. That allows the keyboard
223
// event to be triggered. It is not so dumb - you might want to trap Delete or
224
// Insert keys on a figure etc.
225
this.html.tabIndex="0";
229
this.keyDown=function(event)
231
event.cancelBubble = true; // Stop event propagation
232
event.returnValue = true; // Execute the standard event for this event. Important for Input Fields/Dialogs
233
oThis.onKeyDown(event.keyCode, event.ctrlKey);
235
if (this.html.addEventListener)
236
this.html.addEventListener("keydown", this.keyDown, false);
237
else if (this.html.attachEvent)
238
this.html.attachEvent("onkeydown", this.keyDown);
240
this.draggable = new draw2d.Draggable(this.html, draw2d.Draggable.DRAG_X | draw2d.Draggable.DRAG_Y);
241
this.draggable.node = this;
242
this.tmpContextMenu = function (oEvent){oThis.onContextMenu(oThis.x+oEvent.x, oEvent.y+oThis.y);};
243
this.tmpMouseEnter = function (oEvent){oThis.onMouseEnter();};
244
this.tmpMouseLeave = function (oEvent){oThis.onMouseLeave();};
245
this.tmpDragend = function (oEvent){oThis.onDragend();};
246
this.tmpDragstart = function (oEvent){
247
var w = oThis.workflow;
249
if(oThis.workflow.toolPalette && oThis.workflow.toolPalette.activeTool)
251
oEvent.returnValue = false;
252
oThis.workflow.onMouseDown(oThis.x+oEvent.x, oEvent.y+oThis.y);
253
oThis.workflow.onMouseUp(oThis.x+oEvent.x, oEvent.y+oThis.y);
256
oEvent.returnValue = oThis.onDragstart(oEvent.x,oEvent.y);
258
this.tmpDrag = function (oEvent){oThis.onDrag();};
259
this.tmpDoubleClick = function (oEvent){oThis.onDoubleClick();};
261
this.draggable.addEventListener("contextmenu", this.tmpContextMenu);
262
this.draggable.addEventListener("mouseenter", this.tmpMouseEnter);
263
this.draggable.addEventListener("mouseleave", this.tmpMouseLeave);
264
this.draggable.addEventListener("dragend", this.tmpDragend);
265
this.draggable.addEventListener("dragstart",this.tmpDragstart );
266
this.draggable.addEventListener("drag",this.tmpDrag);
267
this.draggable.addEventListener("dblclick",this.tmpDoubleClick );
269
this.workflow = workflow;
275
draw2d.Figure.prototype.createHTMLElement=function()
277
var item = document.createElement('div');
279
item.style.position="absolute";
280
item.style.left = this.x+"px";
281
item.style.top = this.y+"px";
282
item.style.height = this.width+"px";
283
item.style.width = this.height+"px";
284
item.style.margin = "0px";
285
item.style.padding= "0px";
286
item.style.outline= "none";
287
item.style.zIndex = ""+draw2d.Figure.ZOrderBaseIndex;
294
* Set the parent of this figure.
295
* Don't call them manually. Is CompartmentFigre.appendChild() instead.
297
* @param {draw2d.CompartmentFigure} parent The new parent of this figure
300
draw2d.Figure.prototype.setParent=function(/*:draw2d.CompartmentFigure*/ parent)
302
this.parent = parent;
306
* Get the parent of this figure.
308
* @type draw2d.CompartmentFigure
310
draw2d.Figure.prototype.getParent=function()
317
* @return Returns the z-index of the element.
320
draw2d.Figure.prototype.getZOrder=function()
322
return this.html.style.zIndex;
326
* @param {int} index Set the new z-index of the element
328
draw2d.Figure.prototype.setZOrder=function(/*:int*/ index)
330
this.html.style.zIndex=index;
335
* Return true if the origin of the Object is the window and not
336
* the document. This is usefull if you want implement a window or a
337
* dialog element. The element doesn't move if the user scroll the document.
339
* @returns Returns [true] if the origin of the object the window.
342
draw2d.Figure.prototype.hasFixedPosition=function()
348
* This value is relevant for the interactive resize of the figure.
350
* @returns Returns the min width of this object.
353
draw2d.Figure.prototype.getMinWidth=function()
359
* This value is relevant for the interactive resize of the figure.
361
* @returns Returns the min height of this object.
364
draw2d.Figure.prototype.getMinHeight=function()
372
draw2d.Figure.prototype.getHTMLElement=function()
375
this.html = this.createHTMLElement();
380
* @see draw2d.Circle for an implementation.
383
draw2d.Figure.prototype.paint=function()
385
// called after the element has been added to the document
389
* @param {draw2d.Border} border Set the border for this figure
391
draw2d.Figure.prototype.setBorder=function(/*:draw2d.Border*/ border)
393
if(this.border!=null)
394
this.border.figure=null;
397
this.border.figure=this;
398
this.border.refresh();
399
this.setDocumentDirty();
403
* Callback method for the context menu interaction.
404
* Don't override this method! Implement getContextMenu instead.
406
* @see #getContextMenu
409
* @param {int} x The absolute x coordinate of the right mouse button click
410
* @param {int} y The absolute y coordinate of the right mouse button click
412
draw2d.Figure.prototype.onContextMenu=function(/*:int*/ x, /*:int*/y)
414
var menu = this.getContextMenu();
416
this.workflow.showMenu(menu,x,y);
420
* @returns null or the Menu object for this figure.
423
draw2d.Figure.prototype.getContextMenu=function()
429
* Callback method for the double click event of user interaction.
430
* Sub classes can override this method to implement their own behaviour.
432
draw2d.Figure.prototype.onDoubleClick=function()
437
* Callback method for the mouse enter event. Usefull for mouse hover-effects.
438
* Sub classes can override this method to implement their own behaviour.
440
draw2d.Figure.prototype.onMouseEnter=function()
446
* Callback method for the mouse leave event. Usefull for mouse hover-effects.
449
draw2d.Figure.prototype.onMouseLeave=function()
454
* Don't call them manually. This will be done by the framework.<br>
455
* Will be called if the object are moved via drag and drop.
456
* Sub classes can override this method to implement additional stuff. Don't forget to call
457
* the super implementation via <code>Figure.prototype.onDrag.call(this);</code>
460
draw2d.Figure.prototype.onDrag = function()
462
this.x = this.draggable.getLeft();
463
this.y = this.draggable.getTop();
465
// enable the alpha blending o the first real move of the object
467
if(this.isMoving==false)
469
this.isMoving = true;
472
this.fireMoveEvent();
476
* Will be called after a drag and drop action.<br>
477
* Sub classes can override this method to implement additional stuff. Don't forget to call
478
* the super implementation via <code>Figure.prototype.onDragend.call(this);</code>
481
draw2d.Figure.prototype.onDragend = function()
483
if(this.getWorkflow().getEnableSmoothFigureHandling()==true)
486
var slowShow = function()
488
if(oFigure.alpha<1.0)
489
oFigure.setAlpha(Math.min(1.0,oFigure.alpha+0.05));
492
window.clearInterval(oFigure.timer);
497
window.clearInterval(oFigure.timer);
498
oFigure.timer = window.setInterval(slowShow,20);
504
// Element ist zwar schon an seine Position, das Command muss aber trotzdem
505
// in dem CommandStack gelegt werden damit das Undo funktioniert.
507
this.command.setPosition(this.x, this.y);
508
this.workflow.commandStack.execute(this.command);
510
this.isMoving = false;
511
this.workflow.hideSnapToHelperLines();
512
this.fireMoveEvent();
516
* Will be called if the drag and drop action beginns. You can return [false] if you
517
* want avoid the that the figure can be move.
521
draw2d.Figure.prototype.onDragstart = function(/*:int*/ x, /*:int*/ y)
526
this.command = new draw2d.CommandMove(this, this.x,this.y);
531
* Switch on/off the drag drop behaviour of this object
533
* @param {boolean} flag The new drag drop indicator
535
draw2d.Figure.prototype.setCanDrag=function(/*:boolean*/flag)
539
this.html.style.cursor="move";
541
this.html.style.cursor=null;
545
* Set the alpha blending of this figure.
547
* @param {float} percent Value between 0-1.
549
draw2d.Figure.prototype.setAlpha=function(/*:float 0-1*/ percent)
551
if(this.alpha==percent)
556
this.html.style.MozOpacity=percent ;
561
// standard. Like Apple Safari Browser
562
this.html.style.opacity=percent ;
568
var opacityValue = Math.round(percent * 100);
569
// remove the alpha filter complete if we don't want any.
571
this.html.style.filter = "";
573
this.html.style.filter = "alpha(opacity=" + opacityValue + ")";
576
this.alpha = percent;
580
* Set the new width and height of the figure.
584
* @param {int} w The new width of the figure
585
* @param {int} h The new height of the figure
587
draw2d.Figure.prototype.setDimension=function(/*:int*/ w, /*:int*/ h)
589
this.width = Math.max(this.getMinWidth(),w);
590
this.height= Math.max(this.getMinHeight(),h);
592
// Falls das Element noch nie gezeichnet wurde, dann braucht aus das HTML nicht
593
// aktualisiert werden
598
this.html.style.width = this.width+"px";
599
this.html.style.height = this.height+"px";
601
this.fireMoveEvent();
603
// Update the resize handles if the user change the dimension via an API call
605
if(this.workflow!=null && this.workflow.getCurrentSelection()==this)
606
this.workflow.showResizeHandles(this);
610
* Set the position of the object.
612
* @param {int} xPos The new x coordinate of the figure
613
* @param {int} yPos The new y coordinate of the figure
615
draw2d.Figure.prototype.setPosition=function(/*:int*/ xPos , /*:int*/ yPos )
617
// this.x = Math.max(0,xPos);
618
// this.y = Math.max(0,yPos);
621
// Falls das Element noch nie gezeichnet wurde, dann braucht aus das HTML nicht
622
// aktualisiert werden
627
this.html.style.left = this.x+"px";
628
this.html.style.top = this.y+"px";
630
this.fireMoveEvent();
632
// Update the resize handles if the user change the position of the element via an API call.
634
if(this.workflow!=null && this.workflow.getCurrentSelection()==this)
635
this.workflow.showResizeHandles(this);
639
* Returns the true if the figure can be resized.
641
* @see #setResizeable
644
draw2d.Figure.prototype.isResizeable=function()
646
return this.resizeable;
650
* You can change the resizeable behaviour of this object. Hands over [false] and
651
* the figure has no resizehandles if you select them with the mouse.<br>
653
* @see #getResizeable
654
* @param {boolean} flag The resizeable flag.
656
draw2d.Figure.prototype.setResizeable=function(/*:boolean*/ flag)
658
this.resizeable=flag;
665
draw2d.Figure.prototype.isSelectable=function()
667
return this.selectable;
672
* You can change the selectable behaviour of this object. Hands over [false] and
673
* the figure has no selection handles if you try to select them with the mouse.<br>
675
* @param {boolean} flag The selectable flag.
677
draw2d.Figure.prototype.setSelectable=function(/*:boolean*/ flag)
679
this.selectable=flag;
683
* Return true if the object doesn't care about the aspect ratio.
684
* You can change the hight and width indipendent.
687
draw2d.Figure.prototype.isStrechable=function()
693
* Return false if you avoid that the user can delete your figure.
694
* Sub class can override this method.
697
draw2d.Figure.prototype.isDeleteable=function()
699
return this.deleteable;
703
* Return false if you avoid that the user can delete your figure.
705
* @param {boolean} flag Enable or disable flag for the delete operation
707
draw2d.Figure.prototype.setDeleteable=function(/*:boolean */flag)
709
this.deleteable = flag;
714
* Set the flag if this object can snap to grid or geometry.
715
* A window of dialog should set this flag to false.
716
* @param {boolean} flag The snap to grid/geometry enable flag.
719
draw2d.Figure.prototype.setCanSnapToHelper=function(/*:boolean */flag)
721
this.canSnapToHelper = flag;
725
* Returns true if the figure cna snap to any helper like a grid, guide, geometrie
730
draw2d.Figure.prototype.getCanSnapToHelper=function()
732
return this.canSnapToHelper;
739
draw2d.Figure.prototype.getSnapToGridAnchor=function()
741
return this.snapToGridAnchor;
748
draw2d.Figure.prototype.setSnapToGridAnchor=function(/*:draw2d.Point*/ point)
750
this.snapToGridAnchor = point;
754
* @type draw2d.Dimension
756
draw2d.Figure.prototype.getBounds=function()
758
return new draw2d.Dimension(this.getX(),this.getY(),this.getWidth(),this.getHeight());
765
draw2d.Figure.prototype.getWidth=function()
773
draw2d.Figure.prototype.getHeight=function()
779
* @returns The y-offset to the parent figure.
782
draw2d.Figure.prototype.getY=function()
788
* @returns the x-offset to the parent figure
791
draw2d.Figure.prototype.getX=function()
797
* @returns The Y coordinate in relation the Canvas.
800
draw2d.Figure.prototype.getAbsoluteY=function()
806
* @returns The X coordinate in relation to the canvas
809
draw2d.Figure.prototype.getAbsoluteX=function()
815
* This method will be called from the framework if the objects is selected and the user press any key.
816
* Sub class can override this method to implement their own stuff.
818
* @param {int} keyCode The code of the pressed key
820
draw2d.Figure.prototype.onKeyDown=function(/*:int*/ keyCode, /*:boolean*/ ctrl)
822
if(keyCode==46 && this.isDeleteable()==true)
824
this.workflow.commandStack.execute(new draw2d.CommandDelete(this));
827
// redirect any CTRL key strokes to the parent workflow/canvas
831
this.workflow.onKeyDown(keyCode,ctrl);
836
* Returns the position of the figure.
841
draw2d.Figure.prototype.getPosition=function()
843
return new draw2d.Point(this.x, this.y);
847
draw2d.Figure.prototype.isOver = function (/*:int*/ iX ,/*:int*/ iY)
849
var x = this.getAbsoluteX();
850
var y = this.getAbsoluteY();
851
var iX2 = x + this.width;
852
var iY2 = y + this.height;
853
return (iX >= x && iX <= iX2 && iY >= y && iY <= iY2);
857
* @param {draw2d.Figure} figure The figure to monitor
860
draw2d.Figure.prototype.attachMoveListener = function(/*:draw2d.Figure*/ figure)
862
if(figure==null || this.moveListener==null)
865
this.moveListener.add(figure);
870
* @param {draw2d.Figure} figure The figure to remove the monitor
873
draw2d.Figure.prototype.detachMoveListener = function(/*:draw2d.Figure*/ figure)
875
if(figure==null || this.moveListener==null)
878
this.moveListener.remove(figure);
884
draw2d.Figure.prototype.fireMoveEvent=function()
886
this.setDocumentDirty();
887
var size= this.moveListener.getSize();
888
for(var i=0;i<size;i++)
890
this.moveListener.get(i).onOtherFigureMoved(this);
896
* Falls man sich zuvor an einem Object mit attacheMoveListener(..) registriert hat,
897
* wird man hierüber dann informiert wenn sich das Objekt bewegt hat.
899
* @param {draw2d.Figure} figure The figure which has changed its position
902
draw2d.Figure.prototype.onOtherFigureMoved=function(/*:draw2d.Figure*/ figure)
907
* This method will be called if the figure has changed any postion, color, dimension or something else.
911
draw2d.Figure.prototype.setDocumentDirty=function()
913
if(this.workflow!=null)
914
this.workflow.setDocumentDirty();
922
draw2d.Figure.prototype.generateUId=function()
924
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
925
var string_length = 10;
932
for (var i=0; i<string_length; i++)
934
var rnum = Math.floor(Math.random() * chars.length);
935
id += chars.substring(rnum,rnum+1);
938
elem = document.getElementById(id);
948
* Utility function to disable text selection on the handsover element
952
draw2d.Figure.prototype.disableTextSelection=function(/*:HTMLElement*/ e)
954
// disable text selection
956
if (typeof e.onselectstart!="undefined") //IE route
957
e.onselectstart=function(){return false}
958
else if (typeof e.style.MozUserSelect!="undefined") //Firefox route
959
e.style.MozUserSelect="none"