Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/graphics/vmlgraphics.js
2868 views
1
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
16
/**
17
* @fileoverview VmlGraphics sub class that uses VML to draw the graphics.
18
* @author [email protected] (Erik Arvidsson)
19
*/
20
21
22
goog.provide('goog.graphics.VmlGraphics');
23
24
25
goog.require('goog.array');
26
goog.require('goog.dom.TagName');
27
goog.require('goog.dom.safe');
28
goog.require('goog.events');
29
goog.require('goog.events.EventHandler');
30
goog.require('goog.events.EventType');
31
goog.require('goog.graphics.AbstractGraphics');
32
goog.require('goog.graphics.Font');
33
goog.require('goog.graphics.LinearGradient');
34
goog.require('goog.graphics.Path');
35
goog.require('goog.graphics.SolidFill');
36
goog.require('goog.graphics.VmlEllipseElement');
37
goog.require('goog.graphics.VmlGroupElement');
38
goog.require('goog.graphics.VmlImageElement');
39
goog.require('goog.graphics.VmlPathElement');
40
goog.require('goog.graphics.VmlRectElement');
41
goog.require('goog.graphics.VmlTextElement');
42
goog.require('goog.html.uncheckedconversions');
43
goog.require('goog.math');
44
goog.require('goog.math.Size');
45
goog.require('goog.reflect');
46
goog.require('goog.string');
47
goog.require('goog.string.Const');
48
goog.require('goog.style');
49
goog.require('goog.userAgent');
50
51
52
53
/**
54
* A Graphics implementation for drawing using VML.
55
* @param {string|number} width The (non-zero) width in pixels. Strings
56
* expressing percentages of parent with (e.g. '80%') are also accepted.
57
* @param {string|number} height The (non-zero) height in pixels. Strings
58
* expressing percentages of parent with (e.g. '80%') are also accepted.
59
* @param {?number=} opt_coordWidth The coordinate width - if
60
* omitted or null, defaults to same as width.
61
* @param {?number=} opt_coordHeight The coordinate height - if
62
* omitted or null, defaults to same as height.
63
* @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
64
* document we want to render in.
65
* @constructor
66
* @extends {goog.graphics.AbstractGraphics}
67
* @deprecated goog.graphics is deprecated. It existed to abstract over browser
68
* differences before the canvas tag was widely supported. See
69
* http://en.wikipedia.org/wiki/Canvas_element for details.
70
* @final
71
*/
72
goog.graphics.VmlGraphics = function(
73
width, height, opt_coordWidth, opt_coordHeight, opt_domHelper) {
74
goog.graphics.AbstractGraphics.call(
75
this, width, height, opt_coordWidth, opt_coordHeight, opt_domHelper);
76
this.handler_ = new goog.events.EventHandler(this);
77
this.registerDisposable(this.handler_);
78
};
79
goog.inherits(goog.graphics.VmlGraphics, goog.graphics.AbstractGraphics);
80
81
82
/**
83
* The prefix to use for VML elements
84
* @private
85
* @type {string}
86
*/
87
goog.graphics.VmlGraphics.VML_PREFIX_ = 'g_vml_';
88
89
90
/**
91
* The VML namespace URN
92
* @private
93
* @type {string}
94
*/
95
goog.graphics.VmlGraphics.VML_NS_ = 'urn:schemas-microsoft-com:vml';
96
97
98
/**
99
* The VML behavior URL.
100
* @private
101
* @type {string}
102
*/
103
goog.graphics.VmlGraphics.VML_IMPORT_ = '#default#VML';
104
105
106
/**
107
* Whether the document is using IE8 standards mode, and therefore needs hacks.
108
* @private
109
* @type {boolean}
110
*/
111
goog.graphics.VmlGraphics.IE8_MODE_ = goog.global.document &&
112
goog.global.document.documentMode && goog.global.document.documentMode >= 8;
113
114
115
/**
116
* The coordinate multiplier to allow sub-pixel rendering
117
* @type {number}
118
*/
119
goog.graphics.VmlGraphics.COORD_MULTIPLIER = 100;
120
121
122
/**
123
* Converts the given size to a css size. If it is a percentage, leaves it
124
* alone. Otherwise assumes px.
125
*
126
* @param {number|string} size The size to use.
127
* @return {string} The position adjusted for COORD_MULTIPLIER.
128
*/
129
goog.graphics.VmlGraphics.toCssSize = function(size) {
130
return goog.isString(size) && goog.string.endsWith(size, '%') ?
131
size :
132
parseFloat(size.toString()) + 'px';
133
};
134
135
136
/**
137
* Multiplies positioning coordinates by COORD_MULTIPLIER to allow sub-pixel
138
* coordinates. Also adds a half pixel offset to match SVG.
139
*
140
* This function is internal for the VML supporting classes, and
141
* should not be used externally.
142
*
143
* @param {number|string} number A position in pixels.
144
* @return {number} The position adjusted for COORD_MULTIPLIER.
145
*/
146
goog.graphics.VmlGraphics.toPosCoord = function(number) {
147
return Math.round(
148
(parseFloat(number.toString()) - 0.5) *
149
goog.graphics.VmlGraphics.COORD_MULTIPLIER);
150
};
151
152
153
/**
154
* Add a "px" suffix to a number of pixels, and multiplies all coordinates by
155
* COORD_MULTIPLIER to allow sub-pixel coordinates.
156
*
157
* This function is internal for the VML supporting classes, and
158
* should not be used externally.
159
*
160
* @param {number|string} number A position in pixels.
161
* @return {string} The position with suffix 'px'.
162
*/
163
goog.graphics.VmlGraphics.toPosPx = function(number) {
164
return goog.graphics.VmlGraphics.toPosCoord(number) + 'px';
165
};
166
167
168
/**
169
* Multiplies the width or height coordinate by COORD_MULTIPLIER to allow
170
* sub-pixel coordinates.
171
*
172
* This function is internal for the VML supporting classes, and
173
* should not be used externally.
174
*
175
* @param {string|number} number A size in units.
176
* @return {number} The size multiplied by the correct factor.
177
*/
178
goog.graphics.VmlGraphics.toSizeCoord = function(number) {
179
return Math.round(
180
parseFloat(number.toString()) *
181
goog.graphics.VmlGraphics.COORD_MULTIPLIER);
182
};
183
184
185
/**
186
* Add a "px" suffix to a number of pixels, and multiplies all coordinates by
187
* COORD_MULTIPLIER to allow sub-pixel coordinates.
188
*
189
* This function is internal for the VML supporting classes, and
190
* should not be used externally.
191
*
192
* @param {number|string} number A size in pixels.
193
* @return {string} The size with suffix 'px'.
194
*/
195
goog.graphics.VmlGraphics.toSizePx = function(number) {
196
return goog.graphics.VmlGraphics.toSizeCoord(number) + 'px';
197
};
198
199
200
/**
201
* Sets an attribute on the given VML element, in the way best suited to the
202
* current version of IE. Should only be used in the goog.graphics package.
203
* @param {Element} element The element to set an attribute
204
* on.
205
* @param {string} name The name of the attribute to set.
206
* @param {string} value The value to set it to.
207
*/
208
goog.graphics.VmlGraphics.setAttribute = function(element, name, value) {
209
if (goog.graphics.VmlGraphics.IE8_MODE_) {
210
element[name] = value;
211
} else {
212
element.setAttribute(name, value);
213
}
214
};
215
216
217
/**
218
* Event handler.
219
* @type {goog.events.EventHandler}
220
* @private
221
*/
222
goog.graphics.VmlGraphics.prototype.handler_;
223
224
225
/**
226
* Creates a VML element. Used internally and by different VML classes.
227
* @param {string} tagName The type of element to create.
228
* @return {!Element} The created element.
229
*/
230
goog.graphics.VmlGraphics.prototype.createVmlElement = function(tagName) {
231
var element = this.dom_.createElement(
232
goog.graphics.VmlGraphics.VML_PREFIX_ + ':' + tagName);
233
element.id = goog.string.createUniqueString();
234
return element;
235
};
236
237
238
/**
239
* Returns the VML element with the given id that is a child of this graphics
240
* object.
241
* Should be considered package private, and not used externally.
242
* @param {string} id The element id to find.
243
* @return {Element} The element with the given id, or null if none is found.
244
*/
245
goog.graphics.VmlGraphics.prototype.getVmlElement = function(id) {
246
return this.dom_.getElement(id);
247
};
248
249
250
/**
251
* Resets the graphics so they will display properly on IE8. Noop in older
252
* versions.
253
* @private
254
*/
255
goog.graphics.VmlGraphics.prototype.updateGraphics_ = function() {
256
if (goog.graphics.VmlGraphics.IE8_MODE_ && this.isInDocument()) {
257
// There's a risk of mXSS here, as the browser is not guaranteed to
258
// return the HTML that was originally written, when innerHTML is read.
259
// However, given that this a deprecated API and affects only IE, it seems
260
// an acceptable risk.
261
var html = goog.html.uncheckedconversions
262
.safeHtmlFromStringKnownToSatisfyTypeContract(
263
goog.string.Const.from('Assign innerHTML to itself'),
264
this.getElement().innerHTML);
265
goog.dom.safe.setInnerHtml(
266
/** @type {!Element} */ (this.getElement()), html);
267
}
268
};
269
270
271
/**
272
* Appends an element.
273
*
274
* @param {goog.graphics.Element} element The element wrapper.
275
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
276
* to append to. If not specified, appends to the main canvas.
277
* @private
278
*/
279
goog.graphics.VmlGraphics.prototype.append_ = function(element, opt_group) {
280
var parent = opt_group || this.canvasElement;
281
parent.getElement().appendChild(element.getElement());
282
this.updateGraphics_();
283
};
284
285
286
/**
287
* Sets the fill for the given element.
288
* @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
289
* @param {goog.graphics.Fill?} fill The fill object.
290
* @override
291
*/
292
goog.graphics.VmlGraphics.prototype.setElementFill = function(element, fill) {
293
var vmlElement = element.getElement();
294
goog.graphics.VmlGraphics.removeFill_(vmlElement);
295
if (fill instanceof goog.graphics.SolidFill) {
296
// NOTE(arv): VML does not understand 'transparent' so hard code support
297
// for it.
298
if (fill.getColor() == 'transparent') {
299
vmlElement.filled = false;
300
} else if (fill.getOpacity() != 1) {
301
vmlElement.filled = true;
302
// Set opacity (number 0-1 is translated to percent)
303
var fillNode = this.createVmlElement('fill');
304
fillNode.opacity = Math.round(fill.getOpacity() * 100) + '%';
305
fillNode.color = fill.getColor();
306
vmlElement.appendChild(fillNode);
307
} else {
308
vmlElement.filled = true;
309
vmlElement.fillcolor = fill.getColor();
310
}
311
} else if (fill instanceof goog.graphics.LinearGradient) {
312
vmlElement.filled = true;
313
// Add a 'fill' element
314
var gradient = this.createVmlElement('fill');
315
gradient.color = fill.getColor1();
316
gradient.color2 = fill.getColor2();
317
if (goog.isNumber(fill.getOpacity1())) {
318
gradient.opacity = fill.getOpacity1();
319
}
320
if (goog.isNumber(fill.getOpacity2())) {
321
gradient.opacity2 = fill.getOpacity2();
322
}
323
var angle =
324
goog.math.angle(fill.getX1(), fill.getY1(), fill.getX2(), fill.getY2());
325
// Our angles start from 0 to the right, and grow clockwise.
326
// MSIE starts from 0 to top, and grows anti-clockwise.
327
angle = Math.round(goog.math.standardAngle(270 - angle));
328
gradient.angle = angle;
329
gradient.type = 'gradient';
330
vmlElement.appendChild(gradient);
331
} else {
332
vmlElement.filled = false;
333
}
334
this.updateGraphics_();
335
};
336
337
338
/**
339
* Sets the stroke for the given element.
340
* @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
341
* @param {goog.graphics.Stroke?} stroke The stroke object.
342
* @override
343
*/
344
goog.graphics.VmlGraphics.prototype.setElementStroke = function(
345
element, stroke) {
346
var vmlElement = element.getElement();
347
if (stroke) {
348
vmlElement.stroked = true;
349
350
var width = stroke.getWidth();
351
if (goog.isString(width) && width.indexOf('px') == -1) {
352
width = parseFloat(width);
353
} else {
354
width = width * this.getPixelScaleX();
355
}
356
357
var strokeElement = vmlElement.getElementsByTagName('stroke')[0];
358
if (!strokeElement) {
359
strokeElement = strokeElement || this.createVmlElement('stroke');
360
vmlElement.appendChild(strokeElement);
361
}
362
strokeElement.opacity = stroke.getOpacity();
363
strokeElement.weight = width + 'px';
364
strokeElement.color = stroke.getColor();
365
} else {
366
vmlElement.stroked = false;
367
}
368
this.updateGraphics_();
369
};
370
371
372
/**
373
* Set the translation and rotation of an element.
374
*
375
* If a more general affine transform is needed than this provides
376
* (e.g. skew and scale) then use setElementAffineTransform.
377
* @param {goog.graphics.Element} element The element wrapper.
378
* @param {number} x The x coordinate of the translation transform.
379
* @param {number} y The y coordinate of the translation transform.
380
* @param {number} angle The angle of the rotation transform.
381
* @param {number} centerX The horizontal center of the rotation transform.
382
* @param {number} centerY The vertical center of the rotation transform.
383
* @override
384
*/
385
goog.graphics.VmlGraphics.prototype.setElementTransform = function(
386
element, x, y, angle, centerX, centerY) {
387
var el = element.getElement();
388
389
el.style.left = goog.graphics.VmlGraphics.toPosPx(x);
390
el.style.top = goog.graphics.VmlGraphics.toPosPx(y);
391
if (angle || el.rotation) {
392
el.rotation = angle;
393
el.coordsize = goog.graphics.VmlGraphics.toSizeCoord(centerX * 2) + ' ' +
394
goog.graphics.VmlGraphics.toSizeCoord(centerY * 2);
395
}
396
};
397
398
399
/**
400
* Set the transformation of an element.
401
* @param {!goog.graphics.Element} element The element wrapper.
402
* @param {!goog.graphics.AffineTransform} affineTransform The
403
* transformation applied to this element.
404
* @override
405
*/
406
goog.graphics.VmlGraphics.prototype.setElementAffineTransform = function(
407
element, affineTransform) {
408
var t = affineTransform;
409
var vmlElement = element.getElement();
410
goog.graphics.VmlGraphics.removeSkew_(vmlElement);
411
var skewNode = this.createVmlElement('skew');
412
skewNode.on = 'true';
413
// Move the transform origin to 0px,0px of the graphics.
414
// In VML, 0,0 means the center of the element, -0.5,-0.5 left top conner of
415
// it.
416
skewNode.origin =
417
(-vmlElement.style.pixelLeft / vmlElement.style.pixelWidth - 0.5) + ',' +
418
(-vmlElement.style.pixelTop / vmlElement.style.pixelHeight - 0.5);
419
skewNode.offset = t.getTranslateX().toFixed(1) + 'px,' +
420
t.getTranslateY().toFixed(1) + 'px';
421
skewNode.matrix = [
422
t.getScaleX().toFixed(6), t.getShearX().toFixed(6),
423
t.getShearY().toFixed(6), t.getScaleY().toFixed(6), 0, 0
424
].join(',');
425
vmlElement.appendChild(skewNode);
426
this.updateGraphics_();
427
};
428
429
430
/**
431
* Removes the skew information from a dom element.
432
* @param {Element} element DOM element.
433
* @private
434
*/
435
goog.graphics.VmlGraphics.removeSkew_ = function(element) {
436
goog.array.forEach(element.childNodes, function(child) {
437
if (child.tagName == 'skew') {
438
element.removeChild(child);
439
}
440
});
441
};
442
443
444
/**
445
* Removes the fill information from a dom element.
446
* @param {Element} element DOM element.
447
* @private
448
*/
449
goog.graphics.VmlGraphics.removeFill_ = function(element) {
450
element.fillcolor = '';
451
goog.array.forEach(element.childNodes, function(child) {
452
if (child.tagName == 'fill') {
453
element.removeChild(child);
454
}
455
});
456
};
457
458
459
/**
460
* Set top, left, width and height for an element.
461
* This function is internal for the VML supporting classes, and
462
* should not be used externally.
463
*
464
* @param {Element} element DOM element.
465
* @param {number} left Left ccordinate in pixels.
466
* @param {number} top Top ccordinate in pixels.
467
* @param {number} width Width in pixels.
468
* @param {number} height Height in pixels.
469
*/
470
goog.graphics.VmlGraphics.setPositionAndSize = function(
471
element, left, top, width, height) {
472
var style = element.style;
473
style.position = 'absolute';
474
style.left = goog.graphics.VmlGraphics.toPosPx(left);
475
style.top = goog.graphics.VmlGraphics.toPosPx(top);
476
style.width = goog.graphics.VmlGraphics.toSizePx(width);
477
style.height = goog.graphics.VmlGraphics.toSizePx(height);
478
479
if (element.tagName == 'shape') {
480
element.coordsize = goog.graphics.VmlGraphics.toSizeCoord(width) + ' ' +
481
goog.graphics.VmlGraphics.toSizeCoord(height);
482
}
483
};
484
485
486
/**
487
* Creates an element spanning the surface.
488
*
489
* @param {string} type The type of element to create.
490
* @return {!Element} The created, positioned, and sized element.
491
* @private
492
*/
493
goog.graphics.VmlGraphics.prototype.createFullSizeElement_ = function(type) {
494
var element = this.createVmlElement(type);
495
var size = this.getCoordSize();
496
goog.graphics.VmlGraphics.setPositionAndSize(
497
element, 0, 0, size.width, size.height);
498
return element;
499
};
500
501
502
/**
503
* IE magic - if this "no-op" logic is not here, the 'if' statement in createDom
504
* will fail intermittently. The logic is used to prevent the JsCompiler from
505
* stripping this piece of code, which it quite reasonably thinks is doing
506
* nothing. Put it in try-catch block to prevent "Unspecified Error" when
507
* this statement is executed in a defer JS in IE.
508
* More info here:
509
* http://www.mail-archive.com/[email protected]/msg01838.html
510
*/
511
if (goog.userAgent.IE) {
512
try {
513
goog.reflect.sinkValue(document.namespaces);
514
} catch (e) {
515
}
516
}
517
518
519
/**
520
* Creates the DOM representation of the graphics area.
521
* @override
522
*/
523
goog.graphics.VmlGraphics.prototype.createDom = function() {
524
var doc = this.dom_.getDocument();
525
526
// Add the namespace.
527
if (!doc.namespaces[goog.graphics.VmlGraphics.VML_PREFIX_]) {
528
if (goog.graphics.VmlGraphics.IE8_MODE_) {
529
doc.namespaces.add(
530
goog.graphics.VmlGraphics.VML_PREFIX_,
531
goog.graphics.VmlGraphics.VML_NS_,
532
goog.graphics.VmlGraphics.VML_IMPORT_);
533
} else {
534
doc.namespaces.add(
535
goog.graphics.VmlGraphics.VML_PREFIX_,
536
goog.graphics.VmlGraphics.VML_NS_);
537
}
538
539
// We assume that we only need to add the CSS if the namespace was not
540
// present
541
var ss = doc.createStyleSheet();
542
ss.cssText = goog.graphics.VmlGraphics.VML_PREFIX_ + '\\:*' +
543
'{behavior:url(#default#VML)}';
544
}
545
546
// Outer a DIV with overflow hidden for clipping.
547
// All inner elements are absolutely positioned on-top of this div.
548
var pixelWidth = this.width;
549
var pixelHeight = this.height;
550
var divElement = this.dom_.createDom(goog.dom.TagName.DIV, {
551
'style': 'overflow:hidden;position:relative;width:' +
552
goog.graphics.VmlGraphics.toCssSize(pixelWidth) + ';height:' +
553
goog.graphics.VmlGraphics.toCssSize(pixelHeight)
554
});
555
556
this.setElementInternal(divElement);
557
558
var group = this.createVmlElement('group');
559
var style = group.style;
560
561
style.position = 'absolute';
562
style.left = style.top = '0';
563
style.width = this.width;
564
style.height = this.height;
565
if (this.coordWidth) {
566
group.coordsize = goog.graphics.VmlGraphics.toSizeCoord(this.coordWidth) +
567
' ' +
568
goog.graphics.VmlGraphics.toSizeCoord(
569
/** @type {number} */ (this.coordHeight));
570
} else {
571
group.coordsize = goog.graphics.VmlGraphics.toSizeCoord(pixelWidth) + ' ' +
572
goog.graphics.VmlGraphics.toSizeCoord(pixelHeight);
573
}
574
575
if (goog.isDef(this.coordLeft)) {
576
group.coordorigin = goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) +
577
' ' + goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
578
} else {
579
group.coordorigin = '0 0';
580
}
581
divElement.appendChild(group);
582
583
this.canvasElement = new goog.graphics.VmlGroupElement(group, this);
584
585
goog.events.listen(
586
divElement, goog.events.EventType.RESIZE,
587
goog.bind(this.handleContainerResize_, this));
588
};
589
590
591
/**
592
* Changes the canvas element size to match the container element size.
593
* @private
594
*/
595
goog.graphics.VmlGraphics.prototype.handleContainerResize_ = function() {
596
var size = goog.style.getSize(this.getElement());
597
var style = this.canvasElement.getElement().style;
598
599
if (size.width) {
600
style.width = size.width + 'px';
601
style.height = size.height + 'px';
602
} else {
603
var current = this.getElement();
604
while (current && current.currentStyle &&
605
current.currentStyle.display != 'none') {
606
current = current.parentNode;
607
}
608
if (current && current.currentStyle) {
609
this.handler_.listen(
610
current, 'propertychange', this.handleContainerResize_);
611
}
612
}
613
614
this.dispatchEvent(goog.events.EventType.RESIZE);
615
};
616
617
618
/**
619
* Handle property changes on hidden ancestors.
620
* @param {goog.events.BrowserEvent} e The browser event.
621
* @private
622
*/
623
goog.graphics.VmlGraphics.prototype.handlePropertyChange_ = function(e) {
624
var prop = e.getBrowserEvent().propertyName;
625
if (prop == 'display' || prop == 'className') {
626
this.handler_.unlisten(
627
/** @type {Element} */ (e.target), 'propertychange',
628
this.handlePropertyChange_);
629
this.handleContainerResize_();
630
}
631
};
632
633
634
/**
635
* Changes the coordinate system position.
636
* @param {number} left The coordinate system left bound.
637
* @param {number} top The coordinate system top bound.
638
* @override
639
*/
640
goog.graphics.VmlGraphics.prototype.setCoordOrigin = function(left, top) {
641
this.coordLeft = left;
642
this.coordTop = top;
643
644
this.canvasElement.getElement().coordorigin =
645
goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) + ' ' +
646
goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
647
};
648
649
650
/**
651
* Changes the coordinate size.
652
* @param {number} coordWidth The coordinate width.
653
* @param {number} coordHeight The coordinate height.
654
* @override
655
*/
656
goog.graphics.VmlGraphics.prototype.setCoordSize = function(
657
coordWidth, coordHeight) {
658
goog.graphics.VmlGraphics.superClass_.setCoordSize.apply(this, arguments);
659
660
this.canvasElement.getElement().coordsize =
661
goog.graphics.VmlGraphics.toSizeCoord(coordWidth) + ' ' +
662
goog.graphics.VmlGraphics.toSizeCoord(coordHeight);
663
};
664
665
666
/**
667
* Change the size of the canvas.
668
* @param {number} pixelWidth The width in pixels.
669
* @param {number} pixelHeight The height in pixels.
670
* @override
671
*/
672
goog.graphics.VmlGraphics.prototype.setSize = function(
673
pixelWidth, pixelHeight) {
674
goog.style.setSize(this.getElement(), pixelWidth, pixelHeight);
675
};
676
677
678
/**
679
* @return {!goog.math.Size} Returns the number of pixels spanned by the
680
* surface.
681
* @override
682
*/
683
goog.graphics.VmlGraphics.prototype.getPixelSize = function() {
684
var el = this.getElement();
685
// The following relies on the fact that the size can never be 0.
686
return new goog.math.Size(
687
el.style.pixelWidth || el.offsetWidth || 1,
688
el.style.pixelHeight || el.offsetHeight || 1);
689
};
690
691
692
/**
693
* Remove all drawing elements from the graphics.
694
* @override
695
*/
696
goog.graphics.VmlGraphics.prototype.clear = function() {
697
this.canvasElement.clear();
698
};
699
700
701
/**
702
* Draw an ellipse.
703
*
704
* @param {number} cx Center X coordinate.
705
* @param {number} cy Center Y coordinate.
706
* @param {number} rx Radius length for the x-axis.
707
* @param {number} ry Radius length for the y-axis.
708
* @param {goog.graphics.Stroke?} stroke Stroke object describing the
709
* stroke.
710
* @param {goog.graphics.Fill?} fill Fill object describing the fill.
711
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
712
* to append to. If not specified, appends to the main canvas.
713
*
714
* @return {!goog.graphics.EllipseElement} The newly created element.
715
* @override
716
*/
717
goog.graphics.VmlGraphics.prototype.drawEllipse = function(
718
cx, cy, rx, ry, stroke, fill, opt_group) {
719
var element = this.createVmlElement('oval');
720
goog.graphics.VmlGraphics.setPositionAndSize(
721
element, cx - rx, cy - ry, rx * 2, ry * 2);
722
var wrapper = new goog.graphics.VmlEllipseElement(
723
element, this, cx, cy, rx, ry, stroke, fill);
724
this.append_(wrapper, opt_group);
725
return wrapper;
726
};
727
728
729
/**
730
* Draw a rectangle.
731
*
732
* @param {number} x X coordinate (left).
733
* @param {number} y Y coordinate (top).
734
* @param {number} width Width of rectangle.
735
* @param {number} height Height of rectangle.
736
* @param {goog.graphics.Stroke?} stroke Stroke object describing the
737
* stroke.
738
* @param {goog.graphics.Fill?} fill Fill object describing the fill.
739
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
740
* to append to. If not specified, appends to the main canvas.
741
*
742
* @return {!goog.graphics.RectElement} The newly created element.
743
* @override
744
*/
745
goog.graphics.VmlGraphics.prototype.drawRect = function(
746
x, y, width, height, stroke, fill, opt_group) {
747
var element = this.createVmlElement('rect');
748
goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
749
var wrapper = new goog.graphics.VmlRectElement(element, this, stroke, fill);
750
this.append_(wrapper, opt_group);
751
return wrapper;
752
};
753
754
755
/**
756
* Draw an image.
757
*
758
* @param {number} x X coordinate (left).
759
* @param {number} y Y coordinate (top).
760
* @param {number} width Width of image.
761
* @param {number} height Height of image.
762
* @param {string} src Source of the image.
763
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
764
* to append to. If not specified, appends to the main canvas.
765
*
766
* @return {!goog.graphics.ImageElement} The newly created element.
767
*/
768
goog.graphics.VmlGraphics.prototype.drawImage = function(
769
x, y, width, height, src, opt_group) {
770
var element = this.createVmlElement('image');
771
goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
772
goog.graphics.VmlGraphics.setAttribute(element, 'src', src);
773
var wrapper = new goog.graphics.VmlImageElement(element, this);
774
this.append_(wrapper, opt_group);
775
return wrapper;
776
};
777
778
779
/**
780
* Draw a text string vertically centered on a given line.
781
*
782
* @param {string} text The text to draw.
783
* @param {number} x1 X coordinate of start of line.
784
* @param {number} y1 Y coordinate of start of line.
785
* @param {number} x2 X coordinate of end of line.
786
* @param {number} y2 Y coordinate of end of line.
787
* @param {?string} align Horizontal alignment: left (default), center, right.
788
* @param {goog.graphics.Font} font Font describing the font properties.
789
* @param {goog.graphics.Stroke?} stroke Stroke object describing the stroke.
790
* @param {goog.graphics.Fill?} fill Fill object describing the fill.
791
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
792
* to append to. If not specified, appends to the main canvas.
793
*
794
* @return {!goog.graphics.TextElement} The newly created element.
795
* @override
796
*/
797
goog.graphics.VmlGraphics.prototype.drawTextOnLine = function(
798
text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
799
var shape = this.createFullSizeElement_('shape');
800
801
var pathElement = this.createVmlElement('path');
802
var path = 'M' + goog.graphics.VmlGraphics.toPosCoord(x1) + ',' +
803
goog.graphics.VmlGraphics.toPosCoord(y1) + 'L' +
804
goog.graphics.VmlGraphics.toPosCoord(x2) + ',' +
805
goog.graphics.VmlGraphics.toPosCoord(y2) + 'E';
806
goog.graphics.VmlGraphics.setAttribute(pathElement, 'v', path);
807
goog.graphics.VmlGraphics.setAttribute(pathElement, 'textpathok', 'true');
808
809
var textPathElement = this.createVmlElement('textpath');
810
textPathElement.setAttribute('on', 'true');
811
var style = textPathElement.style;
812
style.fontSize = font.size * this.getPixelScaleX();
813
style.fontFamily = font.family;
814
if (align != null) {
815
style['v-text-align'] = align;
816
}
817
if (font.bold) {
818
style.fontWeight = 'bold';
819
}
820
if (font.italic) {
821
style.fontStyle = 'italic';
822
}
823
goog.graphics.VmlGraphics.setAttribute(textPathElement, 'string', text);
824
825
shape.appendChild(pathElement);
826
shape.appendChild(textPathElement);
827
var wrapper = new goog.graphics.VmlTextElement(shape, this, stroke, fill);
828
this.append_(wrapper, opt_group);
829
return wrapper;
830
};
831
832
833
/**
834
* Draw a path.
835
*
836
* @param {!goog.graphics.Path} path The path object to draw.
837
* @param {goog.graphics.Stroke?} stroke Stroke object describing the stroke.
838
* @param {goog.graphics.Fill?} fill Fill object describing the fill.
839
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
840
* to append to. If not specified, appends to the main canvas.
841
*
842
* @return {!goog.graphics.PathElement} The newly created element.
843
* @override
844
*/
845
goog.graphics.VmlGraphics.prototype.drawPath = function(
846
path, stroke, fill, opt_group) {
847
var element = this.createFullSizeElement_('shape');
848
goog.graphics.VmlGraphics.setAttribute(
849
element, 'path', goog.graphics.VmlGraphics.getVmlPath(path));
850
851
var wrapper = new goog.graphics.VmlPathElement(element, this, stroke, fill);
852
this.append_(wrapper, opt_group);
853
return wrapper;
854
};
855
856
857
/**
858
* Returns a string representation of a logical path suitable for use in
859
* a VML element.
860
*
861
* @param {goog.graphics.Path} path The logical path.
862
* @return {string} The VML path representation.
863
* @suppress {deprecated} goog.graphics is deprecated.
864
*/
865
goog.graphics.VmlGraphics.getVmlPath = function(path) {
866
var list = [];
867
path.forEachSegment(function(segment, args) {
868
switch (segment) {
869
case goog.graphics.Path.Segment.MOVETO:
870
list.push('m');
871
Array.prototype.push.apply(
872
list, goog.array.map(args, goog.graphics.VmlGraphics.toSizeCoord));
873
break;
874
case goog.graphics.Path.Segment.LINETO:
875
list.push('l');
876
Array.prototype.push.apply(
877
list, goog.array.map(args, goog.graphics.VmlGraphics.toSizeCoord));
878
break;
879
case goog.graphics.Path.Segment.CURVETO:
880
list.push('c');
881
Array.prototype.push.apply(
882
list, goog.array.map(args, goog.graphics.VmlGraphics.toSizeCoord));
883
break;
884
case goog.graphics.Path.Segment.CLOSE:
885
list.push('x');
886
break;
887
case goog.graphics.Path.Segment.ARCTO:
888
var toAngle = args[2] + args[3];
889
var cx = goog.graphics.VmlGraphics.toSizeCoord(
890
args[4] - goog.math.angleDx(toAngle, args[0]));
891
var cy = goog.graphics.VmlGraphics.toSizeCoord(
892
args[5] - goog.math.angleDy(toAngle, args[1]));
893
var rx = goog.graphics.VmlGraphics.toSizeCoord(args[0]);
894
var ry = goog.graphics.VmlGraphics.toSizeCoord(args[1]);
895
// VML angles are in fd units (see http://www.w3.org/TR/NOTE-VML) and
896
// are positive counter-clockwise.
897
var fromAngle = Math.round(args[2] * -65536);
898
var extent = Math.round(args[3] * -65536);
899
list.push('ae', cx, cy, rx, ry, fromAngle, extent);
900
break;
901
}
902
});
903
return list.join(' ');
904
};
905
906
907
/**
908
* Create an empty group of drawing elements.
909
*
910
* @param {goog.graphics.GroupElement=} opt_group The group wrapper element
911
* to append to. If not specified, appends to the main canvas.
912
*
913
* @return {!goog.graphics.GroupElement} The newly created group.
914
* @override
915
*/
916
goog.graphics.VmlGraphics.prototype.createGroup = function(opt_group) {
917
var element = this.createFullSizeElement_('group');
918
var parent = opt_group || this.canvasElement;
919
parent.getElement().appendChild(element);
920
return new goog.graphics.VmlGroupElement(element, this);
921
};
922
923
924
/**
925
* Measure and return the width (in pixels) of a given text string.
926
* Text measurement is needed to make sure a text can fit in the allocated
927
* area. The way text length is measured is by writing it into a div that is
928
* after the visible area, measure the div width, and immediately erase the
929
* written value.
930
*
931
* @param {string} text The text string to measure.
932
* @param {goog.graphics.Font} font The font object describing the font style.
933
*
934
* @return {number} The width in pixels of the text strings.
935
* @override
936
*/
937
goog.graphics.VmlGraphics.prototype.getTextWidth = function(text, font) {
938
// TODO(arv): Implement
939
return 0;
940
};
941
942
943
/** @override */
944
goog.graphics.VmlGraphics.prototype.enterDocument = function() {
945
goog.graphics.VmlGraphics.superClass_.enterDocument.call(this);
946
this.handleContainerResize_();
947
this.updateGraphics_();
948
};
949
950
951
/**
952
* Disposes of the component by removing event handlers, detacing DOM nodes from
953
* the document body, and removing references to them.
954
* @override
955
* @protected
956
*/
957
goog.graphics.VmlGraphics.prototype.disposeInternal = function() {
958
this.canvasElement = null;
959
goog.graphics.VmlGraphics.superClass_.disposeInternal.call(this);
960
};
961
962