2150 |
mathias |
1 |
if(!dojo._hasResource["dojox.gfx.vml"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2 |
dojo._hasResource["dojox.gfx.vml"] = true;
|
|
|
3 |
dojo.provide("dojox.gfx.vml");
|
|
|
4 |
|
|
|
5 |
dojo.require("dojox.gfx._base");
|
|
|
6 |
dojo.require("dojox.gfx.shape");
|
|
|
7 |
dojo.require("dojox.gfx.path");
|
|
|
8 |
dojo.require("dojox.gfx.arc");
|
|
|
9 |
|
|
|
10 |
// dojox.gfx.vml.xmlns: String: a VML's namespace
|
|
|
11 |
dojox.gfx.vml.xmlns = "urn:schemas-microsoft-com:vml";
|
|
|
12 |
|
|
|
13 |
// dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment
|
|
|
14 |
dojox.gfx.vml.text_alignment = {start: "left", middle: "center", end: "right"};
|
|
|
15 |
|
|
|
16 |
dojox.gfx.vml._parseFloat = function(str) {
|
|
|
17 |
// summary: a helper function to parse VML-specific floating-point values
|
|
|
18 |
// str: String: a representation of a floating-point number
|
|
|
19 |
return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str); // Number
|
|
|
20 |
};
|
|
|
21 |
|
|
|
22 |
dojox.gfx.vml._bool = {"t": 1, "true": 1};
|
|
|
23 |
|
|
|
24 |
dojo.extend(dojox.gfx.Shape, {
|
|
|
25 |
// summary: VML-specific implementation of dojox.gfx.Shape methods
|
|
|
26 |
|
|
|
27 |
setFill: function(fill){
|
|
|
28 |
// summary: sets a fill object (VML)
|
|
|
29 |
// fill: Object: a fill object
|
|
|
30 |
// (see dojox.gfx.defaultLinearGradient,
|
|
|
31 |
// dojox.gfx.defaultRadialGradient,
|
|
|
32 |
// dojox.gfx.defaultPattern,
|
|
|
33 |
// or dojo.Color)
|
|
|
34 |
|
|
|
35 |
if(!fill){
|
|
|
36 |
// don't fill
|
|
|
37 |
this.fillStyle = null;
|
|
|
38 |
this.rawNode.filled = "f";
|
|
|
39 |
return this;
|
|
|
40 |
}
|
|
|
41 |
if(typeof fill == "object" && "type" in fill){
|
|
|
42 |
// gradient
|
|
|
43 |
switch(fill.type){
|
|
|
44 |
case "linear":
|
|
|
45 |
var f = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill),
|
|
|
46 |
s = [], a = f.colors, matrix = this._getRealMatrix(), m = dojox.gfx.matrix;
|
|
|
47 |
this.fillStyle = f;
|
|
|
48 |
dojo.forEach(a, function(v, i, a){
|
|
|
49 |
a[i].color = dojox.gfx.normalizeColor(v.color);
|
|
|
50 |
});
|
|
|
51 |
if(a[0].offset > 0){
|
|
|
52 |
s.push("0 " + a[0].color.toHex());
|
|
|
53 |
}
|
|
|
54 |
for(var i = 0; i < a.length; ++i){
|
|
|
55 |
s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex());
|
|
|
56 |
}
|
|
|
57 |
var i = a.length - 1;
|
|
|
58 |
if(a[i].offset < 1){
|
|
|
59 |
s.push("1 " + a[i].color.toHex());
|
|
|
60 |
}
|
|
|
61 |
var fo = this.rawNode.fill;
|
|
|
62 |
fo.colors.value = s.join(";");
|
|
|
63 |
fo.method = "sigma";
|
|
|
64 |
fo.type = "gradient";
|
|
|
65 |
var fc1 = matrix ? m.multiplyPoint(matrix, f.x1, f.y1) : {x: f.x1, y: f.y1},
|
|
|
66 |
fc2 = matrix ? m.multiplyPoint(matrix, f.x2, f.y2) : {x: f.x2, y: f.y2};
|
|
|
67 |
fo.angle = (m._radToDeg(Math.atan2(fc2.x - fc1.x, fc2.y - fc1.y)) + 180) % 360;
|
|
|
68 |
fo.on = true;
|
|
|
69 |
break;
|
|
|
70 |
case "radial":
|
|
|
71 |
var f = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
|
|
|
72 |
this.fillStyle = f;
|
|
|
73 |
var l = parseFloat(this.rawNode.style.left),
|
|
|
74 |
t = parseFloat(this.rawNode.style.top),
|
|
|
75 |
w = parseFloat(this.rawNode.style.width),
|
|
|
76 |
h = parseFloat(this.rawNode.style.height),
|
|
|
77 |
c = isNaN(w) ? 1 : 2 * f.r / w,
|
|
|
78 |
a = new Array(f.colors.length);
|
|
|
79 |
// massage colors
|
|
|
80 |
dojo.forEach(f.colors, function(v, i){
|
|
|
81 |
a[i] = {offset: 1 - v.offset * c, color: dojox.gfx.normalizeColor(v.color)};
|
|
|
82 |
});
|
|
|
83 |
var i = a.length - 1;
|
|
|
84 |
while(i >= 0 && a[i].offset < 0){ --i; }
|
|
|
85 |
if(i < a.length - 1){
|
|
|
86 |
// correct excessive colors
|
|
|
87 |
var q = a[i], p = a[i + 1];
|
|
|
88 |
p.color = dojo.blendColors(q.color, p.color, q.offset / (q.offset - p.offset));
|
|
|
89 |
p.offset = 0;
|
|
|
90 |
while(a.length - i > 2) a.pop();
|
|
|
91 |
}
|
|
|
92 |
// set colors
|
|
|
93 |
var i = a.length - 1, s = [];
|
|
|
94 |
if(a[i].offset > 0){
|
|
|
95 |
s.push("0 " + a[i].color.toHex());
|
|
|
96 |
}
|
|
|
97 |
for(; i >= 0; --i){
|
|
|
98 |
s.push(a[i].offset.toFixed(8) + " " + a[i].color.toHex());
|
|
|
99 |
}
|
|
|
100 |
if(a[0].offset < 1){
|
|
|
101 |
s.push("1 " + a[0].color.toHex());
|
|
|
102 |
}
|
|
|
103 |
var fo = this.rawNode.fill;
|
|
|
104 |
fo.colors.value = s.join(";");
|
|
|
105 |
fo.method = "sigma";
|
|
|
106 |
fo.type = "gradientradial";
|
|
|
107 |
if(isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)){
|
|
|
108 |
fo.focusposition = "0.5 0.5";
|
|
|
109 |
}else{
|
|
|
110 |
fo.focusposition = ((f.cx - l) / w).toFixed(8) + " " + ((f.cy - t) / h).toFixed(8);
|
|
|
111 |
}
|
|
|
112 |
fo.focussize = "0 0";
|
|
|
113 |
fo.on = true;
|
|
|
114 |
break;
|
|
|
115 |
case "pattern":
|
|
|
116 |
var f = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
|
|
|
117 |
this.fillStyle = f;
|
|
|
118 |
var fo = this.rawNode.fill;
|
|
|
119 |
fo.type = "tile";
|
|
|
120 |
fo.src = f.src;
|
|
|
121 |
if(f.width && f.height){
|
|
|
122 |
// in points
|
|
|
123 |
fo.size.x = dojox.gfx.px2pt(f.width);
|
|
|
124 |
fo.size.y = dojox.gfx.px2pt(f.height);
|
|
|
125 |
}
|
|
|
126 |
fo.alignShape = "f";
|
|
|
127 |
fo.position.x = 0;
|
|
|
128 |
fo.position.y = 0;
|
|
|
129 |
fo.origin.x = f.width ? f.x / f.width : 0;
|
|
|
130 |
fo.origin.y = f.height ? f.y / f.height : 0;
|
|
|
131 |
fo.on = true;
|
|
|
132 |
break;
|
|
|
133 |
}
|
|
|
134 |
this.rawNode.fill.opacity = 1;
|
|
|
135 |
return this;
|
|
|
136 |
}
|
|
|
137 |
// color object
|
|
|
138 |
this.fillStyle = dojox.gfx.normalizeColor(fill);
|
|
|
139 |
this.rawNode.fillcolor = this.fillStyle.toHex();
|
|
|
140 |
this.rawNode.fill.opacity = this.fillStyle.a;
|
|
|
141 |
this.rawNode.filled = true;
|
|
|
142 |
return this; // self
|
|
|
143 |
},
|
|
|
144 |
|
|
|
145 |
setStroke: function(stroke){
|
|
|
146 |
// summary: sets a stroke object (VML)
|
|
|
147 |
// stroke: Object: a stroke object
|
|
|
148 |
// (see dojox.gfx.defaultStroke)
|
|
|
149 |
|
|
|
150 |
if(!stroke){
|
|
|
151 |
// don't stroke
|
|
|
152 |
this.strokeStyle = null;
|
|
|
153 |
this.rawNode.stroked = "f";
|
|
|
154 |
return this;
|
|
|
155 |
}
|
|
|
156 |
// normalize the stroke
|
|
|
157 |
if(typeof stroke == "string"){
|
|
|
158 |
stroke = {color: stroke};
|
|
|
159 |
}
|
|
|
160 |
var s = this.strokeStyle = dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke);
|
|
|
161 |
s.color = dojox.gfx.normalizeColor(s.color);
|
|
|
162 |
// generate attributes
|
|
|
163 |
var rn = this.rawNode;
|
|
|
164 |
rn.stroked = true;
|
|
|
165 |
rn.strokecolor = s.color.toCss();
|
|
|
166 |
rn.strokeweight = s.width + "px"; // TODO: should we assume that the width is always in pixels?
|
|
|
167 |
if(rn.stroke) {
|
|
|
168 |
rn.stroke.opacity = s.color.a;
|
|
|
169 |
rn.stroke.endcap = this._translate(this._capMap, s.cap);
|
|
|
170 |
if(typeof s.join == "number") {
|
|
|
171 |
rn.stroke.joinstyle = "miter";
|
|
|
172 |
rn.stroke.miterlimit = s.join;
|
|
|
173 |
}else{
|
|
|
174 |
rn.stroke.joinstyle = s.join;
|
|
|
175 |
// rn.stroke.miterlimit = s.width;
|
|
|
176 |
}
|
|
|
177 |
rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
|
|
|
178 |
}
|
|
|
179 |
return this; // self
|
|
|
180 |
},
|
|
|
181 |
|
|
|
182 |
_capMap: { butt: 'flat' },
|
|
|
183 |
_capMapReversed: { flat: 'butt' },
|
|
|
184 |
|
|
|
185 |
_translate: function(dict, value) {
|
|
|
186 |
return (value in dict) ? dict[value] : value;
|
|
|
187 |
},
|
|
|
188 |
|
|
|
189 |
_applyTransform: function() {
|
|
|
190 |
if(this.fillStyle && this.fillStyle.type == "linear"){
|
|
|
191 |
this.setFill(this.fillStyle);
|
|
|
192 |
}
|
|
|
193 |
var matrix = this._getRealMatrix();
|
|
|
194 |
if(!matrix) return this;
|
|
|
195 |
var skew = this.rawNode.skew;
|
|
|
196 |
if(typeof skew == "undefined"){
|
|
|
197 |
for(var i = 0; i < this.rawNode.childNodes.length; ++i){
|
|
|
198 |
if(this.rawNode.childNodes[i].tagName == "skew"){
|
|
|
199 |
skew = this.rawNode.childNodes[i];
|
|
|
200 |
break;
|
|
|
201 |
}
|
|
|
202 |
}
|
|
|
203 |
}
|
|
|
204 |
if(skew){
|
|
|
205 |
skew.on = "f";
|
|
|
206 |
var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " +
|
|
|
207 |
matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0",
|
|
|
208 |
offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px",
|
|
|
209 |
s = this.rawNode.style,
|
|
|
210 |
l = parseFloat(s.left),
|
|
|
211 |
t = parseFloat(s.top),
|
|
|
212 |
w = parseFloat(s.width),
|
|
|
213 |
h = parseFloat(s.height);
|
|
|
214 |
if(isNaN(l)) l = 0;
|
|
|
215 |
if(isNaN(t)) t = 0;
|
|
|
216 |
if(isNaN(w)) w = 1;
|
|
|
217 |
if(isNaN(h)) h = 1;
|
|
|
218 |
var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
|
|
|
219 |
skew.matrix = mt;
|
|
|
220 |
skew.origin = origin;
|
|
|
221 |
skew.offset = offset;
|
|
|
222 |
skew.on = true;
|
|
|
223 |
}
|
|
|
224 |
return this;
|
|
|
225 |
},
|
|
|
226 |
|
|
|
227 |
setRawNode: function(rawNode){
|
|
|
228 |
// summary:
|
|
|
229 |
// assigns and clears the underlying node that will represent this
|
|
|
230 |
// shape. Once set, transforms, gradients, etc, can be applied.
|
|
|
231 |
// (no fill & stroke by default)
|
|
|
232 |
rawNode.stroked = "f";
|
|
|
233 |
rawNode.filled = "f";
|
|
|
234 |
this.rawNode = rawNode;
|
|
|
235 |
},
|
|
|
236 |
|
|
|
237 |
// move family
|
|
|
238 |
|
|
|
239 |
_moveToFront: function(){
|
|
|
240 |
// summary: moves a shape to front of its parent's list of shapes (VML)
|
|
|
241 |
this.rawNode.parentNode.appendChild(this.rawNode);
|
|
|
242 |
return this;
|
|
|
243 |
},
|
|
|
244 |
_moveToBack: function(){
|
|
|
245 |
// summary: moves a shape to back of its parent's list of shapes (VML)
|
|
|
246 |
var r = this.rawNode, p = r.parentNode, n = p.firstChild;
|
|
|
247 |
p.insertBefore(r, n);
|
|
|
248 |
if(n.tagName == "rect"){
|
|
|
249 |
// surface has a background rectangle, which position should be preserved
|
|
|
250 |
n.swapNode(r);
|
|
|
251 |
}
|
|
|
252 |
return this;
|
|
|
253 |
},
|
|
|
254 |
|
|
|
255 |
_getRealMatrix: function(){
|
|
|
256 |
// summary: returns the cumulative ("real") transformation matrix
|
|
|
257 |
// by combining the shape's matrix with its parent's matrix
|
|
|
258 |
return this.parentMatrix ? new dojox.gfx.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix; // dojox.gfx.Matrix2D
|
|
|
259 |
}
|
|
|
260 |
});
|
|
|
261 |
|
|
|
262 |
dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, {
|
|
|
263 |
// summary: a group shape (VML), which can be used
|
|
|
264 |
// to logically group shapes (e.g, to propagate matricies)
|
|
|
265 |
constructor: function(){
|
|
|
266 |
dojox.gfx.vml.Container._init.call(this);
|
|
|
267 |
},
|
|
|
268 |
// apply transformation
|
|
|
269 |
_applyTransform: function(){
|
|
|
270 |
// summary: applies a transformation matrix to a group
|
|
|
271 |
var matrix = this._getRealMatrix();
|
|
|
272 |
for(var i = 0; i < this.children.length; ++i){
|
|
|
273 |
this.children[i]._updateParentMatrix(matrix);
|
|
|
274 |
}
|
|
|
275 |
return this; // self
|
|
|
276 |
}
|
|
|
277 |
});
|
|
|
278 |
dojox.gfx.Group.nodeType = "group";
|
|
|
279 |
|
|
|
280 |
dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
|
|
|
281 |
// summary: a rectangle shape (VML)
|
|
|
282 |
setShape: function(newShape){
|
|
|
283 |
// summary: sets a rectangle shape object (VML)
|
|
|
284 |
// newShape: Object: a rectangle shape object
|
|
|
285 |
var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
286 |
this.bbox = null;
|
|
|
287 |
var style = this.rawNode.style;
|
|
|
288 |
style.left = shape.x.toFixed();
|
|
|
289 |
style.top = shape.y.toFixed();
|
|
|
290 |
style.width = (typeof shape.width == "string" && shape.width.indexOf("%") >= 0) ? shape.width : shape.width.toFixed();
|
|
|
291 |
style.height = (typeof shape.width == "string" && shape.height.indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
|
|
|
292 |
var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
|
|
|
293 |
// a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
|
|
|
294 |
var parent = this.rawNode.parentNode, before = null;
|
|
|
295 |
if(parent){
|
|
|
296 |
if(parent.lastChild != this.rawNode){
|
|
|
297 |
for(var i = 0; i < parent.childNodes.length; ++i){
|
|
|
298 |
if(parent.childNodes[i] == this.rawNode){
|
|
|
299 |
before = parent.childNodes[i+1];
|
|
|
300 |
break;
|
|
|
301 |
}
|
|
|
302 |
}
|
|
|
303 |
}
|
|
|
304 |
parent.removeChild(this.rawNode);
|
|
|
305 |
}
|
|
|
306 |
this.rawNode.arcsize = r;
|
|
|
307 |
if(parent){
|
|
|
308 |
if(before){
|
|
|
309 |
parent.insertBefore(this.rawNode, before);
|
|
|
310 |
}else{
|
|
|
311 |
parent.appendChild(this.rawNode);
|
|
|
312 |
}
|
|
|
313 |
}
|
|
|
314 |
// set all necessary styles, which are lost by VML (yes, it's a VML's bug)
|
|
|
315 |
return this.setTransform(this.matrix).setFill(this.fillStyle).setStroke(this.strokeStyle); // self
|
|
|
316 |
}
|
|
|
317 |
});
|
|
|
318 |
dojox.gfx.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected
|
|
|
319 |
|
|
|
320 |
dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, {
|
|
|
321 |
// summary: an ellipse shape (VML)
|
|
|
322 |
setShape: function(newShape){
|
|
|
323 |
// summary: sets an ellipse shape object (VML)
|
|
|
324 |
// newShape: Object: an ellipse shape object
|
|
|
325 |
var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
326 |
this.bbox = null;
|
|
|
327 |
var style = this.rawNode.style;
|
|
|
328 |
style.left = (shape.cx - shape.rx).toFixed();
|
|
|
329 |
style.top = (shape.cy - shape.ry).toFixed();
|
|
|
330 |
style.width = (shape.rx * 2).toFixed();
|
|
|
331 |
style.height = (shape.ry * 2).toFixed();
|
|
|
332 |
return this.setTransform(this.matrix); // self
|
|
|
333 |
}
|
|
|
334 |
});
|
|
|
335 |
dojox.gfx.Ellipse.nodeType = "oval";
|
|
|
336 |
|
|
|
337 |
dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, {
|
|
|
338 |
// summary: a circle shape (VML)
|
|
|
339 |
setShape: function(newShape){
|
|
|
340 |
// summary: sets a circle shape object (VML)
|
|
|
341 |
// newShape: Object: a circle shape object
|
|
|
342 |
var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
343 |
this.bbox = null;
|
|
|
344 |
var style = this.rawNode.style;
|
|
|
345 |
style.left = (shape.cx - shape.r).toFixed();
|
|
|
346 |
style.top = (shape.cy - shape.r).toFixed();
|
|
|
347 |
style.width = (shape.r * 2).toFixed();
|
|
|
348 |
style.height = (shape.r * 2).toFixed();
|
|
|
349 |
return this; // self
|
|
|
350 |
}
|
|
|
351 |
});
|
|
|
352 |
dojox.gfx.Circle.nodeType = "oval";
|
|
|
353 |
|
|
|
354 |
dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, {
|
|
|
355 |
// summary: a line shape (VML)
|
|
|
356 |
constructor: function(rawNode){
|
|
|
357 |
if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
|
|
|
358 |
},
|
|
|
359 |
setShape: function(newShape){
|
|
|
360 |
// summary: sets a line shape object (VML)
|
|
|
361 |
// newShape: Object: a line shape object
|
|
|
362 |
var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
363 |
this.bbox = null;
|
|
|
364 |
this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
|
|
|
365 |
"l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
|
|
|
366 |
return this.setTransform(this.matrix); // self
|
|
|
367 |
}
|
|
|
368 |
});
|
|
|
369 |
dojox.gfx.Line.nodeType = "shape";
|
|
|
370 |
|
|
|
371 |
dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, {
|
|
|
372 |
// summary: a polyline/polygon shape (VML)
|
|
|
373 |
constructor: function(rawNode){
|
|
|
374 |
if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
|
|
|
375 |
},
|
|
|
376 |
setShape: function(points, closed){
|
|
|
377 |
// summary: sets a polyline/polygon shape object (VML)
|
|
|
378 |
// points: Object: a polyline/polygon shape object
|
|
|
379 |
// closed: Boolean?: if true, close the polyline explicitely
|
|
|
380 |
if(points && points instanceof Array){
|
|
|
381 |
// branch
|
|
|
382 |
// points: Array: an array of points
|
|
|
383 |
this.shape = dojox.gfx.makeParameters(this.shape, { points: points });
|
|
|
384 |
if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
|
|
|
385 |
}else{
|
|
|
386 |
this.shape = dojox.gfx.makeParameters(this.shape, points);
|
|
|
387 |
}
|
|
|
388 |
this.bbox = null;
|
|
|
389 |
var attr = [], p = this.shape.points;
|
|
|
390 |
if(p.length > 0){
|
|
|
391 |
attr.push("m");
|
|
|
392 |
var k = 1;
|
|
|
393 |
if(typeof p[0] == "number"){
|
|
|
394 |
attr.push(p[0].toFixed());
|
|
|
395 |
attr.push(p[1].toFixed());
|
|
|
396 |
k = 2;
|
|
|
397 |
}else{
|
|
|
398 |
attr.push(p[0].x.toFixed());
|
|
|
399 |
attr.push(p[0].y.toFixed());
|
|
|
400 |
}
|
|
|
401 |
if(p.length > k){
|
|
|
402 |
attr.push("l");
|
|
|
403 |
for(var i = k; i < p.length; ++i){
|
|
|
404 |
if(typeof p[i] == "number"){
|
|
|
405 |
attr.push(p[i].toFixed());
|
|
|
406 |
}else{
|
|
|
407 |
attr.push(p[i].x.toFixed());
|
|
|
408 |
attr.push(p[i].y.toFixed());
|
|
|
409 |
}
|
|
|
410 |
}
|
|
|
411 |
}
|
|
|
412 |
}
|
|
|
413 |
attr.push("e");
|
|
|
414 |
this.rawNode.path.v = attr.join(" ");
|
|
|
415 |
return this.setTransform(this.matrix); // self
|
|
|
416 |
}
|
|
|
417 |
});
|
|
|
418 |
dojox.gfx.Polyline.nodeType = "shape";
|
|
|
419 |
|
|
|
420 |
dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, {
|
|
|
421 |
// summary: an image (VML)
|
|
|
422 |
constructor: function(rawNode){
|
|
|
423 |
if(rawNode) rawNode.setAttribute("dojoGfxType", "image");
|
|
|
424 |
},
|
|
|
425 |
getEventSource: function() {
|
|
|
426 |
// summary: returns a Node, which is used as
|
|
|
427 |
// a source of events for this shape
|
|
|
428 |
return this.rawNode ? this.rawNode.firstChild : null; // Node
|
|
|
429 |
},
|
|
|
430 |
setShape: function(newShape){
|
|
|
431 |
// summary: sets an image shape object (VML)
|
|
|
432 |
// newShape: Object: an image shape object
|
|
|
433 |
var shape = this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
434 |
this.bbox = null;
|
|
|
435 |
var firstChild = this.rawNode.firstChild;
|
|
|
436 |
firstChild.src = shape.src;
|
|
|
437 |
if(shape.width || shape.height){
|
|
|
438 |
firstChild.style.width = shape.width;
|
|
|
439 |
firstChild.style.height = shape.height;
|
|
|
440 |
}
|
|
|
441 |
return this.setTransform(this.matrix); // self
|
|
|
442 |
},
|
|
|
443 |
_applyTransform: function() {
|
|
|
444 |
var matrix = this._getRealMatrix();
|
|
|
445 |
if(!matrix) return this;
|
|
|
446 |
matrix = dojox.gfx.matrix.multiply(matrix, {dx: this.shape.x, dy: this.shape.y});
|
|
|
447 |
var f = this.rawNode.filters["DXImageTransform.Microsoft.Matrix"];
|
|
|
448 |
f.M11 = matrix.xx;
|
|
|
449 |
f.M12 = matrix.xy;
|
|
|
450 |
f.M21 = matrix.yx;
|
|
|
451 |
f.M22 = matrix.yy;
|
|
|
452 |
f.Dx = matrix.dx;
|
|
|
453 |
f.Dy = matrix.dy;
|
|
|
454 |
return this;
|
|
|
455 |
}
|
|
|
456 |
});
|
|
|
457 |
dojox.gfx.Image.nodeType = "div";
|
|
|
458 |
|
|
|
459 |
dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, {
|
|
|
460 |
// summary: an anchored text (VML)
|
|
|
461 |
constructor: function(rawNode){
|
|
|
462 |
if(rawNode){rawNode.setAttribute("dojoGfxType", "text");}
|
|
|
463 |
this.fontStyle = null;
|
|
|
464 |
},
|
|
|
465 |
_alignment: {start: "left", middle: "center", end: "right"},
|
|
|
466 |
setShape: function(newShape){
|
|
|
467 |
// summary: sets a text shape object (VML)
|
|
|
468 |
// newShape: Object: a text shape object
|
|
|
469 |
this.shape = dojox.gfx.makeParameters(this.shape, newShape);
|
|
|
470 |
this.bbox = null;
|
|
|
471 |
var r = this.rawNode, s = this.shape, x = s.x, y = s.y.toFixed();
|
|
|
472 |
switch(s.align){
|
|
|
473 |
case "middle":
|
|
|
474 |
x -= 5;
|
|
|
475 |
break;
|
|
|
476 |
case "end":
|
|
|
477 |
x -= 10;
|
|
|
478 |
break;
|
|
|
479 |
}
|
|
|
480 |
this.rawNode.path.v = "m" + x.toFixed() + "," + y +
|
|
|
481 |
"l" + (x + 10).toFixed() + "," + y + "e";
|
|
|
482 |
// find path and text path
|
|
|
483 |
var p = null, t = null, c = r.childNodes;
|
|
|
484 |
for(var i = 0; i < c.length; ++i){
|
|
|
485 |
var tag = c[i].tagName;
|
|
|
486 |
if(tag == "path"){
|
|
|
487 |
p = c[i];
|
|
|
488 |
if(t) break;
|
|
|
489 |
}else if(tag == "textpath"){
|
|
|
490 |
t = c[i];
|
|
|
491 |
if(p) break;
|
|
|
492 |
}
|
|
|
493 |
}
|
|
|
494 |
if(!p){
|
|
|
495 |
p = this.rawNode.ownerDocument.createElement("v:path");
|
|
|
496 |
r.appendChild(p);
|
|
|
497 |
}
|
|
|
498 |
if(!t){
|
|
|
499 |
t = this.rawNode.ownerDocument.createElement("v:textpath");
|
|
|
500 |
r.appendChild(t);
|
|
|
501 |
}
|
|
|
502 |
p.textPathOk = true;
|
|
|
503 |
t.on = true;
|
|
|
504 |
var a = dojox.gfx.vml.text_alignment[s.align];
|
|
|
505 |
t.style["v-text-align"] = a ? a : "left";
|
|
|
506 |
t.style["text-decoration"] = s.decoration;
|
|
|
507 |
t.style["v-rotate-letters"] = s.rotated;
|
|
|
508 |
t.style["v-text-kern"] = s.kerning;
|
|
|
509 |
t.string = s.text;
|
|
|
510 |
return this.setTransform(this.matrix); // self
|
|
|
511 |
},
|
|
|
512 |
_setFont: function(){
|
|
|
513 |
// summary: sets a font object (VML)
|
|
|
514 |
var f = this.fontStyle, c = this.rawNode.childNodes;
|
|
|
515 |
for(var i = 0; i < c.length; ++i){
|
|
|
516 |
if(c[i].tagName == "textpath"){
|
|
|
517 |
c[i].style.font = dojox.gfx.makeFontString(f);
|
|
|
518 |
break;
|
|
|
519 |
}
|
|
|
520 |
}
|
|
|
521 |
this.setTransform(this.matrix);
|
|
|
522 |
},
|
|
|
523 |
_getRealMatrix: function(){
|
|
|
524 |
// summary: returns the cumulative ("real") transformation matrix
|
|
|
525 |
// by combining the shape's matrix with its parent's matrix;
|
|
|
526 |
// it makes a correction for a font size
|
|
|
527 |
var matrix = dojox.gfx.Shape.prototype._getRealMatrix.call(this);
|
|
|
528 |
// It appears that text is always aligned vertically at a middle of x-height (???).
|
|
|
529 |
// It is impossible to obtain these metrics from VML => I try to approximate it with
|
|
|
530 |
// more-or-less util value of 0.7 * FontSize, which is typical for European fonts.
|
|
|
531 |
if(matrix){
|
|
|
532 |
matrix = dojox.gfx.matrix.multiply(matrix,
|
|
|
533 |
{dy: -dojox.gfx.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35});
|
|
|
534 |
}
|
|
|
535 |
return matrix; // dojox.gfx.Matrix2D
|
|
|
536 |
},
|
|
|
537 |
getTextWidth: function(){
|
|
|
538 |
// summary: get the text width, in px
|
|
|
539 |
var rawNode = this.rawNode, _display = rawNode.style.display;
|
|
|
540 |
rawNode.style.display = "inline";
|
|
|
541 |
var _width = dojox.gfx.pt2px(parseFloat(rawNode.currentStyle.width));
|
|
|
542 |
rawNode.style.display = _display;
|
|
|
543 |
return _width;
|
|
|
544 |
}
|
|
|
545 |
});
|
|
|
546 |
dojox.gfx.Text.nodeType = "shape";
|
|
|
547 |
|
|
|
548 |
dojox.gfx.path._calcArc = function(alpha){
|
|
|
549 |
// return a start point, 1st and 2nd control points, and an end point
|
|
|
550 |
var cosa = Math.cos(alpha), sina = Math.sin(alpha),
|
|
|
551 |
p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
|
|
|
552 |
return {
|
|
|
553 |
s: {x: cosa, y: -sina},
|
|
|
554 |
c1: {x: p2.x, y: -p2.y},
|
|
|
555 |
c2: p2,
|
|
|
556 |
e: {x: cosa, y: sina}
|
|
|
557 |
};
|
|
|
558 |
};
|
|
|
559 |
|
|
|
560 |
dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, {
|
|
|
561 |
// summary: a path shape (VML)
|
|
|
562 |
constructor: function(rawNode){
|
|
|
563 |
if(rawNode && !rawNode.getAttribute("dojoGfxType")){
|
|
|
564 |
rawNode.setAttribute("dojoGfxType", "path");
|
|
|
565 |
}
|
|
|
566 |
this.vmlPath = "";
|
|
|
567 |
this.lastControl = {};
|
|
|
568 |
},
|
|
|
569 |
_updateWithSegment: function(segment){
|
|
|
570 |
// summary: updates the bounding box of path with new segment
|
|
|
571 |
// segment: Object: a segment
|
|
|
572 |
var last = dojo.clone(this.last);
|
|
|
573 |
dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
|
|
|
574 |
// add a VML path segment
|
|
|
575 |
var path = this[this.renderers[segment.action]](segment, last);
|
|
|
576 |
if(typeof this.vmlPath == "string"){
|
|
|
577 |
this.vmlPath += path.join("");
|
|
|
578 |
this.rawNode.path.v = this.vmlPath + " r0,0 e";
|
|
|
579 |
}else{
|
|
|
580 |
this.vmlPath = this.vmlPath.concat(path);
|
|
|
581 |
}
|
|
|
582 |
},
|
|
|
583 |
setShape: function(newShape){
|
|
|
584 |
// summary: forms a path using a shape (VML)
|
|
|
585 |
// newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath)
|
|
|
586 |
this.vmlPath = [];
|
|
|
587 |
this.lastControl = {};
|
|
|
588 |
dojox.gfx.Path.superclass.setShape.apply(this, arguments);
|
|
|
589 |
this.vmlPath = this.vmlPath.join("");
|
|
|
590 |
this.rawNode.path.v = this.vmlPath + " r0,0 e";
|
|
|
591 |
return this;
|
|
|
592 |
},
|
|
|
593 |
_pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
|
|
|
594 |
// VML-specific segment renderers
|
|
|
595 |
renderers: {
|
|
|
596 |
M: "_moveToA", m: "_moveToR",
|
|
|
597 |
L: "_lineToA", l: "_lineToR",
|
|
|
598 |
H: "_hLineToA", h: "_hLineToR",
|
|
|
599 |
V: "_vLineToA", v: "_vLineToR",
|
|
|
600 |
C: "_curveToA", c: "_curveToR",
|
|
|
601 |
S: "_smoothCurveToA", s: "_smoothCurveToR",
|
|
|
602 |
Q: "_qCurveToA", q: "_qCurveToR",
|
|
|
603 |
T: "_qSmoothCurveToA", t: "_qSmoothCurveToR",
|
|
|
604 |
A: "_arcTo", a: "_arcTo",
|
|
|
605 |
Z: "_closePath", z: "_closePath"
|
|
|
606 |
},
|
|
|
607 |
_addArgs: function(path, args, from, upto){
|
|
|
608 |
if(typeof upto == "undefined"){
|
|
|
609 |
upto = args.length;
|
|
|
610 |
}
|
|
|
611 |
if(typeof from == "undefined"){
|
|
|
612 |
from = 0;
|
|
|
613 |
}
|
|
|
614 |
for(var i = from; i < upto; ++i){
|
|
|
615 |
path.push(" ");
|
|
|
616 |
path.push(args[i].toFixed());
|
|
|
617 |
}
|
|
|
618 |
},
|
|
|
619 |
_addArgsAdjusted: function(path, last, args, from, upto){
|
|
|
620 |
if(typeof upto == "undefined"){
|
|
|
621 |
upto = args.length;
|
|
|
622 |
}
|
|
|
623 |
if(typeof from == "undefined"){
|
|
|
624 |
from = 0;
|
|
|
625 |
}
|
|
|
626 |
for(var i = from; i < upto; i += 2){
|
|
|
627 |
path.push(" ");
|
|
|
628 |
path.push((last.x + args[i]).toFixed());
|
|
|
629 |
path.push(" ");
|
|
|
630 |
path.push((last.y + args[i + 1]).toFixed());
|
|
|
631 |
}
|
|
|
632 |
},
|
|
|
633 |
_moveToA: function(segment){
|
|
|
634 |
var p = [" m"], n = segment.args, l = n.length;
|
|
|
635 |
if(l == 2){
|
|
|
636 |
this._addArgs(p, n);
|
|
|
637 |
}else{
|
|
|
638 |
this._addArgs(p, n, 0, 2);
|
|
|
639 |
p.push(" l");
|
|
|
640 |
this._addArgs(p, n, 2);
|
|
|
641 |
}
|
|
|
642 |
this.lastControl = {};
|
|
|
643 |
return p;
|
|
|
644 |
},
|
|
|
645 |
_moveToR: function(segment, last){
|
|
|
646 |
var p = ["x" in last ? " t" : " m"], n = segment.args, l = n.length;
|
|
|
647 |
if(l == 2){
|
|
|
648 |
this._addArgs(p, n);
|
|
|
649 |
}else{
|
|
|
650 |
this._addArgs(p, n, 0, 2);
|
|
|
651 |
p.push(" r");
|
|
|
652 |
this._addArgs(p, n, 2);
|
|
|
653 |
}
|
|
|
654 |
this.lastControl = {};
|
|
|
655 |
return p;
|
|
|
656 |
},
|
|
|
657 |
_lineToA: function(segment){
|
|
|
658 |
var p = [" l"];
|
|
|
659 |
this._addArgs(p, segment.args);
|
|
|
660 |
this.lastControl = {};
|
|
|
661 |
return p;
|
|
|
662 |
},
|
|
|
663 |
_lineToR: function(segment){
|
|
|
664 |
var p = [" r"];
|
|
|
665 |
this._addArgs(p, segment.args);
|
|
|
666 |
this.lastControl = {};
|
|
|
667 |
return p;
|
|
|
668 |
},
|
|
|
669 |
_hLineToA: function(segment, last){
|
|
|
670 |
var p = [" l"], n = segment.args, l = n.length, y = " " + last.y.toFixed();
|
|
|
671 |
for(var i = 0; i < l; ++i){
|
|
|
672 |
p.push(" ");
|
|
|
673 |
p.push(n[i].toFixed());
|
|
|
674 |
p.push(y);
|
|
|
675 |
}
|
|
|
676 |
this.lastControl = {};
|
|
|
677 |
return p;
|
|
|
678 |
},
|
|
|
679 |
_hLineToR: function(segment){
|
|
|
680 |
var p = [" r"], n = segment.args, l = n.length;
|
|
|
681 |
for(var i = 0; i < l; ++i){
|
|
|
682 |
p.push(" ");
|
|
|
683 |
p.push(n[i].toFixed());
|
|
|
684 |
p.push(" 0");
|
|
|
685 |
}
|
|
|
686 |
this.lastControl = {};
|
|
|
687 |
return p;
|
|
|
688 |
},
|
|
|
689 |
_vLineToA: function(segment, last){
|
|
|
690 |
var p = [" l"], n = segment.args, l = n.length, x = " " + last.x.toFixed();
|
|
|
691 |
for(var i = 0; i < l; ++i){
|
|
|
692 |
p.push(x);
|
|
|
693 |
p.push(" ");
|
|
|
694 |
p.push(n[i].toFixed());
|
|
|
695 |
}
|
|
|
696 |
this.lastControl = {};
|
|
|
697 |
return p;
|
|
|
698 |
},
|
|
|
699 |
_vLineToR: function(segment){
|
|
|
700 |
var p = [" r"], n = segment.args, l = n.length;
|
|
|
701 |
for(var i = 0; i < l; ++i){
|
|
|
702 |
p.push(" 0 ");
|
|
|
703 |
p.push(n[i].toFixed());
|
|
|
704 |
}
|
|
|
705 |
this.lastControl = {};
|
|
|
706 |
return p;
|
|
|
707 |
},
|
|
|
708 |
_curveToA: function(segment){
|
|
|
709 |
var p = [], n = segment.args, l = n.length;
|
|
|
710 |
for(var i = 0; i < l; i += 6){
|
|
|
711 |
p.push(" c");
|
|
|
712 |
this._addArgs(p, n, i, i + 6);
|
|
|
713 |
}
|
|
|
714 |
this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
|
|
|
715 |
return p;
|
|
|
716 |
},
|
|
|
717 |
_curveToR: function(segment, last){
|
|
|
718 |
var p = [], n = segment.args, l = n.length;
|
|
|
719 |
for(var i = 0; i < l; i += 6){
|
|
|
720 |
p.push(" v");
|
|
|
721 |
this._addArgs(p, n, i, i + 6);
|
|
|
722 |
this.lastControl = {x: last.x + n[i + 2], y: last.y + n[i + 3]};
|
|
|
723 |
last.x += n[i + 4];
|
|
|
724 |
last.y += n[i + 5];
|
|
|
725 |
}
|
|
|
726 |
this.lastControl.type = "C";
|
|
|
727 |
return p;
|
|
|
728 |
},
|
|
|
729 |
_smoothCurveToA: function(segment, last){
|
|
|
730 |
var p = [], n = segment.args, l = n.length;
|
|
|
731 |
for(var i = 0; i < l; i += 4){
|
|
|
732 |
p.push(" c");
|
|
|
733 |
if(this.lastControl.type == "C"){
|
|
|
734 |
this._addArgs(p, [
|
|
|
735 |
2 * last.x - this.lastControl.x,
|
|
|
736 |
2 * last.y - this.lastControl.y
|
|
|
737 |
]);
|
|
|
738 |
}else{
|
|
|
739 |
this._addArgs(p, [last.x, last.y]);
|
|
|
740 |
}
|
|
|
741 |
this._addArgs(p, n, i, i + 4);
|
|
|
742 |
}
|
|
|
743 |
this.lastControl = {x: n[l - 4], y: n[l - 3], type: "C"};
|
|
|
744 |
return p;
|
|
|
745 |
},
|
|
|
746 |
_smoothCurveToR: function(segment, last){
|
|
|
747 |
var p = [], n = segment.args, l = n.length;
|
|
|
748 |
for(var i = 0; i < l; i += 4){
|
|
|
749 |
p.push(" v");
|
|
|
750 |
if(this.lastControl.type == "C"){
|
|
|
751 |
this._addArgs(p, [
|
|
|
752 |
last.x - this.lastControl.x,
|
|
|
753 |
last.y - this.lastControl.y
|
|
|
754 |
]);
|
|
|
755 |
}else{
|
|
|
756 |
this._addArgs(p, [0, 0]);
|
|
|
757 |
}
|
|
|
758 |
this._addArgs(p, n, i, i + 4);
|
|
|
759 |
this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
|
|
|
760 |
last.x += n[i + 2];
|
|
|
761 |
last.y += n[i + 3];
|
|
|
762 |
}
|
|
|
763 |
this.lastControl.type = "C";
|
|
|
764 |
return p;
|
|
|
765 |
},
|
|
|
766 |
_qCurveToA: function(segment){
|
|
|
767 |
var p = [], n = segment.args, l = n.length;
|
|
|
768 |
for(var i = 0; i < l; i += 4){
|
|
|
769 |
p.push(" qb");
|
|
|
770 |
this._addArgs(p, n, i, i + 4);
|
|
|
771 |
}
|
|
|
772 |
this.lastControl = {x: n[l - 4], y: n[l - 3], type: "Q"};
|
|
|
773 |
return p;
|
|
|
774 |
},
|
|
|
775 |
_qCurveToR: function(segment, last){
|
|
|
776 |
var p = [], n = segment.args, l = n.length;
|
|
|
777 |
for(var i = 0; i < l; i += 4){
|
|
|
778 |
p.push(" qb");
|
|
|
779 |
this._addArgsAdjusted(p, last, n, i, i + 4);
|
|
|
780 |
this.lastControl = {x: last.x + n[i], y: last.y + n[i + 1]};
|
|
|
781 |
last.x += n[i + 2];
|
|
|
782 |
last.y += n[i + 3];
|
|
|
783 |
}
|
|
|
784 |
this.lastControl.type = "Q";
|
|
|
785 |
return p;
|
|
|
786 |
},
|
|
|
787 |
_qSmoothCurveToA: function(segment, last){
|
|
|
788 |
var p = [], n = segment.args, l = n.length;
|
|
|
789 |
for(var i = 0; i < l; i += 2){
|
|
|
790 |
p.push(" qb");
|
|
|
791 |
if(this.lastControl.type == "Q"){
|
|
|
792 |
this._addArgs(p, [
|
|
|
793 |
this.lastControl.x = 2 * last.x - this.lastControl.x,
|
|
|
794 |
this.lastControl.y = 2 * last.y - this.lastControl.y
|
|
|
795 |
]);
|
|
|
796 |
}else{
|
|
|
797 |
this._addArgs(p, [
|
|
|
798 |
this.lastControl.x = last.x,
|
|
|
799 |
this.lastControl.y = last.y
|
|
|
800 |
]);
|
|
|
801 |
}
|
|
|
802 |
this._addArgs(p, n, i, i + 2);
|
|
|
803 |
}
|
|
|
804 |
this.lastControl.type = "Q";
|
|
|
805 |
return p;
|
|
|
806 |
},
|
|
|
807 |
_qSmoothCurveToR: function(segment, last){
|
|
|
808 |
var p = [], n = segment.args, l = n.length;
|
|
|
809 |
for(var i = 0; i < l; i += 2){
|
|
|
810 |
p.push(" qb");
|
|
|
811 |
if(this.lastControl.type == "Q"){
|
|
|
812 |
this._addArgs(p, [
|
|
|
813 |
this.lastControl.x = 2 * last.x - this.lastControl.x,
|
|
|
814 |
this.lastControl.y = 2 * last.y - this.lastControl.y
|
|
|
815 |
]);
|
|
|
816 |
}else{
|
|
|
817 |
this._addArgs(p, [
|
|
|
818 |
this.lastControl.x = last.x,
|
|
|
819 |
this.lastControl.y = last.y
|
|
|
820 |
]);
|
|
|
821 |
}
|
|
|
822 |
this._addArgsAdjusted(p, last, n, i, i + 2);
|
|
|
823 |
}
|
|
|
824 |
this.lastControl.type = "Q";
|
|
|
825 |
return p;
|
|
|
826 |
},
|
|
|
827 |
_arcTo: function(segment, last){
|
|
|
828 |
var p = [], n = segment.args, l = n.length, relative = segment.action == "a";
|
|
|
829 |
for(var i = 0; i < l; i += 7){
|
|
|
830 |
var x1 = n[i + 5], y1 = n[i + 6];
|
|
|
831 |
if(relative){
|
|
|
832 |
x1 += last.x;
|
|
|
833 |
y1 += last.y;
|
|
|
834 |
}
|
|
|
835 |
var result = dojox.gfx.arc.arcAsBezier(
|
|
|
836 |
last, n[i], n[i + 1], n[i + 2],
|
|
|
837 |
n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
|
|
|
838 |
x1, y1
|
|
|
839 |
);
|
|
|
840 |
for(var j = 0; j < result.length; ++j){
|
|
|
841 |
p.push(" c");
|
|
|
842 |
this._addArgs(p, result[j]);
|
|
|
843 |
}
|
|
|
844 |
last = {x: x1, y: y1};
|
|
|
845 |
}
|
|
|
846 |
this.lastControl = {};
|
|
|
847 |
return p;
|
|
|
848 |
},
|
|
|
849 |
_closePath: function(){
|
|
|
850 |
this.lastControl = {};
|
|
|
851 |
return ["x"];
|
|
|
852 |
}
|
|
|
853 |
});
|
|
|
854 |
dojox.gfx.Path.nodeType = "shape";
|
|
|
855 |
|
|
|
856 |
dojo.declare("dojox.gfx.TextPath", dojox.gfx.Path, {
|
|
|
857 |
// summary: a textpath shape (VML)
|
|
|
858 |
constructor: function(rawNode){
|
|
|
859 |
if(rawNode){rawNode.setAttribute("dojoGfxType", "textpath");}
|
|
|
860 |
this.fontStyle = null;
|
|
|
861 |
if(!("text" in this)){
|
|
|
862 |
this.text = dojo.clone(dojox.gfx.defaultTextPath);
|
|
|
863 |
}
|
|
|
864 |
if(!("fontStyle" in this)){
|
|
|
865 |
this.fontStyle = dojo.clone(dojox.gfx.defaultFont);
|
|
|
866 |
}
|
|
|
867 |
},
|
|
|
868 |
setText: function(newText){
|
|
|
869 |
// summary: sets a text to be drawn along the path
|
|
|
870 |
this.text = dojox.gfx.makeParameters(this.text,
|
|
|
871 |
typeof newText == "string" ? {text: newText} : newText);
|
|
|
872 |
this._setText();
|
|
|
873 |
return this; // self
|
|
|
874 |
},
|
|
|
875 |
setFont: function(newFont){
|
|
|
876 |
// summary: sets a font for text
|
|
|
877 |
this.fontStyle = typeof newFont == "string" ?
|
|
|
878 |
dojox.gfx.splitFontString(newFont) :
|
|
|
879 |
dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
|
|
|
880 |
this._setFont();
|
|
|
881 |
return this; // self
|
|
|
882 |
},
|
|
|
883 |
|
|
|
884 |
_setText: function(){
|
|
|
885 |
// summary: sets a text shape object (VML)
|
|
|
886 |
this.bbox = null;
|
|
|
887 |
var r = this.rawNode, s = this.text,
|
|
|
888 |
// find path and text path
|
|
|
889 |
p = null, t = null, c = r.childNodes;
|
|
|
890 |
for(var i = 0; i < c.length; ++i){
|
|
|
891 |
var tag = c[i].tagName;
|
|
|
892 |
if(tag == "path"){
|
|
|
893 |
p = c[i];
|
|
|
894 |
if(t) break;
|
|
|
895 |
}else if(tag == "textpath"){
|
|
|
896 |
t = c[i];
|
|
|
897 |
if(p) break;
|
|
|
898 |
}
|
|
|
899 |
}
|
|
|
900 |
if(!p){
|
|
|
901 |
p = this.rawNode.ownerDocument.createElement("v:path");
|
|
|
902 |
r.appendChild(p);
|
|
|
903 |
}
|
|
|
904 |
if(!t){
|
|
|
905 |
t = this.rawNode.ownerDocument.createElement("v:textpath");
|
|
|
906 |
r.appendChild(t);
|
|
|
907 |
}
|
|
|
908 |
p.textPathOk = true;
|
|
|
909 |
t.on = true;
|
|
|
910 |
var a = dojox.gfx.vml.text_alignment[s.align];
|
|
|
911 |
t.style["v-text-align"] = a ? a : "left";
|
|
|
912 |
t.style["text-decoration"] = s.decoration;
|
|
|
913 |
t.style["v-rotate-letters"] = s.rotated;
|
|
|
914 |
t.style["v-text-kern"] = s.kerning;
|
|
|
915 |
t.string = s.text;
|
|
|
916 |
},
|
|
|
917 |
_setFont: function(){
|
|
|
918 |
// summary: sets a font object (VML)
|
|
|
919 |
var f = this.fontStyle, c = this.rawNode.childNodes;
|
|
|
920 |
for(var i = 0; i < c.length; ++i){
|
|
|
921 |
if(c[i].tagName == "textpath"){
|
|
|
922 |
c[i].style.font = dojox.gfx.makeFontString(f);
|
|
|
923 |
break;
|
|
|
924 |
}
|
|
|
925 |
}
|
|
|
926 |
}
|
|
|
927 |
});
|
|
|
928 |
dojox.gfx.TextPath.nodeType = "shape";
|
|
|
929 |
|
|
|
930 |
dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, {
|
|
|
931 |
// summary: a surface object to be used for drawings (VML)
|
|
|
932 |
constructor: function(){
|
|
|
933 |
dojox.gfx.vml.Container._init.call(this);
|
|
|
934 |
},
|
|
|
935 |
setDimensions: function(width, height){
|
|
|
936 |
// summary: sets the width and height of the rawNode
|
|
|
937 |
// width: String: width of surface, e.g., "100px"
|
|
|
938 |
// height: String: height of surface, e.g., "100px"
|
|
|
939 |
this.width = dojox.gfx.normalizedLength(width); // in pixels
|
|
|
940 |
this.height = dojox.gfx.normalizedLength(height); // in pixels
|
|
|
941 |
if(!this.rawNode) return this;
|
|
|
942 |
var cs = this.clipNode.style,
|
|
|
943 |
r = this.rawNode, rs = r.style,
|
|
|
944 |
bs = this.bgNode.style;
|
|
|
945 |
cs.width = width;
|
|
|
946 |
cs.height = height;
|
|
|
947 |
cs.clip = "rect(0 " + width + " " + height + " 0)";
|
|
|
948 |
rs.width = width;
|
|
|
949 |
rs.height = height;
|
|
|
950 |
r.coordsize = width + " " + height;
|
|
|
951 |
bs.width = width;
|
|
|
952 |
bs.height = height;
|
|
|
953 |
return this; // self
|
|
|
954 |
},
|
|
|
955 |
getDimensions: function(){
|
|
|
956 |
// summary: returns an object with properties "width" and "height"
|
|
|
957 |
var t = this.rawNode ? {
|
|
|
958 |
width: dojox.gfx.normalizedLength(this.rawNode.style.width),
|
|
|
959 |
height: dojox.gfx.normalizedLength(this.rawNode.style.height)} : null;
|
|
|
960 |
if(t.width <= 0){ t.width = this.width; }
|
|
|
961 |
if(t.height <= 0){ t.height = this.height; }
|
|
|
962 |
return t; // Object
|
|
|
963 |
}
|
|
|
964 |
});
|
|
|
965 |
|
|
|
966 |
dojox.gfx.createSurface = function(parentNode, width, height){
|
|
|
967 |
// summary: creates a surface (VML)
|
|
|
968 |
// parentNode: Node: a parent node
|
|
|
969 |
// width: String: width of surface, e.g., "100px"
|
|
|
970 |
// height: String: height of surface, e.g., "100px"
|
|
|
971 |
|
|
|
972 |
if(!width){ width = "100%"; }
|
|
|
973 |
if(!height){ height = "100%"; }
|
|
|
974 |
var s = new dojox.gfx.Surface(), p = dojo.byId(parentNode),
|
|
|
975 |
c = s.clipNode = p.ownerDocument.createElement("div"),
|
|
|
976 |
r = s.rawNode = p.ownerDocument.createElement("v:group"),
|
|
|
977 |
cs = c.style, rs = r.style;
|
|
|
978 |
|
|
|
979 |
p.style.width = width;
|
|
|
980 |
p.style.height = height;
|
|
|
981 |
|
|
|
982 |
cs.width = width;
|
|
|
983 |
cs.height = height;
|
|
|
984 |
cs.clip = "rect(0 " + width + " " + height + " 0)";
|
|
|
985 |
cs.position = "absolute";
|
|
|
986 |
rs.width = width;
|
|
|
987 |
rs.height = height;
|
|
|
988 |
r.coordsize = (width == "100%" ? width : parseFloat(width)) + " " +
|
|
|
989 |
(height == "100%" ? height : parseFloat(height));
|
|
|
990 |
r.coordorigin = "0 0";
|
|
|
991 |
|
|
|
992 |
// create a background rectangle, which is required to show all other shapes
|
|
|
993 |
var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style;
|
|
|
994 |
bs.left = bs.top = 0;
|
|
|
995 |
bs.width = rs.width;
|
|
|
996 |
bs.height = rs.height;
|
|
|
997 |
b.filled = b.stroked = "f";
|
|
|
998 |
|
|
|
999 |
r.appendChild(b);
|
|
|
1000 |
c.appendChild(r);
|
|
|
1001 |
p.appendChild(c);
|
|
|
1002 |
|
|
|
1003 |
s.width = dojox.gfx.normalizedLength(width); // in pixels
|
|
|
1004 |
s.height = dojox.gfx.normalizedLength(height); // in pixels
|
|
|
1005 |
|
|
|
1006 |
return s; // dojox.gfx.Surface
|
|
|
1007 |
};
|
|
|
1008 |
|
|
|
1009 |
// Extenders
|
|
|
1010 |
|
|
|
1011 |
dojox.gfx.vml.Container = {
|
|
|
1012 |
_init: function(){
|
|
|
1013 |
dojox.gfx.shape.Container._init.call(this);
|
|
|
1014 |
},
|
|
|
1015 |
add: function(shape){
|
|
|
1016 |
// summary: adds a shape to a group/surface
|
|
|
1017 |
// shape: dojox.gfx.Shape: an VML shape object
|
|
|
1018 |
if(this != shape.getParent()){
|
|
|
1019 |
this.rawNode.appendChild(shape.rawNode);
|
|
|
1020 |
//dojox.gfx.Group.superclass.add.apply(this, arguments);
|
|
|
1021 |
//this.inherited(arguments);
|
|
|
1022 |
dojox.gfx.shape.Container.add.apply(this, arguments);
|
|
|
1023 |
}
|
|
|
1024 |
return this; // self
|
|
|
1025 |
},
|
|
|
1026 |
remove: function(shape, silently){
|
|
|
1027 |
// summary: remove a shape from a group/surface
|
|
|
1028 |
// shape: dojox.gfx.Shape: an VML shape object
|
|
|
1029 |
// silently: Boolean?: if true, regenerate a picture
|
|
|
1030 |
if(this == shape.getParent()){
|
|
|
1031 |
if(this.rawNode == shape.rawNode.parentNode){
|
|
|
1032 |
this.rawNode.removeChild(shape.rawNode);
|
|
|
1033 |
}
|
|
|
1034 |
//dojox.gfx.Group.superclass.remove.apply(this, arguments);
|
|
|
1035 |
//this.inherited(arguments);
|
|
|
1036 |
dojox.gfx.shape.Container.remove.apply(this, arguments);
|
|
|
1037 |
}
|
|
|
1038 |
return this; // self
|
|
|
1039 |
},
|
|
|
1040 |
clear: function(){
|
|
|
1041 |
// summary: removes all shapes from a group/surface
|
|
|
1042 |
var r = this.rawNode;
|
|
|
1043 |
while(r.firstChild != r.lastChild){
|
|
|
1044 |
if(r.firstChild != this.bgNode){
|
|
|
1045 |
r.removeChild(r.firstChild);
|
|
|
1046 |
}
|
|
|
1047 |
if(r.lastChild != this.bgNode){
|
|
|
1048 |
r.removeChild(r.lastChild);
|
|
|
1049 |
}
|
|
|
1050 |
}
|
|
|
1051 |
//return this.inherited(arguments); // self
|
|
|
1052 |
return dojox.gfx.shape.Container.clear.apply(this, arguments);
|
|
|
1053 |
},
|
|
|
1054 |
_moveChildToFront: dojox.gfx.shape.Container._moveChildToFront,
|
|
|
1055 |
_moveChildToBack: dojox.gfx.shape.Container._moveChildToBack
|
|
|
1056 |
};
|
|
|
1057 |
|
|
|
1058 |
dojo.mixin(dojox.gfx.shape.Creator, {
|
|
|
1059 |
// summary: VML shape creators
|
|
|
1060 |
createGroup: function(){
|
|
|
1061 |
// summary: creates a VML group shape
|
|
|
1062 |
var g = this.createObject(dojox.gfx.Group, null); // dojox.gfx.Group
|
|
|
1063 |
// create a background rectangle, which is required to show all other shapes
|
|
|
1064 |
var r = g.rawNode.ownerDocument.createElement("v:rect");
|
|
|
1065 |
r.style.left = r.style.top = 0;
|
|
|
1066 |
r.style.width = g.rawNode.style.width;
|
|
|
1067 |
r.style.height = g.rawNode.style.height;
|
|
|
1068 |
r.filled = r.stroked = "f";
|
|
|
1069 |
g.rawNode.appendChild(r);
|
|
|
1070 |
g.bgNode = r;
|
|
|
1071 |
return g; // dojox.gfx.Group
|
|
|
1072 |
},
|
|
|
1073 |
createImage: function(image){
|
|
|
1074 |
// summary: creates a VML image shape
|
|
|
1075 |
// image: Object: an image object (see dojox.gfx.defaultImage)
|
|
|
1076 |
if(!this.rawNode) return null;
|
|
|
1077 |
var shape = new dojox.gfx.Image(), node = this.rawNode.ownerDocument.createElement('div');
|
|
|
1078 |
node.style.position = "absolute";
|
|
|
1079 |
node.style.width = this.rawNode.style.width;
|
|
|
1080 |
node.style.height = this.rawNode.style.height;
|
|
|
1081 |
node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, Dx=0, Dy=0)";
|
|
|
1082 |
var img = this.rawNode.ownerDocument.createElement('img');
|
|
|
1083 |
node.appendChild(img);
|
|
|
1084 |
shape.setRawNode(node);
|
|
|
1085 |
this.rawNode.appendChild(node);
|
|
|
1086 |
shape.setShape(image);
|
|
|
1087 |
this.add(shape);
|
|
|
1088 |
return shape; // dojox.gfx.Image
|
|
|
1089 |
},
|
|
|
1090 |
createObject: function(shapeType, rawShape) {
|
|
|
1091 |
// summary: creates an instance of the passed shapeType class
|
|
|
1092 |
// shapeType: Function: a class constructor to create an instance of
|
|
|
1093 |
// rawShape: Object: properties to be passed in to the classes "setShape" method
|
|
|
1094 |
// overrideSize: Boolean: set the size explicitly, if true
|
|
|
1095 |
if(!this.rawNode) return null;
|
|
|
1096 |
var shape = new shapeType(),
|
|
|
1097 |
node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType);
|
|
|
1098 |
shape.setRawNode(node);
|
|
|
1099 |
this.rawNode.appendChild(node);
|
|
|
1100 |
switch(shapeType){
|
|
|
1101 |
case dojox.gfx.Group:
|
|
|
1102 |
case dojox.gfx.Line:
|
|
|
1103 |
case dojox.gfx.Polyline:
|
|
|
1104 |
case dojox.gfx.Text:
|
|
|
1105 |
case dojox.gfx.Path:
|
|
|
1106 |
case dojox.gfx.TextPath:
|
|
|
1107 |
this._overrideSize(node);
|
|
|
1108 |
}
|
|
|
1109 |
shape.setShape(rawShape);
|
|
|
1110 |
this.add(shape);
|
|
|
1111 |
return shape; // dojox.gfx.Shape
|
|
|
1112 |
},
|
|
|
1113 |
_overrideSize: function(node){
|
|
|
1114 |
var p = this;
|
|
|
1115 |
for(; p && !(p instanceof dojox.gfx.Surface); p = p.parent);
|
|
|
1116 |
node.style.width = p.width;
|
|
|
1117 |
node.style.height = p.height;
|
|
|
1118 |
node.coordsize = p.width + " " + p.height;
|
|
|
1119 |
}
|
|
|
1120 |
});
|
|
|
1121 |
|
|
|
1122 |
dojo.extend(dojox.gfx.Group, dojox.gfx.vml.Container);
|
|
|
1123 |
dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator);
|
|
|
1124 |
|
|
|
1125 |
dojo.extend(dojox.gfx.Surface, dojox.gfx.vml.Container);
|
|
|
1126 |
dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator);
|
|
|
1127 |
|
|
|
1128 |
}
|