1 | define(["dojo/_base/kernel", "dojo/_base/lang", "./_base", "./matrix", "./path", "dojo/_base/Color", "./vml"], |
---|
2 | function (kernel, lang, g, m, pathLib, Color, vml){ |
---|
3 | |
---|
4 | kernel.experimental("dojox.gfx.vml_attach"); |
---|
5 | |
---|
6 | vml.attachNode = function(node){ |
---|
7 | // summary: |
---|
8 | // creates a shape from a Node |
---|
9 | // node: Node |
---|
10 | // a VML node |
---|
11 | if(!node) return null; |
---|
12 | var s = null; |
---|
13 | switch(node.tagName.toLowerCase()){ |
---|
14 | case vml.Rect.nodeType: |
---|
15 | s = new vml.Rect(node); |
---|
16 | attachRect(s); |
---|
17 | break; |
---|
18 | case vml.Ellipse.nodeType: |
---|
19 | if(node.style.width == node.style.height){ |
---|
20 | s = new vml.Circle(node); |
---|
21 | attachCircle(s); |
---|
22 | }else{ |
---|
23 | s = new vml.Ellipse(node); |
---|
24 | attachEllipse(s); |
---|
25 | } |
---|
26 | break; |
---|
27 | case vml.Path.nodeType: |
---|
28 | switch(node.getAttribute("dojoGfxType")){ |
---|
29 | case "line": |
---|
30 | s = new vml.Line(node); |
---|
31 | attachLine(s); |
---|
32 | break; |
---|
33 | case "polyline": |
---|
34 | s = new vml.Polyline(node); |
---|
35 | attachPolyline(s); |
---|
36 | break; |
---|
37 | case "path": |
---|
38 | s = new vml.Path(node); |
---|
39 | attachPath(s); |
---|
40 | break; |
---|
41 | case "text": |
---|
42 | s = new vml.Text(node); |
---|
43 | attachText(s); |
---|
44 | attachFont(s); |
---|
45 | attachTextTransform(s); |
---|
46 | break; |
---|
47 | case "textpath": |
---|
48 | s = new vml.TextPath(node); |
---|
49 | attachPath(s); |
---|
50 | attachText(s); |
---|
51 | attachFont(s); |
---|
52 | break; |
---|
53 | } |
---|
54 | break; |
---|
55 | case vml.Image.nodeType: |
---|
56 | switch(node.getAttribute("dojoGfxType")){ |
---|
57 | case "image": |
---|
58 | s = new vml.Image(node); |
---|
59 | attachImage(s); |
---|
60 | attachImageTransform(s); |
---|
61 | break; |
---|
62 | } |
---|
63 | break; |
---|
64 | default: |
---|
65 | //console.debug("FATAL ERROR! tagName = " + node.tagName); |
---|
66 | return null; |
---|
67 | } |
---|
68 | if(!(s instanceof vml.Image)){ |
---|
69 | attachFill(s); |
---|
70 | attachStroke(s); |
---|
71 | if(!(s instanceof vml.Text)){ |
---|
72 | attachTransform(s); |
---|
73 | } |
---|
74 | } |
---|
75 | return s; // dojox/gfx/shape.Shape |
---|
76 | }; |
---|
77 | |
---|
78 | vml.attachSurface = function(node){ |
---|
79 | // summary: |
---|
80 | // creates a surface from a Node |
---|
81 | // node: Node |
---|
82 | // a VML node |
---|
83 | var s = new vml.Surface(); |
---|
84 | s.clipNode = node; |
---|
85 | var r = s.rawNode = node.firstChild; |
---|
86 | var b = r.firstChild; |
---|
87 | if(!b || b.tagName != "rect"){ |
---|
88 | return null; // dojox/gfx.Surface |
---|
89 | } |
---|
90 | s.bgNode = r; |
---|
91 | return s; // dojox/gfx.Surface |
---|
92 | }; |
---|
93 | |
---|
94 | var attachFill = function(object){ |
---|
95 | // summary: |
---|
96 | // deduces a fill style from a node. |
---|
97 | // object: dojox/gfx/shape.Shape |
---|
98 | // a VML shape |
---|
99 | var fillStyle = null, r = object.rawNode, fo = r.fill, stops, i, t; |
---|
100 | if(fo.on && fo.type == "gradient"){ |
---|
101 | fillStyle = lang.clone(g.defaultLinearGradient), |
---|
102 | rad = m._degToRad(fo.angle); |
---|
103 | fillStyle.x2 = Math.cos(rad); |
---|
104 | fillStyle.y2 = Math.sin(rad); |
---|
105 | fillStyle.colors = []; |
---|
106 | stops = fo.colors.value.split(";"); |
---|
107 | for(i = 0; i < stops.length; ++i){ |
---|
108 | t = stops[i].match(/\S+/g); |
---|
109 | if(!t || t.length != 2){ continue; } |
---|
110 | fillStyle.colors.push({offset: vml._parseFloat(t[0]), color: new Color(t[1])}); |
---|
111 | } |
---|
112 | }else if(fo.on && fo.type == "gradientradial"){ |
---|
113 | fillStyle = lang.clone(g.defaultRadialGradient), |
---|
114 | w = parseFloat(r.style.width), h = parseFloat(r.style.height); |
---|
115 | fillStyle.cx = isNaN(w) ? 0 : fo.focusposition.x * w; |
---|
116 | fillStyle.cy = isNaN(h) ? 0 : fo.focusposition.y * h; |
---|
117 | fillStyle.r = isNaN(w) ? 1 : w / 2; |
---|
118 | fillStyle.colors = []; |
---|
119 | stops = fo.colors.value.split(";"); |
---|
120 | for(i = stops.length - 1; i >= 0; --i){ |
---|
121 | t = stops[i].match(/\S+/g); |
---|
122 | if(!t || t.length != 2){ continue; } |
---|
123 | fillStyle.colors.push({offset: vml._parseFloat(t[0]), color: new Color(t[1])}); |
---|
124 | } |
---|
125 | }else if(fo.on && fo.type == "tile"){ |
---|
126 | fillStyle = lang.clone(g.defaultPattern); |
---|
127 | fillStyle.width = g.pt2px(fo.size.x); // from pt |
---|
128 | fillStyle.height = g.pt2px(fo.size.y); // from pt |
---|
129 | fillStyle.x = fo.origin.x * fillStyle.width; |
---|
130 | fillStyle.y = fo.origin.y * fillStyle.height; |
---|
131 | fillStyle.src = fo.src; |
---|
132 | }else if(fo.on && r.fillcolor){ |
---|
133 | // a color object ! |
---|
134 | fillStyle = new Color(r.fillcolor+""); |
---|
135 | fillStyle.a = fo.opacity; |
---|
136 | } |
---|
137 | object.fillStyle = fillStyle; |
---|
138 | }; |
---|
139 | |
---|
140 | var attachStroke = function(object) { |
---|
141 | // summary: |
---|
142 | // deduces a stroke style from a node. |
---|
143 | // object: dojox/gfx/shape.Shape |
---|
144 | // a VML shape |
---|
145 | var r = object.rawNode; |
---|
146 | if(!r.stroked){ |
---|
147 | object.strokeStyle = null; |
---|
148 | return; |
---|
149 | } |
---|
150 | var strokeStyle = object.strokeStyle = lang.clone(g.defaultStroke), |
---|
151 | rs = r.stroke; |
---|
152 | strokeStyle.color = new Color(r.strokecolor.value); |
---|
153 | strokeStyle.width = g.normalizedLength(r.strokeweight+""); |
---|
154 | strokeStyle.color.a = rs.opacity; |
---|
155 | strokeStyle.cap = this._translate(this._capMapReversed, rs.endcap); |
---|
156 | strokeStyle.join = rs.joinstyle == "miter" ? rs.miterlimit : rs.joinstyle; |
---|
157 | strokeStyle.style = rs.dashstyle; |
---|
158 | }; |
---|
159 | |
---|
160 | var attachTransform = function(object) { |
---|
161 | // summary: |
---|
162 | // deduces a transformation matrix from a node. |
---|
163 | // object: dojox/gfx/shape.Shape |
---|
164 | // a VML shape |
---|
165 | var s = object.rawNode.skew, sm = s.matrix, so = s.offset; |
---|
166 | object.matrix = m.normalize({ |
---|
167 | xx: sm.xtox, |
---|
168 | xy: sm.ytox, |
---|
169 | yx: sm.xtoy, |
---|
170 | yy: sm.ytoy, |
---|
171 | dx: g.pt2px(so.x), |
---|
172 | dy: g.pt2px(so.y) |
---|
173 | }); |
---|
174 | }; |
---|
175 | |
---|
176 | var attachGroup = function(object){ |
---|
177 | // summary: |
---|
178 | // reconstructs all group shape parameters from a node (VML). |
---|
179 | // object: dojox/gfx/shape.Shape |
---|
180 | // a VML shape |
---|
181 | |
---|
182 | // attach the background |
---|
183 | object.bgNode = object.rawNode.firstChild; // TODO: check it first |
---|
184 | }; |
---|
185 | |
---|
186 | var attachRect = function(object){ |
---|
187 | // summary: |
---|
188 | // builds a rectangle shape from a node. |
---|
189 | // object: dojox/gfx/shape.Shape |
---|
190 | // a VML shape |
---|
191 | |
---|
192 | // a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node |
---|
193 | var r = object.rawNode, arcsize = r.outerHTML.match(/arcsize = \"(\d*\.?\d+[%f]?)\"/)[1], |
---|
194 | style = r.style, width = parseFloat(style.width), height = parseFloat(style.height); |
---|
195 | arcsize = (arcsize.indexOf("%") >= 0) ? parseFloat(arcsize) / 100 : vml._parseFloat(arcsize); |
---|
196 | // make an object |
---|
197 | object.shape = g.makeParameters(g.defaultRect, { |
---|
198 | x: parseInt(style.left), |
---|
199 | y: parseInt(style.top), |
---|
200 | width: width, |
---|
201 | height: height, |
---|
202 | r: Math.min(width, height) * arcsize |
---|
203 | }); |
---|
204 | }; |
---|
205 | |
---|
206 | var attachEllipse = function(object){ |
---|
207 | // summary: |
---|
208 | // builds an ellipse shape from a node. |
---|
209 | // object: dojox/gfx/shape.Shape |
---|
210 | // a VML shape |
---|
211 | var style = object.rawNode.style, |
---|
212 | rx = parseInt(style.width ) / 2, |
---|
213 | ry = parseInt(style.height) / 2; |
---|
214 | object.shape = g.makeParameters(g.defaultEllipse, { |
---|
215 | cx: parseInt(style.left) + rx, |
---|
216 | cy: parseInt(style.top ) + ry, |
---|
217 | rx: rx, |
---|
218 | ry: ry |
---|
219 | }); |
---|
220 | }; |
---|
221 | |
---|
222 | var attachCircle = function(object){ |
---|
223 | // summary: |
---|
224 | // builds a circle shape from a node. |
---|
225 | // object: dojox/gfx/shape.Shape |
---|
226 | // a VML shape |
---|
227 | var style = object.rawNode.style, r = parseInt(style.width) / 2; |
---|
228 | object.shape = g.makeParameters(g.defaultCircle, { |
---|
229 | cx: parseInt(style.left) + r, |
---|
230 | cy: parseInt(style.top) + r, |
---|
231 | r: r |
---|
232 | }); |
---|
233 | }; |
---|
234 | |
---|
235 | var attachLine = function(object){ |
---|
236 | // summary: |
---|
237 | // builds a line shape from a node. |
---|
238 | // object: dojox/gfx/shape.Shape |
---|
239 | // a VML shape |
---|
240 | var shape = object.shape = lang.clone(g.defaultLine), |
---|
241 | p = object.rawNode.path.v.match(g.pathVmlRegExp); |
---|
242 | do{ |
---|
243 | if(p.length < 7 || p[0] != "m" || p[3] != "l" || p[6] != "e"){ break; } |
---|
244 | shape.x1 = parseInt(p[1]); |
---|
245 | shape.y1 = parseInt(p[2]); |
---|
246 | shape.x2 = parseInt(p[4]); |
---|
247 | shape.y2 = parseInt(p[5]); |
---|
248 | }while(false); |
---|
249 | }; |
---|
250 | |
---|
251 | var attachPolyline = function(object){ |
---|
252 | // summary: |
---|
253 | // builds a polyline/polygon shape from a node. |
---|
254 | // object: dojox/gfx/shape.Shape |
---|
255 | // a VML shape |
---|
256 | var shape = object.shape = lang.clone(g.defaultPolyline), |
---|
257 | p = object.rawNode.path.v.match(g.pathVmlRegExp); |
---|
258 | do{ |
---|
259 | if(p.length < 3 || p[0] != "m"){ break; } |
---|
260 | var x = parseInt(p[0]), y = parseInt(p[1]); |
---|
261 | if(isNaN(x) || isNaN(y)){ break; } |
---|
262 | shape.points.push({x: x, y: y}); |
---|
263 | if(p.length < 6 || p[3] != "l"){ break; } |
---|
264 | for(var i = 4; i < p.length; i += 2){ |
---|
265 | x = parseInt(p[i]); |
---|
266 | y = parseInt(p[i + 1]); |
---|
267 | if(isNaN(x) || isNaN(y)){ break; } |
---|
268 | shape.points.push({x: x, y: y}); |
---|
269 | } |
---|
270 | }while(false); |
---|
271 | }; |
---|
272 | |
---|
273 | var attachImage = function(object){ |
---|
274 | // summary: |
---|
275 | // builds an image shape from a node. |
---|
276 | // object: dojox/gfx/shape.Shape |
---|
277 | // a VML shape |
---|
278 | object.shape = lang.clone(g.defaultImage); |
---|
279 | object.shape.src = object.rawNode.firstChild.src; |
---|
280 | }; |
---|
281 | |
---|
282 | var attachImageTransform = function(object) { |
---|
283 | // summary: |
---|
284 | // deduces a transformation matrix from a node. |
---|
285 | // object: dojox/gfx/shape.Shape |
---|
286 | // a VML shape |
---|
287 | var mm = object.rawNode.filters["DXImageTransform.Microsoft.Matrix"]; |
---|
288 | object.matrix = m.normalize({ |
---|
289 | xx: mm.M11, |
---|
290 | xy: mm.M12, |
---|
291 | yx: mm.M21, |
---|
292 | yy: mm.M22, |
---|
293 | dx: mm.Dx, |
---|
294 | dy: mm.Dy |
---|
295 | }); |
---|
296 | }; |
---|
297 | |
---|
298 | var attachText = function(object){ |
---|
299 | // summary: |
---|
300 | // builds a text shape from a node. |
---|
301 | // object: dojox/gfx/shape.Shape |
---|
302 | // a VML shape |
---|
303 | var shape = object.shape = lang.clone(g.defaultText), |
---|
304 | r = object.rawNode, p = r.path.v.match(g.pathVmlRegExp); |
---|
305 | do{ |
---|
306 | if(!p || p.length != 7){ break; } |
---|
307 | var c = r.childNodes, i = 0; |
---|
308 | for(; i < c.length && c[i].tagName != "textpath"; ++i); |
---|
309 | if(i >= c.length){ break; } |
---|
310 | var s = c[i].style; |
---|
311 | shape.text = c[i].string; |
---|
312 | switch(s["v-text-align"]){ |
---|
313 | case "left": |
---|
314 | shape.x = parseInt(p[1]); |
---|
315 | shape.align = "start"; |
---|
316 | break; |
---|
317 | case "center": |
---|
318 | shape.x = (parseInt(p[1]) + parseInt(p[4])) / 2; |
---|
319 | shape.align = "middle"; |
---|
320 | break; |
---|
321 | case "right": |
---|
322 | shape.x = parseInt(p[4]); |
---|
323 | shape.align = "end"; |
---|
324 | break; |
---|
325 | } |
---|
326 | shape.y = parseInt(p[2]); |
---|
327 | shape.decoration = s["text-decoration"]; |
---|
328 | shape.rotated = s["v-rotate-letters"].toLowerCase() in vml._bool; |
---|
329 | shape.kerning = s["v-text-kern"].toLowerCase() in vml._bool; |
---|
330 | return; |
---|
331 | }while(false); |
---|
332 | object.shape = null; |
---|
333 | }; |
---|
334 | |
---|
335 | var attachFont = function(object){ |
---|
336 | // summary: |
---|
337 | // deduces a font style from a node. |
---|
338 | // object: dojox/gfx/shape.Shape |
---|
339 | // a VML shape |
---|
340 | var fontStyle = object.fontStyle = lang.clone(g.defaultFont), |
---|
341 | c = object.rawNode.childNodes, i = 0; |
---|
342 | for(; i < c.length && c[i].tagName == "textpath"; ++i); |
---|
343 | if(i >= c.length){ |
---|
344 | object.fontStyle = null; |
---|
345 | return; |
---|
346 | } |
---|
347 | var s = c[i].style; |
---|
348 | fontStyle.style = s.fontstyle; |
---|
349 | fontStyle.variant = s.fontvariant; |
---|
350 | fontStyle.weight = s.fontweight; |
---|
351 | fontStyle.size = s.fontsize; |
---|
352 | fontStyle.family = s.fontfamily; |
---|
353 | }; |
---|
354 | |
---|
355 | var attachTextTransform = function(object) { |
---|
356 | // summary: |
---|
357 | // deduces a transformation matrix from a node. |
---|
358 | // object: dojox/gfx/shape.Shape |
---|
359 | // a VML shape |
---|
360 | attachTransform(object); |
---|
361 | var matrix = object.matrix, fs = object.fontStyle; |
---|
362 | // see comments in _getRealMatrix() |
---|
363 | if(matrix && fs){ |
---|
364 | object.matrix = m.multiply(matrix, {dy: g.normalizedLength(fs.size) * 0.35}); |
---|
365 | } |
---|
366 | }; |
---|
367 | |
---|
368 | var attachPath = function(object){ |
---|
369 | // summary: |
---|
370 | // builds a path shape from a Node. |
---|
371 | // object: dojox/gfx/shape.Shape |
---|
372 | // a VML shape |
---|
373 | var shape = object.shape = lang.clone(g.defaultPath), |
---|
374 | p = object.rawNode.path.v.match(g.pathVmlRegExp), |
---|
375 | t = [], skip = false, map = pathLib._pathVmlToSvgMap; |
---|
376 | for(var i = 0; i < p.length; ++p){ |
---|
377 | var s = p[i]; |
---|
378 | if(s in map) { |
---|
379 | skip = false; |
---|
380 | t.push(map[s]); |
---|
381 | } else if(!skip){ |
---|
382 | var n = parseInt(s); |
---|
383 | if(isNaN(n)){ |
---|
384 | skip = true; |
---|
385 | }else{ |
---|
386 | t.push(n); |
---|
387 | } |
---|
388 | } |
---|
389 | } |
---|
390 | var l = t.length; |
---|
391 | if(l >= 4 && t[l - 1] == "" && t[l - 2] == 0 && t[l - 3] == 0 && t[l - 4] == "l"){ |
---|
392 | t.splice(l - 4, 4); |
---|
393 | } |
---|
394 | if(l){ |
---|
395 | shape.path = t.join(" "); |
---|
396 | } |
---|
397 | }; |
---|
398 | |
---|
399 | return vml; //return augmented vml api |
---|
400 | }); |
---|