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