1 | dojo.provide("dojox.drawing.util.common"); |
---|
2 | dojo.require("dojox.math.round"); |
---|
3 | |
---|
4 | (function(){ |
---|
5 | |
---|
6 | var uidMap = {}; |
---|
7 | var start = 0; |
---|
8 | dojox.drawing.util.common = { |
---|
9 | // summary: |
---|
10 | // A collection of common methods used for DojoX Drawing. |
---|
11 | // This singleton is accessible in most Drawing classes |
---|
12 | // as this.util |
---|
13 | // |
---|
14 | // NOTE: |
---|
15 | // A lot of functions use a EventObject |
---|
16 | // as an argument. An attempt was made to accept |
---|
17 | // either that object or a list of numbers. That wasn't |
---|
18 | // finished (it didn't work well in all cases) but is |
---|
19 | // likely to happen in the future. |
---|
20 | // In cases where you are not sending a Mouse object, |
---|
21 | // form your argument like so: |
---|
22 | // var obj = { |
---|
23 | // start:{ |
---|
24 | // x:Number, // start x |
---|
25 | // y:Number // start y |
---|
26 | // }, |
---|
27 | // x: Number, // end x |
---|
28 | // y:Number // end y |
---|
29 | // } |
---|
30 | // |
---|
31 | // |
---|
32 | radToDeg: function(/*Numer*/n){ |
---|
33 | // summary: |
---|
34 | // Convert the passed number to degrees. |
---|
35 | return (n*180)/Math.PI; // Number |
---|
36 | }, |
---|
37 | |
---|
38 | degToRad: function(/*Numer*/n){ |
---|
39 | // summary: |
---|
40 | // Convert the passed number to radians. |
---|
41 | return (n*Math.PI)/180; // Number |
---|
42 | }, |
---|
43 | |
---|
44 | angle: function(/*EventObject*/obj, /* ? Float */snap){ |
---|
45 | // summary: |
---|
46 | // Return angle based on mouse object |
---|
47 | // arguments: |
---|
48 | // obj: EventObject |
---|
49 | // Manager.Mouse event. |
---|
50 | // snap: Float |
---|
51 | // Returns nearest angle within snap limits |
---|
52 | // |
---|
53 | //obj = this.argsToObj.apply(this, arguments); |
---|
54 | if(snap){ |
---|
55 | snap = snap/180; |
---|
56 | var radians = this.radians(obj), |
---|
57 | seg = Math.PI * snap, |
---|
58 | rnd = dojox.math.round(radians/seg), |
---|
59 | new_radian = rnd*seg; |
---|
60 | return dojox.math.round(this.radToDeg(new_radian)); // Whole Number |
---|
61 | |
---|
62 | }else{ |
---|
63 | return this.radToDeg(this.radians(obj)); // Float |
---|
64 | } |
---|
65 | }, |
---|
66 | |
---|
67 | oppAngle: function(/*Angle*/ang){ |
---|
68 | (ang+=180) > 360 ? ang = ang - 360 : ang; |
---|
69 | return ang; |
---|
70 | }, |
---|
71 | |
---|
72 | radians: function(/*EventObject*/o){ |
---|
73 | // summary: |
---|
74 | // Return the radians derived from the coordinates |
---|
75 | // in the Mouse object. |
---|
76 | // |
---|
77 | //var o = this.argsToObj.apply(this, arguments); |
---|
78 | return Math.atan2(o.start.y-o.y,o.x-o.start.x); |
---|
79 | }, |
---|
80 | |
---|
81 | length: function(/*EventObject*/o){ |
---|
82 | // summary: |
---|
83 | // Return the length derived from the coordinates |
---|
84 | // in the Mouse object. |
---|
85 | // |
---|
86 | return Math.sqrt(Math.pow(o.start.x-o.x, 2)+Math.pow(o.start.y-o.y, 2)); |
---|
87 | }, |
---|
88 | |
---|
89 | lineSub: function(/*Number*/x1, /*Number*/y1, /*Number*/x2, /*Number*/y2, /*Number*/amt){ |
---|
90 | // summary: |
---|
91 | // Subtract an amount from a line |
---|
92 | // description: |
---|
93 | // x1,y1,x2,y2 represents the Line. 'amt' represents the amount |
---|
94 | // to subtract from it. |
---|
95 | // |
---|
96 | var len = this.distance(this.argsToObj.apply(this, arguments)); |
---|
97 | len = len < amt ? amt : len; |
---|
98 | var pc = (len-amt)/len; |
---|
99 | var x = x1 - (x1-x2) * pc; |
---|
100 | var y = y1 - (y1-y2) * pc; |
---|
101 | return {x:x, y:y}; // Object |
---|
102 | }, |
---|
103 | |
---|
104 | argsToObj: function(){ |
---|
105 | // summary: |
---|
106 | // Attempts to determine in a Mouse Object |
---|
107 | // was passed or indiviual numbers. Returns |
---|
108 | // an object. |
---|
109 | // |
---|
110 | var a = arguments; |
---|
111 | if(a.length < 4){ return a[0]; } |
---|
112 | return { |
---|
113 | start:{ |
---|
114 | x:a[0], |
---|
115 | y:a[1] |
---|
116 | }, |
---|
117 | x:a[2], |
---|
118 | y:a[3]//, |
---|
119 | //snap:a[4] |
---|
120 | }; // Object |
---|
121 | }, |
---|
122 | |
---|
123 | distance: function(/*EventObject or x1,y1,x2,y2*/){ |
---|
124 | // summary: |
---|
125 | // Return the length derived from the coordinates |
---|
126 | // in the Mouse object. Different from util.length |
---|
127 | // in that this always returns an absolute value. |
---|
128 | // |
---|
129 | var o = this.argsToObj.apply(this, arguments); |
---|
130 | return Math.abs(Math.sqrt(Math.pow(o.start.x-o.x, 2)+Math.pow(o.start.y-o.y, 2))); // Number |
---|
131 | }, |
---|
132 | |
---|
133 | slope:function(/*Object*/p1, /*Object*/p2){ |
---|
134 | // summary: |
---|
135 | // Given two poits of a line, returns the slope. |
---|
136 | if(!(p1.x-p2.x)){ return 0; } |
---|
137 | return ((p1.y-p2.y)/(p1.x-p2.x)); // Number |
---|
138 | }, |
---|
139 | |
---|
140 | pointOnCircle: function(/*Number*/cx, /*Number*/cy, /*Number*/radius, /*Number*/angle){ |
---|
141 | // summary: |
---|
142 | // A *very* helpful method. If you know the center |
---|
143 | // (or starting) point, length and angle, find the |
---|
144 | // x,y point at the end of that line. |
---|
145 | // |
---|
146 | var radians = angle * Math.PI / 180.0; |
---|
147 | var x = radius * Math.cos(radians); |
---|
148 | var y = radius * Math.sin(radians); |
---|
149 | return { |
---|
150 | x:cx+x, |
---|
151 | y:cy-y |
---|
152 | }; // Object |
---|
153 | }, |
---|
154 | |
---|
155 | constrainAngle: function(/*EventObject*/obj, /*Number*/min, /*Number*/max){ |
---|
156 | // summary: |
---|
157 | // Ensures the angle in the Mouse Object is within the |
---|
158 | // min and max limits. If not one of those limits is used. |
---|
159 | // Returns an x,y point for the angle used. |
---|
160 | // |
---|
161 | var angle = this.angle(obj); |
---|
162 | if(angle >= min && angle <= max){ |
---|
163 | return obj; // Object |
---|
164 | } |
---|
165 | var radius = this.length(obj); |
---|
166 | var new_angle = angle > max ? max : min - angle < 100 ? min : max; |
---|
167 | return this.pointOnCircle(obj.start.x,obj.start.y,radius, new_angle); // Object |
---|
168 | }, |
---|
169 | |
---|
170 | snapAngle: function(/*EventObject*/obj, /*Float*/ca){ |
---|
171 | // summary: |
---|
172 | // Snaps a line to the nearest angle |
---|
173 | // obj: Mouse object (see dojox.drawing.Mouse) |
---|
174 | // ca: Fractional amount to snap to |
---|
175 | // A decimal number fraction of a half circle |
---|
176 | // .5 would snap to 90 degrees |
---|
177 | // .25 would snap to 45 degrees |
---|
178 | // .125 would snap to 22.5 degrees, etc. |
---|
179 | // |
---|
180 | var radians = this.radians(obj), |
---|
181 | radius = this.length(obj), |
---|
182 | seg = Math.PI * ca, |
---|
183 | rnd = Math.round(radians/seg), |
---|
184 | new_radian = rnd*seg, |
---|
185 | new_angle = this.radToDeg(new_radian), |
---|
186 | pt = this.pointOnCircle(obj.start.x,obj.start.y,radius,new_angle); |
---|
187 | return pt; // Object |
---|
188 | }, |
---|
189 | |
---|
190 | // helpers |
---|
191 | idSetStart: function(num){ |
---|
192 | start=num; |
---|
193 | }, |
---|
194 | |
---|
195 | uid: function(/* ? String */str){ |
---|
196 | // summary: |
---|
197 | // Creates a unique ID. |
---|
198 | // arguments: |
---|
199 | // str: String |
---|
200 | // If provided, kept in a map, incremented |
---|
201 | // and used in the id. Otherwise 'shape' is used. |
---|
202 | // |
---|
203 | str = str || "shape"; |
---|
204 | uidMap[str] = uidMap[str]===undefined ? start : uidMap[str] + 1; |
---|
205 | return str + uidMap[str]; // String |
---|
206 | }, |
---|
207 | |
---|
208 | abbr: function(type){ |
---|
209 | // summary: |
---|
210 | // Converts a namespace (typically a tool or a stencil) into |
---|
211 | // an abbreviation |
---|
212 | return type.substring(type.lastIndexOf(".")+1).charAt(0).toLowerCase() |
---|
213 | + type.substring(type.lastIndexOf(".")+2); |
---|
214 | }, |
---|
215 | mixin: function(o1, o2){ |
---|
216 | // TODO: make faster |
---|
217 | //return dojo.mixin(dojo.clone(o1), dojo.clone(o2)); |
---|
218 | }, |
---|
219 | |
---|
220 | objects:{}, //private? |
---|
221 | register: function(/*Object*/obj){ |
---|
222 | // summary: |
---|
223 | // Since util is the only Singleton in Drawing (besides |
---|
224 | // keys) it is used to help connect the Drawing object |
---|
225 | // the Toolbar. Since multiple drawings can be on one |
---|
226 | // page, this function serves a little more use than |
---|
227 | // on first apearance. |
---|
228 | this.objects[obj.id] = obj; |
---|
229 | }, |
---|
230 | byId: function(/*String*/id){ |
---|
231 | // summary: |
---|
232 | // Get an object that was registered with util.register |
---|
233 | // |
---|
234 | return this.objects[id]; |
---|
235 | }, |
---|
236 | attr: function(/* Object */ elem, /* property */ prop, /* ? value */ value, squelchErrors){ |
---|
237 | // summary: |
---|
238 | // Helper function to attach attributes to SVG and VML raw nodes. |
---|
239 | // |
---|
240 | |
---|
241 | if(!elem){ return false; } |
---|
242 | try{ |
---|
243 | |
---|
244 | // util is a crappy check, but we need to tell the diff |
---|
245 | // between a Drawing shape and a GFX shape |
---|
246 | if(elem.shape && elem.util){ |
---|
247 | elem = elem.shape; |
---|
248 | } |
---|
249 | |
---|
250 | if(!value && prop=="id" && elem.target){ |
---|
251 | |
---|
252 | var n = elem.target; |
---|
253 | while(!dojo.attr(n, "id")){ |
---|
254 | n = n.parentNode; |
---|
255 | } |
---|
256 | return dojo.attr(n, "id"); |
---|
257 | } |
---|
258 | |
---|
259 | if(elem.rawNode || elem.target){ |
---|
260 | var args = Array.prototype.slice.call(arguments); |
---|
261 | args[0] = elem.rawNode || elem.target; |
---|
262 | return dojo.attr.apply(dojo, args); |
---|
263 | } |
---|
264 | return dojo.attr(elem, "id"); |
---|
265 | |
---|
266 | |
---|
267 | |
---|
268 | }catch(e){ |
---|
269 | if(!squelchErrors){ |
---|
270 | // For debugging only. These errors actually cause errors in IE's console |
---|
271 | //console.error("BAD ATTR: prop:", prop, "el:", elem) |
---|
272 | //console.error(e) |
---|
273 | //console.trace(); |
---|
274 | } |
---|
275 | return false; |
---|
276 | } |
---|
277 | } |
---|
278 | }; |
---|
279 | |
---|
280 | })(); |
---|