[483] | 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 | }); |
---|