outfielding-jqplot-rails 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +8 -4
- data/changes-jqplot.txt +48 -37
- data/copyright-jqplot.txt +17 -17
- data/lib/outfielding-jqplot-rails/version.rb +1 -1
- data/vendor/assets/javascripts/excanvas.js +1438 -1438
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.BezierCurveRenderer.js +313 -313
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.barRenderer.js +801 -801
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.blockRenderer.js +234 -234
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.bubbleRenderer.js +758 -758
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisLabelRenderer.js +202 -202
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasAxisTickRenderer.js +252 -252
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasOverlay.js +1020 -1020
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.canvasTextRenderer.js +448 -448
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.categoryAxisRenderer.js +679 -679
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.ciParser.js +115 -115
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.cursor.js +1108 -1108
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.dateAxisRenderer.js +741 -741
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.donutRenderer.js +816 -805
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.dragable.js +224 -224
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedLegendRenderer.js +305 -305
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.enhancedPieLegendRenderer.js +261 -0
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.funnelRenderer.js +942 -942
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.highlighter.js +464 -464
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.json2.js +475 -475
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.logAxisRenderer.js +533 -533
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoAxisRenderer.js +611 -611
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.mekkoRenderer.js +437 -437
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.meterGaugeRenderer.js +1029 -1029
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.mobile.js +2 -2
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.ohlcRenderer.js +373 -373
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.pieRenderer.js +945 -903
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.pointLabels.js +379 -377
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidAxisRenderer.js +728 -728
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidGridRenderer.js +428 -428
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.pyramidRenderer.js +513 -513
- data/vendor/assets/javascripts/jqplot-plugins/jqplot.trendline.js +222 -222
- data/vendor/assets/javascripts/jquery.jqplot.js +11477 -11411
- data/vendor/assets/stylesheets/jquery.jqplot.css +259 -259
- metadata +9 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d8c0d787e7240d5724f1991fb886e70192f11fd
|
4
|
+
data.tar.gz: cfd7a5fe84574f8e41ab3950edd6a1746902c0a3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3d6a4c58b923d3a6e6826364f6f9cd63817768bb4f73f770de0c60850d34d50e6437e0d70d6dbae30faf71b4d61a97939a5be618252eaa639f35829931754606
|
7
|
+
data.tar.gz: 58b4437bc96259cd964c3caee0c011616e8d8573c7173c1b817c6960be142306f810941d83fbd47b1cd8041060a9210364190d2c1083b0285e69a74966072ce8
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
2017-02-26 Jason Young <jay@outfielding.net>
|
2
|
+
|
3
|
+
* Includes jqplot 1.0.9 (d96a669)
|
4
|
+
|
1
5
|
2013-03-30 Jason Young <jay@outfielding.net>
|
2
|
-
|
6
|
+
|
3
7
|
* Includes jqplot 1.0.8 (r1250)
|
4
8
|
|
5
9
|
2013-02-27 Jason Young <jay@outfielding.net>
|
6
|
-
|
10
|
+
|
7
11
|
* Includes jqplot 1.0.7 (r1224)
|
8
12
|
* adds in the changes.txt (and copyright.txt and updates the README.txt) from jqplot 1.0.7
|
9
13
|
|
@@ -14,5 +18,5 @@
|
|
14
18
|
* drops the release revision from the versioning (at least for now)
|
15
19
|
|
16
20
|
2012-11-04 Jason Young <jay@outfielding.net>
|
17
|
-
|
18
|
-
* Initial release (includes jqplot 1.0.4r1121)
|
21
|
+
|
22
|
+
* Initial release (includes jqplot 1.0.4r1121)
|
data/changes-jqplot.txt
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
Title: Change Log
|
2
2
|
|
3
|
+
1.0.9:
|
4
|
+
* Convert toolchain to grunt
|
5
|
+
* Add "step" chart style
|
6
|
+
* Refactor code according to JSLint rules (johanbove)
|
7
|
+
* Add enhancedPieLegendRenderer
|
8
|
+
* Pull request #17: Fix infinite loop
|
9
|
+
* Pull request #22: Update jqplot.pointLabels.js
|
10
|
+
* Pull request #23 Update jqplot.pieRenderer.js
|
11
|
+
* Pull request #25: barRenderer resizing fix
|
12
|
+
* Pull request #26: Error resizing horizontal bar charts
|
13
|
+
|
3
14
|
1.0.8:
|
4
15
|
* Issue #375: sortMergedLabels does not sort string labels
|
5
16
|
* Issue #279: Groups > 3 Causes Alignment Issues
|
@@ -12,8 +23,8 @@ Title: Change Log
|
|
12
23
|
* Issue #756: jqplot.min files contain non-UTF-8 characters
|
13
24
|
* Issue #223: fillToZero does not color negative values when crossover point is 0
|
14
25
|
* Pull Request #23: Adding rectangles to Canvas Overlay plugin
|
15
|
-
* Pull Request #28: Cross-over points of 0 will actually change colors
|
16
|
-
* Pull Request #35: Don't highlight hidden bars or show tooltips for them
|
26
|
+
* Pull Request #28: Cross-over points of 0 will actually change colors
|
27
|
+
* Pull Request #35: Don't highlight hidden bars or show tooltips for them
|
17
28
|
* Pull Request #41: Add dutch(nl) and svenska(sv) translations for dates
|
18
29
|
* Add tooltip support for Pie Charts
|
19
30
|
* Update to latest YUI compressor
|
@@ -65,7 +76,7 @@ Title: Change Log
|
|
65
76
|
|
66
77
|
1.0.0b2:
|
67
78
|
* Major improvements in memory usage:
|
68
|
-
** Merged in changes from Timo Besenruether to reuse canvas elements and improve
|
79
|
+
** Merged in changes from Timo Besenruether to reuse canvas elements and improve
|
69
80
|
memory performance.
|
70
81
|
** Fixed all identifiable DOM leaks.
|
71
82
|
** Mergged in changes from cguillot for memory improvements in IE < 9.
|
@@ -73,16 +84,16 @@ Title: Change Log
|
|
73
84
|
* Fixed bug where initially hidden plots would not display.
|
74
85
|
* Fixed bug with point labels and null data points.
|
75
86
|
* Updated to jQuery 1.6.1.
|
76
|
-
* Improved pie slice margin calculation and fixed slice margin and pie positioning
|
87
|
+
* Improved pie slice margin calculation and fixed slice margin and pie positioning
|
77
88
|
with small slices.
|
78
89
|
* Improved bar renderer so bars always start at 0 if:
|
79
90
|
** The axis is a linear axis (not log/date).
|
80
91
|
** There are no other line types besides bars attached to the axis.
|
81
92
|
** The data on the axis is all >= 0.
|
82
93
|
** The user has not specified a pad, padMin or forceTickAt0 = true option.
|
83
|
-
* Modified tick prefix behavious so prefix no added to all ticks, even if format
|
94
|
+
* Modified tick prefix behavious so prefix no added to all ticks, even if format
|
84
95
|
string is specified.
|
85
|
-
* Fix to ensure original tick formats are applied when zooming and resetting
|
96
|
+
* Fix to ensure original tick formats are applied when zooming and resetting
|
86
97
|
zoom.
|
87
98
|
* Updated auto tick format string so format adjusted when zooming.
|
88
99
|
* Modified auto tick computation to put less ticks on small plots and more
|
@@ -90,12 +101,12 @@ Title: Change Log
|
|
90
101
|
* Update bubble render to support gradients in IE 9.
|
91
102
|
|
92
103
|
1.0.0b1:
|
93
|
-
* Much improved tick generation algorithm to get precise rounded
|
104
|
+
* Much improved tick generation algorithm to get precise rounded
|
94
105
|
tick values (Thanks Scott Prahl!).
|
95
106
|
* Auto compute tick format string if none is provided.
|
96
107
|
* Much better "slicing" of pie charts when using "sliceMargin" option to set
|
97
108
|
a gap between the slices.
|
98
|
-
* Expanded canvasOverlay plugin to create arbitrary dashed and solid
|
109
|
+
* Expanded canvasOverlay plugin to create arbitrary dashed and solid
|
99
110
|
horizontal and vertical lines on top of plot.
|
100
111
|
* Added defaultColors and defaultNegativeColors options to $.jqplot.config.
|
101
112
|
* Fixed issue #318, highlighter & bar renderer incompatability.
|
@@ -203,23 +214,23 @@ Title: Change Log
|
|
203
214
|
* Implemented vertical waterfall charts. Can create waterfall plot as
|
204
215
|
option to bar chart. See examples folder of distribution.
|
205
216
|
* Enhanced plot labels for waterfall style.
|
206
|
-
* Enhanced bar plots so you can now color each bar of a series
|
217
|
+
* Enhanced bar plots so you can now color each bar of a series
|
207
218
|
independently with the "varyBarColor" option.
|
208
219
|
* Re-factored series drawing so that each series and series shadow drawn
|
209
220
|
on its own canvas. Allows series to be redrawn independently of each other.
|
210
221
|
* Added additional default series colors.
|
211
|
-
* Added useNegativeColors option to turn off negative color array and use
|
222
|
+
* Added useNegativeColors option to turn off negative color array and use
|
212
223
|
only seriesColors array to define all bar/filled line colors.
|
213
224
|
* Fix css for cursor legend.
|
214
225
|
* Modified shape renderer so rectangles can be stroked and filled.
|
215
|
-
* Re-factored date methods out of dateAxisRenderer so that date formatter
|
226
|
+
* Re-factored date methods out of dateAxisRenderer so that date formatter
|
216
227
|
and methods can be accesses outside of dateAxisRenderer plugin.
|
217
228
|
* Fixed #132, now trigger series change event on plot target instead of drag canvas.
|
218
|
-
* Fixes issue #116 where some source files had mix of tabs and spaces
|
229
|
+
* Fixes issue #116 where some source files had mix of tabs and spaces
|
219
230
|
for indentation. Should have been all spaces.
|
220
231
|
* Fixed issue #126, some links broken in docs section of web site.
|
221
232
|
* Fixed issue #90, trendline plugin incompatibility with pie renderer.
|
222
|
-
* Updated samples in examples folder of distribution to include navigation
|
233
|
+
* Updated samples in examples folder of distribution to include navigation
|
223
234
|
links if web server is set up to process .html files with php.
|
224
235
|
|
225
236
|
|
@@ -253,7 +264,7 @@ Title: Change Log
|
|
253
264
|
|
254
265
|
0.9.5:
|
255
266
|
|
256
|
-
* Implemented "zoomProxy". zoomProxy allows zooming one plot from another
|
267
|
+
* Implemented "zoomProxy". zoomProxy allows zooming one plot from another
|
257
268
|
such as an overview plot.
|
258
269
|
* Zooming can now be constrained to just x or y axis.
|
259
270
|
* Enhanced cursor plugin with vertical "dataTracking" line. This is a line
|
@@ -284,7 +295,7 @@ Title: Change Log
|
|
284
295
|
|
285
296
|
0.9.4:
|
286
297
|
|
287
|
-
* Implemented axis labels. Labels can be rendered in div tags or as canvas
|
298
|
+
* Implemented axis labels. Labels can be rendered in div tags or as canvas
|
288
299
|
elements supporting rotated text.
|
289
300
|
* Improved rotated axis label positioning so labels will start or end at a
|
290
301
|
tick position.
|
@@ -295,7 +306,7 @@ Title: Change Log
|
|
295
306
|
* Added option to legend to encode special HTML characters.
|
296
307
|
* Fixed undesirable behavior where point labels for points off the plot
|
297
308
|
were being rendered.
|
298
|
-
* Added edgeTolerance option to point label renderer to control rendering of
|
309
|
+
* Added edgeTolerance option to point label renderer to control rendering of
|
299
310
|
labels near plot edges.
|
300
311
|
|
301
312
|
|
@@ -303,9 +314,9 @@ Title: Change Log
|
|
303
314
|
|
304
315
|
* Preliminary support for axis labels. Currently rendered into DIV tags,
|
305
316
|
so no rotated label support. This feature is currently experimental.
|
306
|
-
* Fixed bug #52, needed space in tick div tag between style and class declarations
|
317
|
+
* Fixed bug #52, needed space in tick div tag between style and class declarations
|
307
318
|
or plot failed in certain application doctypes.
|
308
|
-
* Fixed issue #54, miter style line join for chart lines causing spikes at steep
|
319
|
+
* Fixed issue #54, miter style line join for chart lines causing spikes at steep
|
309
320
|
changes in slope. Changed miter style to round.
|
310
321
|
* Added examples for new autoscaling algorithm.
|
311
322
|
* Fixed bug #57, category axis labels disappear on redraw()
|
@@ -318,7 +329,7 @@ Title: Change Log
|
|
318
329
|
0.9.2:
|
319
330
|
|
320
331
|
* Fixed bug #45 where a plot could crash if series had different numbers of points.
|
321
|
-
* Fixed issue #50, added option to turn off sorting of series data.
|
332
|
+
* Fixed issue #50, added option to turn off sorting of series data.
|
322
333
|
* Fixed issue #31, implemented a better axis autoscaling algorithm and added an autoscale option.
|
323
334
|
|
324
335
|
0.9.1:
|
@@ -345,7 +356,7 @@ Title: Change Log
|
|
345
356
|
* Added zooming ability with double click or single click options to reset zoom.
|
346
357
|
* Modified default tick spacing algorithm for date axes to give more space to ticks.
|
347
358
|
* Fixed bug #2 where tickInterval wasn't working properly.
|
348
|
-
* Added neighborThreshold option to control how close mouse must be to
|
359
|
+
* Added neighborThreshold option to control how close mouse must be to
|
349
360
|
point to trigger neighbor detection.
|
350
361
|
* Added double click event handler on plot.
|
351
362
|
|
@@ -354,9 +365,9 @@ Title: Change Log
|
|
354
365
|
* Support for up to 9 y axes.
|
355
366
|
* Added option to control padding at max/min bounds of axes separately.
|
356
367
|
* Closed issue #21, added options to control grid line color and width.
|
357
|
-
* Closed issue #20, added options to filled line charts to stoke above
|
368
|
+
* Closed issue #20, added options to filled line charts to stoke above
|
358
369
|
fill and customize fill color and transparency.
|
359
|
-
* Improved structure of on line documentation to make usage and options
|
370
|
+
* Improved structure of on line documentation to make usage and options
|
360
371
|
docs default.
|
361
372
|
* Added much documentation on options and css styling.
|
362
373
|
|
@@ -364,25 +375,25 @@ Title: Change Log
|
|
364
375
|
|
365
376
|
* Bug fix release
|
366
377
|
* Fixed bug #6, missing semi-colons messing up some javascript compressors.
|
367
|
-
* Fixed bug #13 where 2D ticks array of [values, labels] would fail to
|
378
|
+
* Fixed bug #13 where 2D ticks array of [values, labels] would fail to
|
368
379
|
renderer with DateAxisRenderer.
|
369
|
-
* Fixes bug #16 where pie renderer overwriting options for all plot types
|
380
|
+
* Fixes bug #16 where pie renderer overwriting options for all plot types
|
370
381
|
and crashing non pie plots.
|
371
|
-
* Fixes bug #17 constrainTo dragable option mispelled as "contstrainTo".
|
382
|
+
* Fixes bug #17 constrainTo dragable option mispelled as "contstrainTo".
|
372
383
|
Fixed dragable color issue when used with trend lines.
|
373
384
|
|
374
385
|
0.7.0:
|
375
386
|
|
376
387
|
* Pie chart support
|
377
|
-
* Enabled tooltipLocation option in highlighter.
|
378
|
-
* Highlighter Tooltip will account for mark size and highlight size when
|
379
|
-
positioning itself.
|
388
|
+
* Enabled tooltipLocation option in highlighter.
|
389
|
+
* Highlighter Tooltip will account for mark size and highlight size when
|
390
|
+
positioning itself.
|
380
391
|
* Added ability to show just x, y or both axes in highlighter tooltip.
|
381
392
|
* Added customization of separator between axes values in highlighter tooltip.
|
382
|
-
* Modified how shadows are drawn for lines, bars and markers. Now drawn first,
|
393
|
+
* Modified how shadows are drawn for lines, bars and markers. Now drawn first,
|
383
394
|
so they are always behind the object.
|
384
395
|
* Adjustments to shadow parameters on lines to account for new shadow positioning.
|
385
|
-
* Added a ColorGenerator class to robustly return next available color
|
396
|
+
* Added a ColorGenerator class to robustly return next available color
|
386
397
|
for a plot with wrap around to first color at end.
|
387
398
|
* Udates to docs about css file.
|
388
399
|
* Fixed bug with String x values in series and IE error on sorting (Category Axis).
|
@@ -391,35 +402,35 @@ Title: Change Log
|
|
391
402
|
0.6.6b:
|
392
403
|
|
393
404
|
* Added excanvas.js and excanvas.min.js to compressed distributions.
|
394
|
-
* Added example/test html pages I had locally into repository and to
|
405
|
+
* Added example/test html pages I had locally into repository and to
|
395
406
|
compressed distributions.
|
396
407
|
|
397
408
|
0.6.6a:
|
398
409
|
|
399
410
|
* Removed absolute positioning from dom element and put back into css file.
|
400
|
-
* Duplicate of 0.6.6 with a suffix to unambiguously differentiate between
|
411
|
+
* Duplicate of 0.6.6 with a suffix to unambiguously differentiate between
|
401
412
|
previously posted 0.6.6 release.
|
402
413
|
|
403
414
|
0.6.6:
|
404
415
|
|
405
416
|
* Fixed bug #5, trend line plugin failing when no trend line options specified.
|
406
417
|
* Added absolute position css spec to axis tick dom element.
|
407
|
-
* Enhancement to category axes, more intuitive handling of series with
|
418
|
+
* Enhancement to category axes, more intuitive handling of series with
|
408
419
|
missing data values.
|
409
420
|
|
410
421
|
0.6.5:
|
411
422
|
|
412
|
-
* Fixed bug #4, series of unequal data length not rendering correctly.
|
423
|
+
* Fixed bug #4, series of unequal data length not rendering correctly.
|
413
424
|
This is a bugfix release only.
|
414
425
|
|
415
426
|
0.6.4:
|
416
427
|
|
417
|
-
* Fixed bug (issue #1 in tracker) where flat line data series (all x and/or y
|
428
|
+
* Fixed bug (issue #1 in tracker) where flat line data series (all x and/or y
|
418
429
|
values are euqal) or single value data series would crash.
|
419
430
|
|
420
431
|
0.6.3:
|
421
432
|
|
422
|
-
* Support for stacked line (a.k.a. area) and stacked bar (horizontal and
|
433
|
+
* Support for stacked line (a.k.a. area) and stacked bar (horizontal and
|
423
434
|
vertical) charts.
|
424
435
|
* Refactored barRenderer to use default shape and shadow renderers.
|
425
436
|
* Added info (contacts & support information) page to web site.
|
@@ -446,7 +457,7 @@ Title: Change Log
|
|
446
457
|
|
447
458
|
0.6.0:
|
448
459
|
|
449
|
-
* Added rotated text support. Uses native canvas text functionality in
|
460
|
+
* Added rotated text support. Uses native canvas text functionality in
|
450
461
|
browsers that support it or draws text on canvas with Hershey font
|
451
462
|
* metrics for non-supporting browsers.
|
452
463
|
* Removed lots of lint in js code.
|
data/copyright-jqplot.txt
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
*
|
5
5
|
* Version: @VERSION
|
6
6
|
*
|
7
|
-
* Copyright (c) 2009-
|
8
|
-
* jqPlot is currently available for use in all personal or commercial projects
|
9
|
-
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
10
|
-
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
11
|
-
* choose the license that best suits your project and use it accordingly.
|
12
|
-
*
|
13
|
-
* Although not required, the author would appreciate an email letting him
|
14
|
-
* know of any substantial use of jqPlot. You can reach the author at:
|
7
|
+
* Copyright (c) 2009-2015 Chris Leonello
|
8
|
+
* jqPlot is currently available for use in all personal or commercial projects
|
9
|
+
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
10
|
+
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
11
|
+
* choose the license that best suits your project and use it accordingly.
|
12
|
+
*
|
13
|
+
* Although not required, the author would appreciate an email letting him
|
14
|
+
* know of any substantial use of jqPlot. You can reach the author at:
|
15
15
|
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
16
16
|
*
|
17
17
|
* If you are feeling kind and generous, consider supporting the project by
|
@@ -28,20 +28,20 @@
|
|
28
28
|
*
|
29
29
|
* included jsDate library by Chris Leonello:
|
30
30
|
*
|
31
|
-
* Copyright (c) 2010-
|
31
|
+
* Copyright (c) 2010-2015 Chris Leonello
|
32
32
|
*
|
33
|
-
* jsDate is currently available for use in all personal or commercial projects
|
34
|
-
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
33
|
+
* jsDate is currently available for use in all personal or commercial projects
|
34
|
+
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
35
35
|
* choose the license that best suits your project and use it accordingly.
|
36
36
|
*
|
37
|
-
* jsDate borrows many concepts and ideas from the Date Instance
|
37
|
+
* jsDate borrows many concepts and ideas from the Date Instance
|
38
38
|
* Methods by Ken Snyder along with some parts of Ken's actual code.
|
39
|
-
*
|
39
|
+
*
|
40
40
|
* Ken's origianl Date Instance Methods and copyright notice:
|
41
|
-
*
|
41
|
+
*
|
42
42
|
* Ken Snyder (ken d snyder at gmail dot com)
|
43
43
|
* 2008-09-10
|
44
|
-
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
44
|
+
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
45
45
|
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
46
46
|
*
|
47
47
|
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
|
@@ -51,6 +51,6 @@
|
|
51
51
|
* Larry's original code can be found here:
|
52
52
|
*
|
53
53
|
* https://github.com/lsiden/export-jqplot-to-png
|
54
|
-
*
|
55
|
-
*
|
54
|
+
*
|
55
|
+
*
|
56
56
|
*/
|
@@ -1,1438 +1,1438 @@
|
|
1
|
-
// Memory Leaks patch from http://explorercanvas.googlecode.com/svn/trunk/
|
2
|
-
// svn : r73
|
3
|
-
// ------------------------------------------------------------------
|
4
|
-
// Copyright 2006 Google Inc.
|
5
|
-
//
|
6
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
// you may not use this file except in compliance with the License.
|
8
|
-
// You may obtain a copy of the License at
|
9
|
-
//
|
10
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
//
|
12
|
-
// Unless required by applicable law or agreed to in writing, software
|
13
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
// See the License for the specific language governing permissions and
|
16
|
-
// limitations under the License.
|
17
|
-
|
18
|
-
|
19
|
-
// Known Issues:
|
20
|
-
//
|
21
|
-
// * Patterns only support repeat.
|
22
|
-
// * Radial gradient are not implemented. The VML version of these look very
|
23
|
-
// different from the canvas one.
|
24
|
-
// * Clipping paths are not implemented.
|
25
|
-
// * Coordsize. The width and height attribute have higher priority than the
|
26
|
-
// width and height style values which isn't correct.
|
27
|
-
// * Painting mode isn't implemented.
|
28
|
-
// * Canvas width/height should is using content-box by default. IE in
|
29
|
-
// Quirks mode will draw the canvas using border-box. Either change your
|
30
|
-
// doctype to HTML5
|
31
|
-
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
|
32
|
-
// or use Box Sizing Behavior from WebFX
|
33
|
-
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
|
34
|
-
// * Non uniform scaling does not correctly scale strokes.
|
35
|
-
// * Optimize. There is always room for speed improvements.
|
36
|
-
|
37
|
-
// Only add this code if we do not already have a canvas implementation
|
38
|
-
if (!document.createElement('canvas').getContext) {
|
39
|
-
|
40
|
-
(function() {
|
41
|
-
|
42
|
-
// alias some functions to make (compiled) code shorter
|
43
|
-
var m = Math;
|
44
|
-
var mr = m.round;
|
45
|
-
var ms = m.sin;
|
46
|
-
var mc = m.cos;
|
47
|
-
var abs = m.abs;
|
48
|
-
var sqrt = m.sqrt;
|
49
|
-
|
50
|
-
// this is used for sub pixel precision
|
51
|
-
var Z = 10;
|
52
|
-
var Z2 = Z / 2;
|
53
|
-
|
54
|
-
var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
|
55
|
-
|
56
|
-
/**
|
57
|
-
* This funtion is assigned to the <canvas> elements as element.getContext().
|
58
|
-
* @this {HTMLElement}
|
59
|
-
* @return {CanvasRenderingContext2D_}
|
60
|
-
*/
|
61
|
-
function getContext() {
|
62
|
-
return this.context_ ||
|
63
|
-
(this.context_ = new CanvasRenderingContext2D_(this));
|
64
|
-
}
|
65
|
-
|
66
|
-
var slice = Array.prototype.slice;
|
67
|
-
|
68
|
-
/**
|
69
|
-
* Binds a function to an object. The returned function will always use the
|
70
|
-
* passed in {@code obj} as {@code this}.
|
71
|
-
*
|
72
|
-
* Example:
|
73
|
-
*
|
74
|
-
* g = bind(f, obj, a, b)
|
75
|
-
* g(c, d) // will do f.call(obj, a, b, c, d)
|
76
|
-
*
|
77
|
-
* @param {Function} f The function to bind the object to
|
78
|
-
* @param {Object} obj The object that should act as this when the function
|
79
|
-
* is called
|
80
|
-
* @param {*} var_args Rest arguments that will be used as the initial
|
81
|
-
* arguments when the function is called
|
82
|
-
* @return {Function} A new function that has bound this
|
83
|
-
*/
|
84
|
-
function bind(f, obj, var_args) {
|
85
|
-
var a = slice.call(arguments, 2);
|
86
|
-
return function() {
|
87
|
-
return f.apply(obj, a.concat(slice.call(arguments)));
|
88
|
-
};
|
89
|
-
}
|
90
|
-
|
91
|
-
function encodeHtmlAttribute(s) {
|
92
|
-
return String(s).replace(/&/g, '&').replace(/"/g, '"');
|
93
|
-
}
|
94
|
-
|
95
|
-
function addNamespace(doc, prefix, urn) {
|
96
|
-
if (!doc.namespaces[prefix]) {
|
97
|
-
doc.namespaces.add(prefix, urn, '#default#VML');
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
function addNamespacesAndStylesheet(doc) {
|
102
|
-
addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
|
103
|
-
addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
|
104
|
-
|
105
|
-
// Setup default CSS. Only add one style sheet per document
|
106
|
-
if (!doc.styleSheets['ex_canvas_']) {
|
107
|
-
var ss = doc.createStyleSheet();
|
108
|
-
ss.owningElement.id = 'ex_canvas_';
|
109
|
-
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
|
110
|
-
// default size is 300x150 in Gecko and Opera
|
111
|
-
'text-align:left;width:300px;height:150px}';
|
112
|
-
}
|
113
|
-
}
|
114
|
-
|
115
|
-
// Add namespaces and stylesheet at startup.
|
116
|
-
addNamespacesAndStylesheet(document);
|
117
|
-
|
118
|
-
var G_vmlCanvasManager_ = {
|
119
|
-
init: function(opt_doc) {
|
120
|
-
var doc = opt_doc || document;
|
121
|
-
// Create a dummy element so that IE will allow canvas elements to be
|
122
|
-
// recognized.
|
123
|
-
doc.createElement('canvas');
|
124
|
-
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
|
125
|
-
},
|
126
|
-
|
127
|
-
init_: function(doc) {
|
128
|
-
// find all canvas elements
|
129
|
-
var els = doc.getElementsByTagName('canvas');
|
130
|
-
for (var i = 0; i < els.length; i++) {
|
131
|
-
this.initElement(els[i]);
|
132
|
-
}
|
133
|
-
},
|
134
|
-
|
135
|
-
/**
|
136
|
-
* Public initializes a canvas element so that it can be used as canvas
|
137
|
-
* element from now on. This is called automatically before the page is
|
138
|
-
* loaded but if you are creating elements using createElement you need to
|
139
|
-
* make sure this is called on the element.
|
140
|
-
* @param {HTMLElement} el The canvas element to initialize.
|
141
|
-
* @return {HTMLElement} the element that was created.
|
142
|
-
*/
|
143
|
-
initElement: function(el) {
|
144
|
-
if (!el.getContext) {
|
145
|
-
el.getContext = getContext;
|
146
|
-
|
147
|
-
// Add namespaces and stylesheet to document of the element.
|
148
|
-
addNamespacesAndStylesheet(el.ownerDocument);
|
149
|
-
|
150
|
-
// Remove fallback content. There is no way to hide text nodes so we
|
151
|
-
// just remove all childNodes. We could hide all elements and remove
|
152
|
-
// text nodes but who really cares about the fallback content.
|
153
|
-
el.innerHTML = '';
|
154
|
-
|
155
|
-
// do not use inline function because that will leak memory
|
156
|
-
el.attachEvent('onpropertychange', onPropertyChange);
|
157
|
-
el.attachEvent('onresize', onResize);
|
158
|
-
|
159
|
-
var attrs = el.attributes;
|
160
|
-
if (attrs.width && attrs.width.specified) {
|
161
|
-
// TODO: use runtimeStyle and coordsize
|
162
|
-
// el.getContext().setWidth_(attrs.width.nodeValue);
|
163
|
-
el.style.width = attrs.width.nodeValue + 'px';
|
164
|
-
} else {
|
165
|
-
el.width = el.clientWidth;
|
166
|
-
}
|
167
|
-
if (attrs.height && attrs.height.specified) {
|
168
|
-
// TODO: use runtimeStyle and coordsize
|
169
|
-
// el.getContext().setHeight_(attrs.height.nodeValue);
|
170
|
-
el.style.height = attrs.height.nodeValue + 'px';
|
171
|
-
} else {
|
172
|
-
el.height = el.clientHeight;
|
173
|
-
}
|
174
|
-
//el.getContext().setCoordsize_()
|
175
|
-
}
|
176
|
-
return el;
|
177
|
-
},
|
178
|
-
|
179
|
-
// Memory Leaks patch : see http://code.google.com/p/explorercanvas/issues/detail?id=82
|
180
|
-
uninitElement: function(el){
|
181
|
-
if (el.getContext) {
|
182
|
-
var ctx = el.getContext();
|
183
|
-
delete ctx.element_;
|
184
|
-
delete ctx.canvas;
|
185
|
-
el.innerHTML = "";
|
186
|
-
//el.outerHTML = "";
|
187
|
-
el.context_ = null;
|
188
|
-
el.getContext = null;
|
189
|
-
el.detachEvent("onpropertychange", onPropertyChange);
|
190
|
-
el.detachEvent("onresize", onResize);
|
191
|
-
}
|
192
|
-
}
|
193
|
-
};
|
194
|
-
|
195
|
-
function onPropertyChange(e) {
|
196
|
-
var el = e.srcElement;
|
197
|
-
|
198
|
-
switch (e.propertyName) {
|
199
|
-
case 'width':
|
200
|
-
el.getContext().clearRect();
|
201
|
-
el.style.width = el.attributes.width.nodeValue + 'px';
|
202
|
-
// In IE8 this does not trigger onresize.
|
203
|
-
el.firstChild.style.width = el.clientWidth + 'px';
|
204
|
-
break;
|
205
|
-
case 'height':
|
206
|
-
el.getContext().clearRect();
|
207
|
-
el.style.height = el.attributes.height.nodeValue + 'px';
|
208
|
-
el.firstChild.style.height = el.clientHeight + 'px';
|
209
|
-
break;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
|
213
|
-
function onResize(e) {
|
214
|
-
var el = e.srcElement;
|
215
|
-
if (el.firstChild) {
|
216
|
-
el.firstChild.style.width = el.clientWidth + 'px';
|
217
|
-
el.firstChild.style.height = el.clientHeight + 'px';
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
|
-
G_vmlCanvasManager_.init();
|
222
|
-
|
223
|
-
// precompute "00" to "FF"
|
224
|
-
var decToHex = [];
|
225
|
-
for (var i = 0; i < 16; i++) {
|
226
|
-
for (var j = 0; j < 16; j++) {
|
227
|
-
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
|
228
|
-
}
|
229
|
-
}
|
230
|
-
|
231
|
-
function createMatrixIdentity() {
|
232
|
-
return [
|
233
|
-
[1, 0, 0],
|
234
|
-
[0, 1, 0],
|
235
|
-
[0, 0, 1]
|
236
|
-
];
|
237
|
-
}
|
238
|
-
|
239
|
-
function matrixMultiply(m1, m2) {
|
240
|
-
var result = createMatrixIdentity();
|
241
|
-
|
242
|
-
for (var x = 0; x < 3; x++) {
|
243
|
-
for (var y = 0; y < 3; y++) {
|
244
|
-
var sum = 0;
|
245
|
-
|
246
|
-
for (var z = 0; z < 3; z++) {
|
247
|
-
sum += m1[x][z] * m2[z][y];
|
248
|
-
}
|
249
|
-
|
250
|
-
result[x][y] = sum;
|
251
|
-
}
|
252
|
-
}
|
253
|
-
return result;
|
254
|
-
}
|
255
|
-
|
256
|
-
function copyState(o1, o2) {
|
257
|
-
o2.fillStyle = o1.fillStyle;
|
258
|
-
o2.lineCap = o1.lineCap;
|
259
|
-
o2.lineJoin = o1.lineJoin;
|
260
|
-
o2.lineWidth = o1.lineWidth;
|
261
|
-
o2.miterLimit = o1.miterLimit;
|
262
|
-
o2.shadowBlur = o1.shadowBlur;
|
263
|
-
o2.shadowColor = o1.shadowColor;
|
264
|
-
o2.shadowOffsetX = o1.shadowOffsetX;
|
265
|
-
o2.shadowOffsetY = o1.shadowOffsetY;
|
266
|
-
o2.strokeStyle = o1.strokeStyle;
|
267
|
-
o2.globalAlpha = o1.globalAlpha;
|
268
|
-
o2.font = o1.font;
|
269
|
-
o2.textAlign = o1.textAlign;
|
270
|
-
o2.textBaseline = o1.textBaseline;
|
271
|
-
o2.arcScaleX_ = o1.arcScaleX_;
|
272
|
-
o2.arcScaleY_ = o1.arcScaleY_;
|
273
|
-
o2.lineScale_ = o1.lineScale_;
|
274
|
-
}
|
275
|
-
|
276
|
-
var colorData = {
|
277
|
-
aliceblue: '#F0F8FF',
|
278
|
-
antiquewhite: '#FAEBD7',
|
279
|
-
aquamarine: '#7FFFD4',
|
280
|
-
azure: '#F0FFFF',
|
281
|
-
beige: '#F5F5DC',
|
282
|
-
bisque: '#FFE4C4',
|
283
|
-
black: '#000000',
|
284
|
-
blanchedalmond: '#FFEBCD',
|
285
|
-
blueviolet: '#8A2BE2',
|
286
|
-
brown: '#A52A2A',
|
287
|
-
burlywood: '#DEB887',
|
288
|
-
cadetblue: '#5F9EA0',
|
289
|
-
chartreuse: '#7FFF00',
|
290
|
-
chocolate: '#D2691E',
|
291
|
-
coral: '#FF7F50',
|
292
|
-
cornflowerblue: '#6495ED',
|
293
|
-
cornsilk: '#FFF8DC',
|
294
|
-
crimson: '#DC143C',
|
295
|
-
cyan: '#00FFFF',
|
296
|
-
darkblue: '#00008B',
|
297
|
-
darkcyan: '#008B8B',
|
298
|
-
darkgoldenrod: '#B8860B',
|
299
|
-
darkgray: '#A9A9A9',
|
300
|
-
darkgreen: '#006400',
|
301
|
-
darkgrey: '#A9A9A9',
|
302
|
-
darkkhaki: '#BDB76B',
|
303
|
-
darkmagenta: '#8B008B',
|
304
|
-
darkolivegreen: '#556B2F',
|
305
|
-
darkorange: '#FF8C00',
|
306
|
-
darkorchid: '#9932CC',
|
307
|
-
darkred: '#8B0000',
|
308
|
-
darksalmon: '#E9967A',
|
309
|
-
darkseagreen: '#8FBC8F',
|
310
|
-
darkslateblue: '#483D8B',
|
311
|
-
darkslategray: '#2F4F4F',
|
312
|
-
darkslategrey: '#2F4F4F',
|
313
|
-
darkturquoise: '#00CED1',
|
314
|
-
darkviolet: '#9400D3',
|
315
|
-
deeppink: '#FF1493',
|
316
|
-
deepskyblue: '#00BFFF',
|
317
|
-
dimgray: '#696969',
|
318
|
-
dimgrey: '#696969',
|
319
|
-
dodgerblue: '#1E90FF',
|
320
|
-
firebrick: '#B22222',
|
321
|
-
floralwhite: '#FFFAF0',
|
322
|
-
forestgreen: '#228B22',
|
323
|
-
gainsboro: '#DCDCDC',
|
324
|
-
ghostwhite: '#F8F8FF',
|
325
|
-
gold: '#FFD700',
|
326
|
-
goldenrod: '#DAA520',
|
327
|
-
grey: '#808080',
|
328
|
-
greenyellow: '#ADFF2F',
|
329
|
-
honeydew: '#F0FFF0',
|
330
|
-
hotpink: '#FF69B4',
|
331
|
-
indianred: '#CD5C5C',
|
332
|
-
indigo: '#4B0082',
|
333
|
-
ivory: '#FFFFF0',
|
334
|
-
khaki: '#F0E68C',
|
335
|
-
lavender: '#E6E6FA',
|
336
|
-
lavenderblush: '#FFF0F5',
|
337
|
-
lawngreen: '#7CFC00',
|
338
|
-
lemonchiffon: '#FFFACD',
|
339
|
-
lightblue: '#ADD8E6',
|
340
|
-
lightcoral: '#F08080',
|
341
|
-
lightcyan: '#E0FFFF',
|
342
|
-
lightgoldenrodyellow: '#FAFAD2',
|
343
|
-
lightgreen: '#90EE90',
|
344
|
-
lightgrey: '#D3D3D3',
|
345
|
-
lightpink: '#FFB6C1',
|
346
|
-
lightsalmon: '#FFA07A',
|
347
|
-
lightseagreen: '#20B2AA',
|
348
|
-
lightskyblue: '#87CEFA',
|
349
|
-
lightslategray: '#778899',
|
350
|
-
lightslategrey: '#778899',
|
351
|
-
lightsteelblue: '#B0C4DE',
|
352
|
-
lightyellow: '#FFFFE0',
|
353
|
-
limegreen: '#32CD32',
|
354
|
-
linen: '#FAF0E6',
|
355
|
-
magenta: '#FF00FF',
|
356
|
-
mediumaquamarine: '#66CDAA',
|
357
|
-
mediumblue: '#0000CD',
|
358
|
-
mediumorchid: '#BA55D3',
|
359
|
-
mediumpurple: '#9370DB',
|
360
|
-
mediumseagreen: '#3CB371',
|
361
|
-
mediumslateblue: '#7B68EE',
|
362
|
-
mediumspringgreen: '#00FA9A',
|
363
|
-
mediumturquoise: '#48D1CC',
|
364
|
-
mediumvioletred: '#C71585',
|
365
|
-
midnightblue: '#191970',
|
366
|
-
mintcream: '#F5FFFA',
|
367
|
-
mistyrose: '#FFE4E1',
|
368
|
-
moccasin: '#FFE4B5',
|
369
|
-
navajowhite: '#FFDEAD',
|
370
|
-
oldlace: '#FDF5E6',
|
371
|
-
olivedrab: '#6B8E23',
|
372
|
-
orange: '#FFA500',
|
373
|
-
orangered: '#FF4500',
|
374
|
-
orchid: '#DA70D6',
|
375
|
-
palegoldenrod: '#EEE8AA',
|
376
|
-
palegreen: '#98FB98',
|
377
|
-
paleturquoise: '#AFEEEE',
|
378
|
-
palevioletred: '#DB7093',
|
379
|
-
papayawhip: '#FFEFD5',
|
380
|
-
peachpuff: '#FFDAB9',
|
381
|
-
peru: '#CD853F',
|
382
|
-
pink: '#FFC0CB',
|
383
|
-
plum: '#DDA0DD',
|
384
|
-
powderblue: '#B0E0E6',
|
385
|
-
rosybrown: '#BC8F8F',
|
386
|
-
royalblue: '#4169E1',
|
387
|
-
saddlebrown: '#8B4513',
|
388
|
-
salmon: '#FA8072',
|
389
|
-
sandybrown: '#F4A460',
|
390
|
-
seagreen: '#2E8B57',
|
391
|
-
seashell: '#FFF5EE',
|
392
|
-
sienna: '#A0522D',
|
393
|
-
skyblue: '#87CEEB',
|
394
|
-
slateblue: '#6A5ACD',
|
395
|
-
slategray: '#708090',
|
396
|
-
slategrey: '#708090',
|
397
|
-
snow: '#FFFAFA',
|
398
|
-
springgreen: '#00FF7F',
|
399
|
-
steelblue: '#4682B4',
|
400
|
-
tan: '#D2B48C',
|
401
|
-
thistle: '#D8BFD8',
|
402
|
-
tomato: '#FF6347',
|
403
|
-
turquoise: '#40E0D0',
|
404
|
-
violet: '#EE82EE',
|
405
|
-
wheat: '#F5DEB3',
|
406
|
-
whitesmoke: '#F5F5F5',
|
407
|
-
yellowgreen: '#9ACD32'
|
408
|
-
};
|
409
|
-
|
410
|
-
|
411
|
-
function getRgbHslContent(styleString) {
|
412
|
-
var start = styleString.indexOf('(', 3);
|
413
|
-
var end = styleString.indexOf(')', start + 1);
|
414
|
-
var parts = styleString.substring(start + 1, end).split(',');
|
415
|
-
// add alpha if needed
|
416
|
-
if (parts.length != 4 || styleString.charAt(3) != 'a') {
|
417
|
-
parts[3] = 1;
|
418
|
-
}
|
419
|
-
return parts;
|
420
|
-
}
|
421
|
-
|
422
|
-
function percent(s) {
|
423
|
-
return parseFloat(s) / 100;
|
424
|
-
}
|
425
|
-
|
426
|
-
function clamp(v, min, max) {
|
427
|
-
return Math.min(max, Math.max(min, v));
|
428
|
-
}
|
429
|
-
|
430
|
-
function hslToRgb(parts){
|
431
|
-
var r, g, b, h, s, l;
|
432
|
-
h = parseFloat(parts[0]) / 360 % 360;
|
433
|
-
if (h < 0)
|
434
|
-
h++;
|
435
|
-
s = clamp(percent(parts[1]), 0, 1);
|
436
|
-
l = clamp(percent(parts[2]), 0, 1);
|
437
|
-
if (s == 0) {
|
438
|
-
r = g = b = l; // achromatic
|
439
|
-
} else {
|
440
|
-
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
441
|
-
var p = 2 * l - q;
|
442
|
-
r = hueToRgb(p, q, h + 1 / 3);
|
443
|
-
g = hueToRgb(p, q, h);
|
444
|
-
b = hueToRgb(p, q, h - 1 / 3);
|
445
|
-
}
|
446
|
-
|
447
|
-
return '#' + decToHex[Math.floor(r * 255)] +
|
448
|
-
decToHex[Math.floor(g * 255)] +
|
449
|
-
decToHex[Math.floor(b * 255)];
|
450
|
-
}
|
451
|
-
|
452
|
-
function hueToRgb(m1, m2, h) {
|
453
|
-
if (h < 0)
|
454
|
-
h++;
|
455
|
-
if (h > 1)
|
456
|
-
h--;
|
457
|
-
|
458
|
-
if (6 * h < 1)
|
459
|
-
return m1 + (m2 - m1) * 6 * h;
|
460
|
-
else if (2 * h < 1)
|
461
|
-
return m2;
|
462
|
-
else if (3 * h < 2)
|
463
|
-
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
464
|
-
else
|
465
|
-
return m1;
|
466
|
-
}
|
467
|
-
|
468
|
-
var processStyleCache = {};
|
469
|
-
|
470
|
-
function processStyle(styleString) {
|
471
|
-
if (styleString in processStyleCache) {
|
472
|
-
return processStyleCache[styleString];
|
473
|
-
}
|
474
|
-
|
475
|
-
var str, alpha = 1;
|
476
|
-
|
477
|
-
styleString = String(styleString);
|
478
|
-
if (styleString.charAt(0) == '#') {
|
479
|
-
str = styleString;
|
480
|
-
} else if (/^rgb/.test(styleString)) {
|
481
|
-
var parts = getRgbHslContent(styleString);
|
482
|
-
var str = '#', n;
|
483
|
-
for (var i = 0; i < 3; i++) {
|
484
|
-
if (parts[i].indexOf('%') != -1) {
|
485
|
-
n = Math.floor(percent(parts[i]) * 255);
|
486
|
-
} else {
|
487
|
-
n = +parts[i];
|
488
|
-
}
|
489
|
-
str += decToHex[clamp(n, 0, 255)];
|
490
|
-
}
|
491
|
-
alpha = +parts[3];
|
492
|
-
} else if (/^hsl/.test(styleString)) {
|
493
|
-
var parts = getRgbHslContent(styleString);
|
494
|
-
str = hslToRgb(parts);
|
495
|
-
alpha = parts[3];
|
496
|
-
} else {
|
497
|
-
str = colorData[styleString] || styleString;
|
498
|
-
}
|
499
|
-
return processStyleCache[styleString] = {color: str, alpha: alpha};
|
500
|
-
}
|
501
|
-
|
502
|
-
var DEFAULT_STYLE = {
|
503
|
-
style: 'normal',
|
504
|
-
variant: 'normal',
|
505
|
-
weight: 'normal',
|
506
|
-
size: 10,
|
507
|
-
family: 'sans-serif'
|
508
|
-
};
|
509
|
-
|
510
|
-
// Internal text style cache
|
511
|
-
var fontStyleCache = {};
|
512
|
-
|
513
|
-
function processFontStyle(styleString) {
|
514
|
-
if (fontStyleCache[styleString]) {
|
515
|
-
return fontStyleCache[styleString];
|
516
|
-
}
|
517
|
-
|
518
|
-
var el = document.createElement('div');
|
519
|
-
var style = el.style;
|
520
|
-
try {
|
521
|
-
style.font = styleString;
|
522
|
-
} catch (ex) {
|
523
|
-
// Ignore failures to set to invalid font.
|
524
|
-
}
|
525
|
-
|
526
|
-
return fontStyleCache[styleString] = {
|
527
|
-
style: style.fontStyle || DEFAULT_STYLE.style,
|
528
|
-
variant: style.fontVariant || DEFAULT_STYLE.variant,
|
529
|
-
weight: style.fontWeight || DEFAULT_STYLE.weight,
|
530
|
-
size: style.fontSize || DEFAULT_STYLE.size,
|
531
|
-
family: style.fontFamily || DEFAULT_STYLE.family
|
532
|
-
};
|
533
|
-
}
|
534
|
-
|
535
|
-
function getComputedStyle(style, element) {
|
536
|
-
var computedStyle = {};
|
537
|
-
|
538
|
-
for (var p in style) {
|
539
|
-
computedStyle[p] = style[p];
|
540
|
-
}
|
541
|
-
|
542
|
-
// Compute the size
|
543
|
-
var canvasFontSize = parseFloat(element.currentStyle.fontSize),
|
544
|
-
fontSize = parseFloat(style.size);
|
545
|
-
|
546
|
-
if (typeof style.size == 'number') {
|
547
|
-
computedStyle.size = style.size;
|
548
|
-
} else if (style.size.indexOf('px') != -1) {
|
549
|
-
computedStyle.size = fontSize;
|
550
|
-
} else if (style.size.indexOf('em') != -1) {
|
551
|
-
computedStyle.size = canvasFontSize * fontSize;
|
552
|
-
} else if(style.size.indexOf('%') != -1) {
|
553
|
-
computedStyle.size = (canvasFontSize / 100) * fontSize;
|
554
|
-
} else if (style.size.indexOf('pt') != -1) {
|
555
|
-
computedStyle.size = fontSize / .75;
|
556
|
-
} else {
|
557
|
-
computedStyle.size = canvasFontSize;
|
558
|
-
}
|
559
|
-
|
560
|
-
// Different scaling between normal text and VML text. This was found using
|
561
|
-
// trial and error to get the same size as non VML text.
|
562
|
-
computedStyle.size *= 0.981;
|
563
|
-
|
564
|
-
// Fix for VML handling of bare font family names. Add a '' around font family names.
|
565
|
-
computedStyle.family = "'" + computedStyle.family.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
|
566
|
-
|
567
|
-
return computedStyle;
|
568
|
-
}
|
569
|
-
|
570
|
-
function buildStyle(style) {
|
571
|
-
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
|
572
|
-
style.size + 'px ' + style.family;
|
573
|
-
}
|
574
|
-
|
575
|
-
var lineCapMap = {
|
576
|
-
'butt': 'flat',
|
577
|
-
'round': 'round'
|
578
|
-
};
|
579
|
-
|
580
|
-
function processLineCap(lineCap) {
|
581
|
-
return lineCapMap[lineCap] || 'square';
|
582
|
-
}
|
583
|
-
|
584
|
-
/**
|
585
|
-
* This class implements CanvasRenderingContext2D interface as described by
|
586
|
-
* the WHATWG.
|
587
|
-
* @param {HTMLElement} canvasElement The element that the 2D context should
|
588
|
-
* be associated with
|
589
|
-
*/
|
590
|
-
function CanvasRenderingContext2D_(canvasElement) {
|
591
|
-
this.m_ = createMatrixIdentity();
|
592
|
-
|
593
|
-
this.mStack_ = [];
|
594
|
-
this.aStack_ = [];
|
595
|
-
this.currentPath_ = [];
|
596
|
-
|
597
|
-
// Canvas context properties
|
598
|
-
this.strokeStyle = '#000';
|
599
|
-
this.fillStyle = '#000';
|
600
|
-
|
601
|
-
this.lineWidth = 1;
|
602
|
-
this.lineJoin = 'miter';
|
603
|
-
this.lineCap = 'butt';
|
604
|
-
this.miterLimit = Z * 1;
|
605
|
-
this.globalAlpha = 1;
|
606
|
-
this.font = '10px sans-serif';
|
607
|
-
this.textAlign = 'left';
|
608
|
-
this.textBaseline = 'alphabetic';
|
609
|
-
this.canvas = canvasElement;
|
610
|
-
|
611
|
-
var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
|
612
|
-
canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
|
613
|
-
var el = canvasElement.ownerDocument.createElement('div');
|
614
|
-
el.style.cssText = cssText;
|
615
|
-
canvasElement.appendChild(el);
|
616
|
-
|
617
|
-
var overlayEl = el.cloneNode(false);
|
618
|
-
// Use a non transparent background.
|
619
|
-
overlayEl.style.backgroundColor = 'red';
|
620
|
-
overlayEl.style.filter = 'alpha(opacity=0)';
|
621
|
-
canvasElement.appendChild(overlayEl);
|
622
|
-
|
623
|
-
this.element_ = el;
|
624
|
-
this.arcScaleX_ = 1;
|
625
|
-
this.arcScaleY_ = 1;
|
626
|
-
this.lineScale_ = 1;
|
627
|
-
}
|
628
|
-
|
629
|
-
var contextPrototype = CanvasRenderingContext2D_.prototype;
|
630
|
-
contextPrototype.clearRect = function() {
|
631
|
-
if (this.textMeasureEl_) {
|
632
|
-
this.textMeasureEl_.removeNode(true);
|
633
|
-
this.textMeasureEl_ = null;
|
634
|
-
}
|
635
|
-
this.element_.innerHTML = '';
|
636
|
-
};
|
637
|
-
|
638
|
-
contextPrototype.beginPath = function() {
|
639
|
-
// TODO: Branch current matrix so that save/restore has no effect
|
640
|
-
// as per safari docs.
|
641
|
-
this.currentPath_ = [];
|
642
|
-
};
|
643
|
-
|
644
|
-
contextPrototype.moveTo = function(aX, aY) {
|
645
|
-
var p = getCoords(this, aX, aY);
|
646
|
-
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
|
647
|
-
this.currentX_ = p.x;
|
648
|
-
this.currentY_ = p.y;
|
649
|
-
};
|
650
|
-
|
651
|
-
contextPrototype.lineTo = function(aX, aY) {
|
652
|
-
var p = getCoords(this, aX, aY);
|
653
|
-
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
|
654
|
-
|
655
|
-
this.currentX_ = p.x;
|
656
|
-
this.currentY_ = p.y;
|
657
|
-
};
|
658
|
-
|
659
|
-
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
|
660
|
-
aCP2x, aCP2y,
|
661
|
-
aX, aY) {
|
662
|
-
var p = getCoords(this, aX, aY);
|
663
|
-
var cp1 = getCoords(this, aCP1x, aCP1y);
|
664
|
-
var cp2 = getCoords(this, aCP2x, aCP2y);
|
665
|
-
bezierCurveTo(this, cp1, cp2, p);
|
666
|
-
};
|
667
|
-
|
668
|
-
// Helper function that takes the already fixed cordinates.
|
669
|
-
function bezierCurveTo(self, cp1, cp2, p) {
|
670
|
-
self.currentPath_.push({
|
671
|
-
type: 'bezierCurveTo',
|
672
|
-
cp1x: cp1.x,
|
673
|
-
cp1y: cp1.y,
|
674
|
-
cp2x: cp2.x,
|
675
|
-
cp2y: cp2.y,
|
676
|
-
x: p.x,
|
677
|
-
y: p.y
|
678
|
-
});
|
679
|
-
self.currentX_ = p.x;
|
680
|
-
self.currentY_ = p.y;
|
681
|
-
}
|
682
|
-
|
683
|
-
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
|
684
|
-
// the following is lifted almost directly from
|
685
|
-
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
|
686
|
-
|
687
|
-
var cp = getCoords(this, aCPx, aCPy);
|
688
|
-
var p = getCoords(this, aX, aY);
|
689
|
-
|
690
|
-
var cp1 = {
|
691
|
-
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
|
692
|
-
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
|
693
|
-
};
|
694
|
-
var cp2 = {
|
695
|
-
x: cp1.x + (p.x - this.currentX_) / 3.0,
|
696
|
-
y: cp1.y + (p.y - this.currentY_) / 3.0
|
697
|
-
};
|
698
|
-
|
699
|
-
bezierCurveTo(this, cp1, cp2, p);
|
700
|
-
};
|
701
|
-
|
702
|
-
contextPrototype.arc = function(aX, aY, aRadius,
|
703
|
-
aStartAngle, aEndAngle, aClockwise) {
|
704
|
-
aRadius *= Z;
|
705
|
-
var arcType = aClockwise ? 'at' : 'wa';
|
706
|
-
|
707
|
-
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
|
708
|
-
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
|
709
|
-
|
710
|
-
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
|
711
|
-
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
|
712
|
-
|
713
|
-
// IE won't render arches drawn counter clockwise if xStart == xEnd.
|
714
|
-
if (xStart == xEnd && !aClockwise) {
|
715
|
-
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
|
716
|
-
// that can be represented in binary
|
717
|
-
}
|
718
|
-
|
719
|
-
var p = getCoords(this, aX, aY);
|
720
|
-
var pStart = getCoords(this, xStart, yStart);
|
721
|
-
var pEnd = getCoords(this, xEnd, yEnd);
|
722
|
-
|
723
|
-
this.currentPath_.push({type: arcType,
|
724
|
-
x: p.x,
|
725
|
-
y: p.y,
|
726
|
-
radius: aRadius,
|
727
|
-
xStart: pStart.x,
|
728
|
-
yStart: pStart.y,
|
729
|
-
xEnd: pEnd.x,
|
730
|
-
yEnd: pEnd.y});
|
731
|
-
|
732
|
-
};
|
733
|
-
|
734
|
-
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
|
735
|
-
this.moveTo(aX, aY);
|
736
|
-
this.lineTo(aX + aWidth, aY);
|
737
|
-
this.lineTo(aX + aWidth, aY + aHeight);
|
738
|
-
this.lineTo(aX, aY + aHeight);
|
739
|
-
this.closePath();
|
740
|
-
};
|
741
|
-
|
742
|
-
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
|
743
|
-
var oldPath = this.currentPath_;
|
744
|
-
this.beginPath();
|
745
|
-
|
746
|
-
this.moveTo(aX, aY);
|
747
|
-
this.lineTo(aX + aWidth, aY);
|
748
|
-
this.lineTo(aX + aWidth, aY + aHeight);
|
749
|
-
this.lineTo(aX, aY + aHeight);
|
750
|
-
this.closePath();
|
751
|
-
this.stroke();
|
752
|
-
|
753
|
-
this.currentPath_ = oldPath;
|
754
|
-
};
|
755
|
-
|
756
|
-
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
|
757
|
-
var oldPath = this.currentPath_;
|
758
|
-
this.beginPath();
|
759
|
-
|
760
|
-
this.moveTo(aX, aY);
|
761
|
-
this.lineTo(aX + aWidth, aY);
|
762
|
-
this.lineTo(aX + aWidth, aY + aHeight);
|
763
|
-
this.lineTo(aX, aY + aHeight);
|
764
|
-
this.closePath();
|
765
|
-
this.fill();
|
766
|
-
|
767
|
-
this.currentPath_ = oldPath;
|
768
|
-
};
|
769
|
-
|
770
|
-
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
|
771
|
-
var gradient = new CanvasGradient_('gradient');
|
772
|
-
gradient.x0_ = aX0;
|
773
|
-
gradient.y0_ = aY0;
|
774
|
-
gradient.x1_ = aX1;
|
775
|
-
gradient.y1_ = aY1;
|
776
|
-
return gradient;
|
777
|
-
};
|
778
|
-
|
779
|
-
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
|
780
|
-
aX1, aY1, aR1) {
|
781
|
-
var gradient = new CanvasGradient_('gradientradial');
|
782
|
-
gradient.x0_ = aX0;
|
783
|
-
gradient.y0_ = aY0;
|
784
|
-
gradient.r0_ = aR0;
|
785
|
-
gradient.x1_ = aX1;
|
786
|
-
gradient.y1_ = aY1;
|
787
|
-
gradient.r1_ = aR1;
|
788
|
-
return gradient;
|
789
|
-
};
|
790
|
-
|
791
|
-
contextPrototype.drawImage = function(image, var_args) {
|
792
|
-
var dx, dy, dw, dh, sx, sy, sw, sh;
|
793
|
-
|
794
|
-
// to find the original width we overide the width and height
|
795
|
-
var oldRuntimeWidth = image.runtimeStyle.width;
|
796
|
-
var oldRuntimeHeight = image.runtimeStyle.height;
|
797
|
-
image.runtimeStyle.width = 'auto';
|
798
|
-
image.runtimeStyle.height = 'auto';
|
799
|
-
|
800
|
-
// get the original size
|
801
|
-
var w = image.width;
|
802
|
-
var h = image.height;
|
803
|
-
|
804
|
-
// and remove overides
|
805
|
-
image.runtimeStyle.width = oldRuntimeWidth;
|
806
|
-
image.runtimeStyle.height = oldRuntimeHeight;
|
807
|
-
|
808
|
-
if (arguments.length == 3) {
|
809
|
-
dx = arguments[1];
|
810
|
-
dy = arguments[2];
|
811
|
-
sx = sy = 0;
|
812
|
-
sw = dw = w;
|
813
|
-
sh = dh = h;
|
814
|
-
} else if (arguments.length == 5) {
|
815
|
-
dx = arguments[1];
|
816
|
-
dy = arguments[2];
|
817
|
-
dw = arguments[3];
|
818
|
-
dh = arguments[4];
|
819
|
-
sx = sy = 0;
|
820
|
-
sw = w;
|
821
|
-
sh = h;
|
822
|
-
} else if (arguments.length == 9) {
|
823
|
-
sx = arguments[1];
|
824
|
-
sy = arguments[2];
|
825
|
-
sw = arguments[3];
|
826
|
-
sh = arguments[4];
|
827
|
-
dx = arguments[5];
|
828
|
-
dy = arguments[6];
|
829
|
-
dw = arguments[7];
|
830
|
-
dh = arguments[8];
|
831
|
-
} else {
|
832
|
-
throw Error('Invalid number of arguments');
|
833
|
-
}
|
834
|
-
|
835
|
-
var d = getCoords(this, dx, dy);
|
836
|
-
|
837
|
-
var w2 = sw / 2;
|
838
|
-
var h2 = sh / 2;
|
839
|
-
|
840
|
-
var vmlStr = [];
|
841
|
-
|
842
|
-
var W = 10;
|
843
|
-
var H = 10;
|
844
|
-
|
845
|
-
// For some reason that I've now forgotten, using divs didn't work
|
846
|
-
vmlStr.push(' <g_vml_:group',
|
847
|
-
' coordsize="', Z * W, ',', Z * H, '"',
|
848
|
-
' coordorigin="0,0"' ,
|
849
|
-
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
|
850
|
-
|
851
|
-
// If filters are necessary (rotation exists), create them
|
852
|
-
// filters are bog-slow, so only create them if abbsolutely necessary
|
853
|
-
// The following check doesn't account for skews (which don't exist
|
854
|
-
// in the canvas spec (yet) anyway.
|
855
|
-
|
856
|
-
if (this.m_[0][0] != 1 || this.m_[0][1] ||
|
857
|
-
this.m_[1][1] != 1 || this.m_[1][0]) {
|
858
|
-
var filter = [];
|
859
|
-
|
860
|
-
// Note the 12/21 reversal
|
861
|
-
filter.push('M11=', this.m_[0][0], ',',
|
862
|
-
'M12=', this.m_[1][0], ',',
|
863
|
-
'M21=', this.m_[0][1], ',',
|
864
|
-
'M22=', this.m_[1][1], ',',
|
865
|
-
'Dx=', mr(d.x / Z), ',',
|
866
|
-
'Dy=', mr(d.y / Z), '');
|
867
|
-
|
868
|
-
// Bounding box calculation (need to minimize displayed area so that
|
869
|
-
// filters don't waste time on unused pixels.
|
870
|
-
var max = d;
|
871
|
-
var c2 = getCoords(this, dx + dw, dy);
|
872
|
-
var c3 = getCoords(this, dx, dy + dh);
|
873
|
-
var c4 = getCoords(this, dx + dw, dy + dh);
|
874
|
-
|
875
|
-
max.x = m.max(max.x, c2.x, c3.x, c4.x);
|
876
|
-
max.y = m.max(max.y, c2.y, c3.y, c4.y);
|
877
|
-
|
878
|
-
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
|
879
|
-
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
|
880
|
-
filter.join(''), ", sizingmethod='clip');");
|
881
|
-
|
882
|
-
} else {
|
883
|
-
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
|
884
|
-
}
|
885
|
-
|
886
|
-
vmlStr.push(' ">' ,
|
887
|
-
'<g_vml_:image src="', image.src, '"',
|
888
|
-
' style="width:', Z * dw, 'px;',
|
889
|
-
' height:', Z * dh, 'px"',
|
890
|
-
' cropleft="', sx / w, '"',
|
891
|
-
' croptop="', sy / h, '"',
|
892
|
-
' cropright="', (w - sx - sw) / w, '"',
|
893
|
-
' cropbottom="', (h - sy - sh) / h, '"',
|
894
|
-
' />',
|
895
|
-
'</g_vml_:group>');
|
896
|
-
|
897
|
-
this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
|
898
|
-
};
|
899
|
-
|
900
|
-
contextPrototype.stroke = function(aFill) {
|
901
|
-
var lineStr = [];
|
902
|
-
var lineOpen = false;
|
903
|
-
|
904
|
-
var W = 10;
|
905
|
-
var H = 10;
|
906
|
-
|
907
|
-
lineStr.push('<g_vml_:shape',
|
908
|
-
' filled="', !!aFill, '"',
|
909
|
-
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
|
910
|
-
' coordorigin="0,0"',
|
911
|
-
' coordsize="', Z * W, ',', Z * H, '"',
|
912
|
-
' stroked="', !aFill, '"',
|
913
|
-
' path="');
|
914
|
-
|
915
|
-
var newSeq = false;
|
916
|
-
var min = {x: null, y: null};
|
917
|
-
var max = {x: null, y: null};
|
918
|
-
|
919
|
-
for (var i = 0; i < this.currentPath_.length; i++) {
|
920
|
-
var p = this.currentPath_[i];
|
921
|
-
var c;
|
922
|
-
|
923
|
-
switch (p.type) {
|
924
|
-
case 'moveTo':
|
925
|
-
c = p;
|
926
|
-
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
|
927
|
-
break;
|
928
|
-
case 'lineTo':
|
929
|
-
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
|
930
|
-
break;
|
931
|
-
case 'close':
|
932
|
-
lineStr.push(' x ');
|
933
|
-
p = null;
|
934
|
-
break;
|
935
|
-
case 'bezierCurveTo':
|
936
|
-
lineStr.push(' c ',
|
937
|
-
mr(p.cp1x), ',', mr(p.cp1y), ',',
|
938
|
-
mr(p.cp2x), ',', mr(p.cp2y), ',',
|
939
|
-
mr(p.x), ',', mr(p.y));
|
940
|
-
break;
|
941
|
-
case 'at':
|
942
|
-
case 'wa':
|
943
|
-
lineStr.push(' ', p.type, ' ',
|
944
|
-
mr(p.x - this.arcScaleX_ * p.radius), ',',
|
945
|
-
mr(p.y - this.arcScaleY_ * p.radius), ' ',
|
946
|
-
mr(p.x + this.arcScaleX_ * p.radius), ',',
|
947
|
-
mr(p.y + this.arcScaleY_ * p.radius), ' ',
|
948
|
-
mr(p.xStart), ',', mr(p.yStart), ' ',
|
949
|
-
mr(p.xEnd), ',', mr(p.yEnd));
|
950
|
-
break;
|
951
|
-
}
|
952
|
-
|
953
|
-
|
954
|
-
// TODO: Following is broken for curves due to
|
955
|
-
// move to proper paths.
|
956
|
-
|
957
|
-
// Figure out dimensions so we can do gradient fills
|
958
|
-
// properly
|
959
|
-
if (p) {
|
960
|
-
if (min.x == null || p.x < min.x) {
|
961
|
-
min.x = p.x;
|
962
|
-
}
|
963
|
-
if (max.x == null || p.x > max.x) {
|
964
|
-
max.x = p.x;
|
965
|
-
}
|
966
|
-
if (min.y == null || p.y < min.y) {
|
967
|
-
min.y = p.y;
|
968
|
-
}
|
969
|
-
if (max.y == null || p.y > max.y) {
|
970
|
-
max.y = p.y;
|
971
|
-
}
|
972
|
-
}
|
973
|
-
}
|
974
|
-
lineStr.push(' ">');
|
975
|
-
|
976
|
-
if (!aFill) {
|
977
|
-
appendStroke(this, lineStr);
|
978
|
-
} else {
|
979
|
-
appendFill(this, lineStr, min, max);
|
980
|
-
}
|
981
|
-
|
982
|
-
lineStr.push('</g_vml_:shape>');
|
983
|
-
|
984
|
-
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
985
|
-
};
|
986
|
-
|
987
|
-
function appendStroke(ctx, lineStr) {
|
988
|
-
var a = processStyle(ctx.strokeStyle);
|
989
|
-
var color = a.color;
|
990
|
-
var opacity = a.alpha * ctx.globalAlpha;
|
991
|
-
var lineWidth = ctx.lineScale_ * ctx.lineWidth;
|
992
|
-
|
993
|
-
// VML cannot correctly render a line if the width is less than 1px.
|
994
|
-
// In that case, we dilute the color to make the line look thinner.
|
995
|
-
if (lineWidth < 1) {
|
996
|
-
opacity *= lineWidth;
|
997
|
-
}
|
998
|
-
|
999
|
-
lineStr.push(
|
1000
|
-
'<g_vml_:stroke',
|
1001
|
-
' opacity="', opacity, '"',
|
1002
|
-
' joinstyle="', ctx.lineJoin, '"',
|
1003
|
-
' miterlimit="', ctx.miterLimit, '"',
|
1004
|
-
' endcap="', processLineCap(ctx.lineCap), '"',
|
1005
|
-
' weight="', lineWidth, 'px"',
|
1006
|
-
' color="', color, '" />'
|
1007
|
-
);
|
1008
|
-
}
|
1009
|
-
|
1010
|
-
function appendFill(ctx, lineStr, min, max) {
|
1011
|
-
var fillStyle = ctx.fillStyle;
|
1012
|
-
var arcScaleX = ctx.arcScaleX_;
|
1013
|
-
var arcScaleY = ctx.arcScaleY_;
|
1014
|
-
var width = max.x - min.x;
|
1015
|
-
var height = max.y - min.y;
|
1016
|
-
if (fillStyle instanceof CanvasGradient_) {
|
1017
|
-
// TODO: Gradients transformed with the transformation matrix.
|
1018
|
-
var angle = 0;
|
1019
|
-
var focus = {x: 0, y: 0};
|
1020
|
-
|
1021
|
-
// additional offset
|
1022
|
-
var shift = 0;
|
1023
|
-
// scale factor for offset
|
1024
|
-
var expansion = 1;
|
1025
|
-
|
1026
|
-
if (fillStyle.type_ == 'gradient') {
|
1027
|
-
var x0 = fillStyle.x0_ / arcScaleX;
|
1028
|
-
var y0 = fillStyle.y0_ / arcScaleY;
|
1029
|
-
var x1 = fillStyle.x1_ / arcScaleX;
|
1030
|
-
var y1 = fillStyle.y1_ / arcScaleY;
|
1031
|
-
var p0 = getCoords(ctx, x0, y0);
|
1032
|
-
var p1 = getCoords(ctx, x1, y1);
|
1033
|
-
var dx = p1.x - p0.x;
|
1034
|
-
var dy = p1.y - p0.y;
|
1035
|
-
angle = Math.atan2(dx, dy) * 180 / Math.PI;
|
1036
|
-
|
1037
|
-
// The angle should be a non-negative number.
|
1038
|
-
if (angle < 0) {
|
1039
|
-
angle += 360;
|
1040
|
-
}
|
1041
|
-
|
1042
|
-
// Very small angles produce an unexpected result because they are
|
1043
|
-
// converted to a scientific notation string.
|
1044
|
-
if (angle < 1e-6) {
|
1045
|
-
angle = 0;
|
1046
|
-
}
|
1047
|
-
} else {
|
1048
|
-
var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
|
1049
|
-
focus = {
|
1050
|
-
x: (p0.x - min.x) / width,
|
1051
|
-
y: (p0.y - min.y) / height
|
1052
|
-
};
|
1053
|
-
|
1054
|
-
width /= arcScaleX * Z;
|
1055
|
-
height /= arcScaleY * Z;
|
1056
|
-
var dimension = m.max(width, height);
|
1057
|
-
shift = 2 * fillStyle.r0_ / dimension;
|
1058
|
-
expansion = 2 * fillStyle.r1_ / dimension - shift;
|
1059
|
-
}
|
1060
|
-
|
1061
|
-
// We need to sort the color stops in ascending order by offset,
|
1062
|
-
// otherwise IE won't interpret it correctly.
|
1063
|
-
var stops = fillStyle.colors_;
|
1064
|
-
stops.sort(function(cs1, cs2) {
|
1065
|
-
return cs1.offset - cs2.offset;
|
1066
|
-
});
|
1067
|
-
|
1068
|
-
var length = stops.length;
|
1069
|
-
var color1 = stops[0].color;
|
1070
|
-
var color2 = stops[length - 1].color;
|
1071
|
-
var opacity1 = stops[0].alpha * ctx.globalAlpha;
|
1072
|
-
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
|
1073
|
-
|
1074
|
-
var colors = [];
|
1075
|
-
for (var i = 0; i < length; i++) {
|
1076
|
-
var stop = stops[i];
|
1077
|
-
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
|
1078
|
-
}
|
1079
|
-
|
1080
|
-
// When colors attribute is used, the meanings of opacity and o:opacity2
|
1081
|
-
// are reversed.
|
1082
|
-
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
|
1083
|
-
' method="none" focus="100%"',
|
1084
|
-
' color="', color1, '"',
|
1085
|
-
' color2="', color2, '"',
|
1086
|
-
' colors="', colors.join(','), '"',
|
1087
|
-
' opacity="', opacity2, '"',
|
1088
|
-
' g_o_:opacity2="', opacity1, '"',
|
1089
|
-
' angle="', angle, '"',
|
1090
|
-
' focusposition="', focus.x, ',', focus.y, '" />');
|
1091
|
-
} else if (fillStyle instanceof CanvasPattern_) {
|
1092
|
-
if (width && height) {
|
1093
|
-
var deltaLeft = -min.x;
|
1094
|
-
var deltaTop = -min.y;
|
1095
|
-
lineStr.push('<g_vml_:fill',
|
1096
|
-
' position="',
|
1097
|
-
deltaLeft / width * arcScaleX * arcScaleX, ',',
|
1098
|
-
deltaTop / height * arcScaleY * arcScaleY, '"',
|
1099
|
-
' type="tile"',
|
1100
|
-
// TODO: Figure out the correct size to fit the scale.
|
1101
|
-
//' size="', w, 'px ', h, 'px"',
|
1102
|
-
' src="', fillStyle.src_, '" />');
|
1103
|
-
}
|
1104
|
-
} else {
|
1105
|
-
var a = processStyle(ctx.fillStyle);
|
1106
|
-
var color = a.color;
|
1107
|
-
var opacity = a.alpha * ctx.globalAlpha;
|
1108
|
-
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
|
1109
|
-
'" />');
|
1110
|
-
}
|
1111
|
-
}
|
1112
|
-
|
1113
|
-
contextPrototype.fill = function() {
|
1114
|
-
this.stroke(true);
|
1115
|
-
};
|
1116
|
-
|
1117
|
-
contextPrototype.closePath = function() {
|
1118
|
-
this.currentPath_.push({type: 'close'});
|
1119
|
-
};
|
1120
|
-
|
1121
|
-
function getCoords(ctx, aX, aY) {
|
1122
|
-
var m = ctx.m_;
|
1123
|
-
return {
|
1124
|
-
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
|
1125
|
-
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
|
1126
|
-
};
|
1127
|
-
};
|
1128
|
-
|
1129
|
-
contextPrototype.save = function() {
|
1130
|
-
var o = {};
|
1131
|
-
copyState(this, o);
|
1132
|
-
this.aStack_.push(o);
|
1133
|
-
this.mStack_.push(this.m_);
|
1134
|
-
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
|
1135
|
-
};
|
1136
|
-
|
1137
|
-
contextPrototype.restore = function() {
|
1138
|
-
if (this.aStack_.length) {
|
1139
|
-
copyState(this.aStack_.pop(), this);
|
1140
|
-
this.m_ = this.mStack_.pop();
|
1141
|
-
}
|
1142
|
-
};
|
1143
|
-
|
1144
|
-
function matrixIsFinite(m) {
|
1145
|
-
return isFinite(m[0][0]) && isFinite(m[0][1]) &&
|
1146
|
-
isFinite(m[1][0]) && isFinite(m[1][1]) &&
|
1147
|
-
isFinite(m[2][0]) && isFinite(m[2][1]);
|
1148
|
-
}
|
1149
|
-
|
1150
|
-
function setM(ctx, m, updateLineScale) {
|
1151
|
-
if (!matrixIsFinite(m)) {
|
1152
|
-
return;
|
1153
|
-
}
|
1154
|
-
ctx.m_ = m;
|
1155
|
-
|
1156
|
-
if (updateLineScale) {
|
1157
|
-
// Get the line scale.
|
1158
|
-
// Determinant of this.m_ means how much the area is enlarged by the
|
1159
|
-
// transformation. So its square root can be used as a scale factor
|
1160
|
-
// for width.
|
1161
|
-
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
1162
|
-
ctx.lineScale_ = sqrt(abs(det));
|
1163
|
-
}
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
contextPrototype.translate = function(aX, aY) {
|
1167
|
-
var m1 = [
|
1168
|
-
[1, 0, 0],
|
1169
|
-
[0, 1, 0],
|
1170
|
-
[aX, aY, 1]
|
1171
|
-
];
|
1172
|
-
|
1173
|
-
setM(this, matrixMultiply(m1, this.m_), false);
|
1174
|
-
};
|
1175
|
-
|
1176
|
-
contextPrototype.rotate = function(aRot) {
|
1177
|
-
var c = mc(aRot);
|
1178
|
-
var s = ms(aRot);
|
1179
|
-
|
1180
|
-
var m1 = [
|
1181
|
-
[c, s, 0],
|
1182
|
-
[-s, c, 0],
|
1183
|
-
[0, 0, 1]
|
1184
|
-
];
|
1185
|
-
|
1186
|
-
setM(this, matrixMultiply(m1, this.m_), false);
|
1187
|
-
};
|
1188
|
-
|
1189
|
-
contextPrototype.scale = function(aX, aY) {
|
1190
|
-
this.arcScaleX_ *= aX;
|
1191
|
-
this.arcScaleY_ *= aY;
|
1192
|
-
var m1 = [
|
1193
|
-
[aX, 0, 0],
|
1194
|
-
[0, aY, 0],
|
1195
|
-
[0, 0, 1]
|
1196
|
-
];
|
1197
|
-
|
1198
|
-
setM(this, matrixMultiply(m1, this.m_), true);
|
1199
|
-
};
|
1200
|
-
|
1201
|
-
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
|
1202
|
-
var m1 = [
|
1203
|
-
[m11, m12, 0],
|
1204
|
-
[m21, m22, 0],
|
1205
|
-
[dx, dy, 1]
|
1206
|
-
];
|
1207
|
-
|
1208
|
-
setM(this, matrixMultiply(m1, this.m_), true);
|
1209
|
-
};
|
1210
|
-
|
1211
|
-
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
|
1212
|
-
var m = [
|
1213
|
-
[m11, m12, 0],
|
1214
|
-
[m21, m22, 0],
|
1215
|
-
[dx, dy, 1]
|
1216
|
-
];
|
1217
|
-
|
1218
|
-
setM(this, m, true);
|
1219
|
-
};
|
1220
|
-
|
1221
|
-
/**
|
1222
|
-
* The text drawing function.
|
1223
|
-
* The maxWidth argument isn't taken in account, since no browser supports
|
1224
|
-
* it yet.
|
1225
|
-
*/
|
1226
|
-
contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
|
1227
|
-
var m = this.m_,
|
1228
|
-
delta = 1000,
|
1229
|
-
left = 0,
|
1230
|
-
right = delta,
|
1231
|
-
offset = {x: 0, y: 0},
|
1232
|
-
lineStr = [];
|
1233
|
-
|
1234
|
-
var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_);
|
1235
|
-
|
1236
|
-
var fontStyleString = buildStyle(fontStyle);
|
1237
|
-
|
1238
|
-
var elementStyle = this.element_.currentStyle;
|
1239
|
-
var textAlign = this.textAlign.toLowerCase();
|
1240
|
-
switch (textAlign) {
|
1241
|
-
case 'left':
|
1242
|
-
case 'center':
|
1243
|
-
case 'right':
|
1244
|
-
break;
|
1245
|
-
case 'end':
|
1246
|
-
textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
|
1247
|
-
break;
|
1248
|
-
case 'start':
|
1249
|
-
textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
|
1250
|
-
break;
|
1251
|
-
default:
|
1252
|
-
textAlign = 'left';
|
1253
|
-
}
|
1254
|
-
|
1255
|
-
// 1.75 is an arbitrary number, as there is no info about the text baseline
|
1256
|
-
switch (this.textBaseline) {
|
1257
|
-
case 'hanging':
|
1258
|
-
case 'top':
|
1259
|
-
offset.y = fontStyle.size / 1.75;
|
1260
|
-
break;
|
1261
|
-
case 'middle':
|
1262
|
-
break;
|
1263
|
-
default:
|
1264
|
-
case null:
|
1265
|
-
case 'alphabetic':
|
1266
|
-
case 'ideographic':
|
1267
|
-
case 'bottom':
|
1268
|
-
offset.y = -fontStyle.size / 2.25;
|
1269
|
-
break;
|
1270
|
-
}
|
1271
|
-
|
1272
|
-
switch(textAlign) {
|
1273
|
-
case 'right':
|
1274
|
-
left = delta;
|
1275
|
-
right = 0.05;
|
1276
|
-
break;
|
1277
|
-
case 'center':
|
1278
|
-
left = right = delta / 2;
|
1279
|
-
break;
|
1280
|
-
}
|
1281
|
-
|
1282
|
-
var d = getCoords(this, x + offset.x, y + offset.y);
|
1283
|
-
|
1284
|
-
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
|
1285
|
-
' coordsize="100 100" coordorigin="0 0"',
|
1286
|
-
' filled="', !stroke, '" stroked="', !!stroke,
|
1287
|
-
'" style="position:absolute;width:1px;height:1px;">');
|
1288
|
-
|
1289
|
-
if (stroke) {
|
1290
|
-
appendStroke(this, lineStr);
|
1291
|
-
} else {
|
1292
|
-
// TODO: Fix the min and max params.
|
1293
|
-
appendFill(this, lineStr, {x: -left, y: 0},
|
1294
|
-
{x: right, y: fontStyle.size});
|
1295
|
-
}
|
1296
|
-
|
1297
|
-
var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
|
1298
|
-
m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
|
1299
|
-
|
1300
|
-
var skewOffset = mr(d.x / Z + 1 - m[0][0]) + ',' + mr(d.y / Z - 2 * m[1][0]);
|
1301
|
-
|
1302
|
-
|
1303
|
-
lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
|
1304
|
-
' offset="', skewOffset, '" origin="', left ,' 0" />',
|
1305
|
-
'<g_vml_:path textpathok="true" />',
|
1306
|
-
'<g_vml_:textpath on="true" string="',
|
1307
|
-
encodeHtmlAttribute(text),
|
1308
|
-
'" style="v-text-align:', textAlign,
|
1309
|
-
';font:', encodeHtmlAttribute(fontStyleString),
|
1310
|
-
'" /></g_vml_:line>');
|
1311
|
-
|
1312
|
-
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
1313
|
-
};
|
1314
|
-
|
1315
|
-
contextPrototype.fillText = function(text, x, y, maxWidth) {
|
1316
|
-
this.drawText_(text, x, y, maxWidth, false);
|
1317
|
-
};
|
1318
|
-
|
1319
|
-
contextPrototype.strokeText = function(text, x, y, maxWidth) {
|
1320
|
-
this.drawText_(text, x, y, maxWidth, true);
|
1321
|
-
};
|
1322
|
-
|
1323
|
-
contextPrototype.measureText = function(text) {
|
1324
|
-
if (!this.textMeasureEl_) {
|
1325
|
-
var s = '<span style="position:absolute;' +
|
1326
|
-
'top:-20000px;left:0;padding:0;margin:0;border:none;' +
|
1327
|
-
'white-space:pre;"></span>';
|
1328
|
-
this.element_.insertAdjacentHTML('beforeEnd', s);
|
1329
|
-
this.textMeasureEl_ = this.element_.lastChild;
|
1330
|
-
}
|
1331
|
-
var doc = this.element_.ownerDocument;
|
1332
|
-
this.textMeasureEl_.innerHTML = '';
|
1333
|
-
this.textMeasureEl_.style.font = this.font;
|
1334
|
-
// Don't use innerHTML or innerText because they allow markup/whitespace.
|
1335
|
-
this.textMeasureEl_.appendChild(doc.createTextNode(text));
|
1336
|
-
return {width: this.textMeasureEl_.offsetWidth};
|
1337
|
-
};
|
1338
|
-
|
1339
|
-
/******** STUBS ********/
|
1340
|
-
contextPrototype.clip = function() {
|
1341
|
-
// TODO: Implement
|
1342
|
-
};
|
1343
|
-
|
1344
|
-
contextPrototype.arcTo = function() {
|
1345
|
-
// TODO: Implement
|
1346
|
-
};
|
1347
|
-
|
1348
|
-
contextPrototype.createPattern = function(image, repetition) {
|
1349
|
-
return new CanvasPattern_(image, repetition);
|
1350
|
-
};
|
1351
|
-
|
1352
|
-
// Gradient / Pattern Stubs
|
1353
|
-
function CanvasGradient_(aType) {
|
1354
|
-
this.type_ = aType;
|
1355
|
-
this.x0_ = 0;
|
1356
|
-
this.y0_ = 0;
|
1357
|
-
this.r0_ = 0;
|
1358
|
-
this.x1_ = 0;
|
1359
|
-
this.y1_ = 0;
|
1360
|
-
this.r1_ = 0;
|
1361
|
-
this.colors_ = [];
|
1362
|
-
}
|
1363
|
-
|
1364
|
-
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
|
1365
|
-
aColor = processStyle(aColor);
|
1366
|
-
this.colors_.push({offset: aOffset,
|
1367
|
-
color: aColor.color,
|
1368
|
-
alpha: aColor.alpha});
|
1369
|
-
};
|
1370
|
-
|
1371
|
-
function CanvasPattern_(image, repetition) {
|
1372
|
-
assertImageIsValid(image);
|
1373
|
-
switch (repetition) {
|
1374
|
-
case 'repeat':
|
1375
|
-
case null:
|
1376
|
-
case '':
|
1377
|
-
this.repetition_ = 'repeat';
|
1378
|
-
break;
|
1379
|
-
case 'repeat-x':
|
1380
|
-
case 'repeat-y':
|
1381
|
-
case 'no-repeat':
|
1382
|
-
this.repetition_ = repetition;
|
1383
|
-
break;
|
1384
|
-
default:
|
1385
|
-
throwException('SYNTAX_ERR');
|
1386
|
-
}
|
1387
|
-
|
1388
|
-
this.src_ = image.src;
|
1389
|
-
this.width_ = image.width;
|
1390
|
-
this.height_ = image.height;
|
1391
|
-
}
|
1392
|
-
|
1393
|
-
function throwException(s) {
|
1394
|
-
throw new DOMException_(s);
|
1395
|
-
}
|
1396
|
-
|
1397
|
-
function assertImageIsValid(img) {
|
1398
|
-
if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
|
1399
|
-
throwException('TYPE_MISMATCH_ERR');
|
1400
|
-
}
|
1401
|
-
if (img.readyState != 'complete') {
|
1402
|
-
throwException('INVALID_STATE_ERR');
|
1403
|
-
}
|
1404
|
-
}
|
1405
|
-
|
1406
|
-
function DOMException_(s) {
|
1407
|
-
this.code = this[s];
|
1408
|
-
this.message = s +': DOM Exception ' + this.code;
|
1409
|
-
}
|
1410
|
-
var p = DOMException_.prototype = new Error;
|
1411
|
-
p.INDEX_SIZE_ERR = 1;
|
1412
|
-
p.DOMSTRING_SIZE_ERR = 2;
|
1413
|
-
p.HIERARCHY_REQUEST_ERR = 3;
|
1414
|
-
p.WRONG_DOCUMENT_ERR = 4;
|
1415
|
-
p.INVALID_CHARACTER_ERR = 5;
|
1416
|
-
p.NO_DATA_ALLOWED_ERR = 6;
|
1417
|
-
p.NO_MODIFICATION_ALLOWED_ERR = 7;
|
1418
|
-
p.NOT_FOUND_ERR = 8;
|
1419
|
-
p.NOT_SUPPORTED_ERR = 9;
|
1420
|
-
p.INUSE_ATTRIBUTE_ERR = 10;
|
1421
|
-
p.INVALID_STATE_ERR = 11;
|
1422
|
-
p.SYNTAX_ERR = 12;
|
1423
|
-
p.INVALID_MODIFICATION_ERR = 13;
|
1424
|
-
p.NAMESPACE_ERR = 14;
|
1425
|
-
p.INVALID_ACCESS_ERR = 15;
|
1426
|
-
p.VALIDATION_ERR = 16;
|
1427
|
-
p.TYPE_MISMATCH_ERR = 17;
|
1428
|
-
|
1429
|
-
// set up externs
|
1430
|
-
G_vmlCanvasManager = G_vmlCanvasManager_;
|
1431
|
-
CanvasRenderingContext2D = CanvasRenderingContext2D_;
|
1432
|
-
CanvasGradient = CanvasGradient_;
|
1433
|
-
CanvasPattern = CanvasPattern_;
|
1434
|
-
DOMException = DOMException_;
|
1435
|
-
G_vmlCanvasManager._version = 888;
|
1436
|
-
})();
|
1437
|
-
|
1438
|
-
} // if
|
1
|
+
// Memory Leaks patch from http://explorercanvas.googlecode.com/svn/trunk/
|
2
|
+
// svn : r73
|
3
|
+
// ------------------------------------------------------------------
|
4
|
+
// Copyright 2006 Google Inc.
|
5
|
+
//
|
6
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
// you may not use this file except in compliance with the License.
|
8
|
+
// You may obtain a copy of the License at
|
9
|
+
//
|
10
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
//
|
12
|
+
// Unless required by applicable law or agreed to in writing, software
|
13
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
// See the License for the specific language governing permissions and
|
16
|
+
// limitations under the License.
|
17
|
+
|
18
|
+
|
19
|
+
// Known Issues:
|
20
|
+
//
|
21
|
+
// * Patterns only support repeat.
|
22
|
+
// * Radial gradient are not implemented. The VML version of these look very
|
23
|
+
// different from the canvas one.
|
24
|
+
// * Clipping paths are not implemented.
|
25
|
+
// * Coordsize. The width and height attribute have higher priority than the
|
26
|
+
// width and height style values which isn't correct.
|
27
|
+
// * Painting mode isn't implemented.
|
28
|
+
// * Canvas width/height should is using content-box by default. IE in
|
29
|
+
// Quirks mode will draw the canvas using border-box. Either change your
|
30
|
+
// doctype to HTML5
|
31
|
+
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
|
32
|
+
// or use Box Sizing Behavior from WebFX
|
33
|
+
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
|
34
|
+
// * Non uniform scaling does not correctly scale strokes.
|
35
|
+
// * Optimize. There is always room for speed improvements.
|
36
|
+
|
37
|
+
// Only add this code if we do not already have a canvas implementation
|
38
|
+
if (!document.createElement('canvas').getContext) {
|
39
|
+
|
40
|
+
(function() {
|
41
|
+
|
42
|
+
// alias some functions to make (compiled) code shorter
|
43
|
+
var m = Math;
|
44
|
+
var mr = m.round;
|
45
|
+
var ms = m.sin;
|
46
|
+
var mc = m.cos;
|
47
|
+
var abs = m.abs;
|
48
|
+
var sqrt = m.sqrt;
|
49
|
+
|
50
|
+
// this is used for sub pixel precision
|
51
|
+
var Z = 10;
|
52
|
+
var Z2 = Z / 2;
|
53
|
+
|
54
|
+
var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
|
55
|
+
|
56
|
+
/**
|
57
|
+
* This funtion is assigned to the <canvas> elements as element.getContext().
|
58
|
+
* @this {HTMLElement}
|
59
|
+
* @return {CanvasRenderingContext2D_}
|
60
|
+
*/
|
61
|
+
function getContext() {
|
62
|
+
return this.context_ ||
|
63
|
+
(this.context_ = new CanvasRenderingContext2D_(this));
|
64
|
+
}
|
65
|
+
|
66
|
+
var slice = Array.prototype.slice;
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Binds a function to an object. The returned function will always use the
|
70
|
+
* passed in {@code obj} as {@code this}.
|
71
|
+
*
|
72
|
+
* Example:
|
73
|
+
*
|
74
|
+
* g = bind(f, obj, a, b)
|
75
|
+
* g(c, d) // will do f.call(obj, a, b, c, d)
|
76
|
+
*
|
77
|
+
* @param {Function} f The function to bind the object to
|
78
|
+
* @param {Object} obj The object that should act as this when the function
|
79
|
+
* is called
|
80
|
+
* @param {*} var_args Rest arguments that will be used as the initial
|
81
|
+
* arguments when the function is called
|
82
|
+
* @return {Function} A new function that has bound this
|
83
|
+
*/
|
84
|
+
function bind(f, obj, var_args) {
|
85
|
+
var a = slice.call(arguments, 2);
|
86
|
+
return function() {
|
87
|
+
return f.apply(obj, a.concat(slice.call(arguments)));
|
88
|
+
};
|
89
|
+
}
|
90
|
+
|
91
|
+
function encodeHtmlAttribute(s) {
|
92
|
+
return String(s).replace(/&/g, '&').replace(/"/g, '"');
|
93
|
+
}
|
94
|
+
|
95
|
+
function addNamespace(doc, prefix, urn) {
|
96
|
+
if (!doc.namespaces[prefix]) {
|
97
|
+
doc.namespaces.add(prefix, urn, '#default#VML');
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
function addNamespacesAndStylesheet(doc) {
|
102
|
+
addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
|
103
|
+
addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
|
104
|
+
|
105
|
+
// Setup default CSS. Only add one style sheet per document
|
106
|
+
if (!doc.styleSheets['ex_canvas_']) {
|
107
|
+
var ss = doc.createStyleSheet();
|
108
|
+
ss.owningElement.id = 'ex_canvas_';
|
109
|
+
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
|
110
|
+
// default size is 300x150 in Gecko and Opera
|
111
|
+
'text-align:left;width:300px;height:150px}';
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
// Add namespaces and stylesheet at startup.
|
116
|
+
addNamespacesAndStylesheet(document);
|
117
|
+
|
118
|
+
var G_vmlCanvasManager_ = {
|
119
|
+
init: function(opt_doc) {
|
120
|
+
var doc = opt_doc || document;
|
121
|
+
// Create a dummy element so that IE will allow canvas elements to be
|
122
|
+
// recognized.
|
123
|
+
doc.createElement('canvas');
|
124
|
+
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
|
125
|
+
},
|
126
|
+
|
127
|
+
init_: function(doc) {
|
128
|
+
// find all canvas elements
|
129
|
+
var els = doc.getElementsByTagName('canvas');
|
130
|
+
for (var i = 0; i < els.length; i++) {
|
131
|
+
this.initElement(els[i]);
|
132
|
+
}
|
133
|
+
},
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Public initializes a canvas element so that it can be used as canvas
|
137
|
+
* element from now on. This is called automatically before the page is
|
138
|
+
* loaded but if you are creating elements using createElement you need to
|
139
|
+
* make sure this is called on the element.
|
140
|
+
* @param {HTMLElement} el The canvas element to initialize.
|
141
|
+
* @return {HTMLElement} the element that was created.
|
142
|
+
*/
|
143
|
+
initElement: function(el) {
|
144
|
+
if (!el.getContext) {
|
145
|
+
el.getContext = getContext;
|
146
|
+
|
147
|
+
// Add namespaces and stylesheet to document of the element.
|
148
|
+
addNamespacesAndStylesheet(el.ownerDocument);
|
149
|
+
|
150
|
+
// Remove fallback content. There is no way to hide text nodes so we
|
151
|
+
// just remove all childNodes. We could hide all elements and remove
|
152
|
+
// text nodes but who really cares about the fallback content.
|
153
|
+
el.innerHTML = '';
|
154
|
+
|
155
|
+
// do not use inline function because that will leak memory
|
156
|
+
el.attachEvent('onpropertychange', onPropertyChange);
|
157
|
+
el.attachEvent('onresize', onResize);
|
158
|
+
|
159
|
+
var attrs = el.attributes;
|
160
|
+
if (attrs.width && attrs.width.specified) {
|
161
|
+
// TODO: use runtimeStyle and coordsize
|
162
|
+
// el.getContext().setWidth_(attrs.width.nodeValue);
|
163
|
+
el.style.width = attrs.width.nodeValue + 'px';
|
164
|
+
} else {
|
165
|
+
el.width = el.clientWidth;
|
166
|
+
}
|
167
|
+
if (attrs.height && attrs.height.specified) {
|
168
|
+
// TODO: use runtimeStyle and coordsize
|
169
|
+
// el.getContext().setHeight_(attrs.height.nodeValue);
|
170
|
+
el.style.height = attrs.height.nodeValue + 'px';
|
171
|
+
} else {
|
172
|
+
el.height = el.clientHeight;
|
173
|
+
}
|
174
|
+
//el.getContext().setCoordsize_()
|
175
|
+
}
|
176
|
+
return el;
|
177
|
+
},
|
178
|
+
|
179
|
+
// Memory Leaks patch : see http://code.google.com/p/explorercanvas/issues/detail?id=82
|
180
|
+
uninitElement: function(el){
|
181
|
+
if (el.getContext) {
|
182
|
+
var ctx = el.getContext();
|
183
|
+
delete ctx.element_;
|
184
|
+
delete ctx.canvas;
|
185
|
+
el.innerHTML = "";
|
186
|
+
//el.outerHTML = "";
|
187
|
+
el.context_ = null;
|
188
|
+
el.getContext = null;
|
189
|
+
el.detachEvent("onpropertychange", onPropertyChange);
|
190
|
+
el.detachEvent("onresize", onResize);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
};
|
194
|
+
|
195
|
+
function onPropertyChange(e) {
|
196
|
+
var el = e.srcElement;
|
197
|
+
|
198
|
+
switch (e.propertyName) {
|
199
|
+
case 'width':
|
200
|
+
el.getContext().clearRect();
|
201
|
+
el.style.width = el.attributes.width.nodeValue + 'px';
|
202
|
+
// In IE8 this does not trigger onresize.
|
203
|
+
el.firstChild.style.width = el.clientWidth + 'px';
|
204
|
+
break;
|
205
|
+
case 'height':
|
206
|
+
el.getContext().clearRect();
|
207
|
+
el.style.height = el.attributes.height.nodeValue + 'px';
|
208
|
+
el.firstChild.style.height = el.clientHeight + 'px';
|
209
|
+
break;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
function onResize(e) {
|
214
|
+
var el = e.srcElement;
|
215
|
+
if (el.firstChild) {
|
216
|
+
el.firstChild.style.width = el.clientWidth + 'px';
|
217
|
+
el.firstChild.style.height = el.clientHeight + 'px';
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
G_vmlCanvasManager_.init();
|
222
|
+
|
223
|
+
// precompute "00" to "FF"
|
224
|
+
var decToHex = [];
|
225
|
+
for (var i = 0; i < 16; i++) {
|
226
|
+
for (var j = 0; j < 16; j++) {
|
227
|
+
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
function createMatrixIdentity() {
|
232
|
+
return [
|
233
|
+
[1, 0, 0],
|
234
|
+
[0, 1, 0],
|
235
|
+
[0, 0, 1]
|
236
|
+
];
|
237
|
+
}
|
238
|
+
|
239
|
+
function matrixMultiply(m1, m2) {
|
240
|
+
var result = createMatrixIdentity();
|
241
|
+
|
242
|
+
for (var x = 0; x < 3; x++) {
|
243
|
+
for (var y = 0; y < 3; y++) {
|
244
|
+
var sum = 0;
|
245
|
+
|
246
|
+
for (var z = 0; z < 3; z++) {
|
247
|
+
sum += m1[x][z] * m2[z][y];
|
248
|
+
}
|
249
|
+
|
250
|
+
result[x][y] = sum;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
return result;
|
254
|
+
}
|
255
|
+
|
256
|
+
function copyState(o1, o2) {
|
257
|
+
o2.fillStyle = o1.fillStyle;
|
258
|
+
o2.lineCap = o1.lineCap;
|
259
|
+
o2.lineJoin = o1.lineJoin;
|
260
|
+
o2.lineWidth = o1.lineWidth;
|
261
|
+
o2.miterLimit = o1.miterLimit;
|
262
|
+
o2.shadowBlur = o1.shadowBlur;
|
263
|
+
o2.shadowColor = o1.shadowColor;
|
264
|
+
o2.shadowOffsetX = o1.shadowOffsetX;
|
265
|
+
o2.shadowOffsetY = o1.shadowOffsetY;
|
266
|
+
o2.strokeStyle = o1.strokeStyle;
|
267
|
+
o2.globalAlpha = o1.globalAlpha;
|
268
|
+
o2.font = o1.font;
|
269
|
+
o2.textAlign = o1.textAlign;
|
270
|
+
o2.textBaseline = o1.textBaseline;
|
271
|
+
o2.arcScaleX_ = o1.arcScaleX_;
|
272
|
+
o2.arcScaleY_ = o1.arcScaleY_;
|
273
|
+
o2.lineScale_ = o1.lineScale_;
|
274
|
+
}
|
275
|
+
|
276
|
+
var colorData = {
|
277
|
+
aliceblue: '#F0F8FF',
|
278
|
+
antiquewhite: '#FAEBD7',
|
279
|
+
aquamarine: '#7FFFD4',
|
280
|
+
azure: '#F0FFFF',
|
281
|
+
beige: '#F5F5DC',
|
282
|
+
bisque: '#FFE4C4',
|
283
|
+
black: '#000000',
|
284
|
+
blanchedalmond: '#FFEBCD',
|
285
|
+
blueviolet: '#8A2BE2',
|
286
|
+
brown: '#A52A2A',
|
287
|
+
burlywood: '#DEB887',
|
288
|
+
cadetblue: '#5F9EA0',
|
289
|
+
chartreuse: '#7FFF00',
|
290
|
+
chocolate: '#D2691E',
|
291
|
+
coral: '#FF7F50',
|
292
|
+
cornflowerblue: '#6495ED',
|
293
|
+
cornsilk: '#FFF8DC',
|
294
|
+
crimson: '#DC143C',
|
295
|
+
cyan: '#00FFFF',
|
296
|
+
darkblue: '#00008B',
|
297
|
+
darkcyan: '#008B8B',
|
298
|
+
darkgoldenrod: '#B8860B',
|
299
|
+
darkgray: '#A9A9A9',
|
300
|
+
darkgreen: '#006400',
|
301
|
+
darkgrey: '#A9A9A9',
|
302
|
+
darkkhaki: '#BDB76B',
|
303
|
+
darkmagenta: '#8B008B',
|
304
|
+
darkolivegreen: '#556B2F',
|
305
|
+
darkorange: '#FF8C00',
|
306
|
+
darkorchid: '#9932CC',
|
307
|
+
darkred: '#8B0000',
|
308
|
+
darksalmon: '#E9967A',
|
309
|
+
darkseagreen: '#8FBC8F',
|
310
|
+
darkslateblue: '#483D8B',
|
311
|
+
darkslategray: '#2F4F4F',
|
312
|
+
darkslategrey: '#2F4F4F',
|
313
|
+
darkturquoise: '#00CED1',
|
314
|
+
darkviolet: '#9400D3',
|
315
|
+
deeppink: '#FF1493',
|
316
|
+
deepskyblue: '#00BFFF',
|
317
|
+
dimgray: '#696969',
|
318
|
+
dimgrey: '#696969',
|
319
|
+
dodgerblue: '#1E90FF',
|
320
|
+
firebrick: '#B22222',
|
321
|
+
floralwhite: '#FFFAF0',
|
322
|
+
forestgreen: '#228B22',
|
323
|
+
gainsboro: '#DCDCDC',
|
324
|
+
ghostwhite: '#F8F8FF',
|
325
|
+
gold: '#FFD700',
|
326
|
+
goldenrod: '#DAA520',
|
327
|
+
grey: '#808080',
|
328
|
+
greenyellow: '#ADFF2F',
|
329
|
+
honeydew: '#F0FFF0',
|
330
|
+
hotpink: '#FF69B4',
|
331
|
+
indianred: '#CD5C5C',
|
332
|
+
indigo: '#4B0082',
|
333
|
+
ivory: '#FFFFF0',
|
334
|
+
khaki: '#F0E68C',
|
335
|
+
lavender: '#E6E6FA',
|
336
|
+
lavenderblush: '#FFF0F5',
|
337
|
+
lawngreen: '#7CFC00',
|
338
|
+
lemonchiffon: '#FFFACD',
|
339
|
+
lightblue: '#ADD8E6',
|
340
|
+
lightcoral: '#F08080',
|
341
|
+
lightcyan: '#E0FFFF',
|
342
|
+
lightgoldenrodyellow: '#FAFAD2',
|
343
|
+
lightgreen: '#90EE90',
|
344
|
+
lightgrey: '#D3D3D3',
|
345
|
+
lightpink: '#FFB6C1',
|
346
|
+
lightsalmon: '#FFA07A',
|
347
|
+
lightseagreen: '#20B2AA',
|
348
|
+
lightskyblue: '#87CEFA',
|
349
|
+
lightslategray: '#778899',
|
350
|
+
lightslategrey: '#778899',
|
351
|
+
lightsteelblue: '#B0C4DE',
|
352
|
+
lightyellow: '#FFFFE0',
|
353
|
+
limegreen: '#32CD32',
|
354
|
+
linen: '#FAF0E6',
|
355
|
+
magenta: '#FF00FF',
|
356
|
+
mediumaquamarine: '#66CDAA',
|
357
|
+
mediumblue: '#0000CD',
|
358
|
+
mediumorchid: '#BA55D3',
|
359
|
+
mediumpurple: '#9370DB',
|
360
|
+
mediumseagreen: '#3CB371',
|
361
|
+
mediumslateblue: '#7B68EE',
|
362
|
+
mediumspringgreen: '#00FA9A',
|
363
|
+
mediumturquoise: '#48D1CC',
|
364
|
+
mediumvioletred: '#C71585',
|
365
|
+
midnightblue: '#191970',
|
366
|
+
mintcream: '#F5FFFA',
|
367
|
+
mistyrose: '#FFE4E1',
|
368
|
+
moccasin: '#FFE4B5',
|
369
|
+
navajowhite: '#FFDEAD',
|
370
|
+
oldlace: '#FDF5E6',
|
371
|
+
olivedrab: '#6B8E23',
|
372
|
+
orange: '#FFA500',
|
373
|
+
orangered: '#FF4500',
|
374
|
+
orchid: '#DA70D6',
|
375
|
+
palegoldenrod: '#EEE8AA',
|
376
|
+
palegreen: '#98FB98',
|
377
|
+
paleturquoise: '#AFEEEE',
|
378
|
+
palevioletred: '#DB7093',
|
379
|
+
papayawhip: '#FFEFD5',
|
380
|
+
peachpuff: '#FFDAB9',
|
381
|
+
peru: '#CD853F',
|
382
|
+
pink: '#FFC0CB',
|
383
|
+
plum: '#DDA0DD',
|
384
|
+
powderblue: '#B0E0E6',
|
385
|
+
rosybrown: '#BC8F8F',
|
386
|
+
royalblue: '#4169E1',
|
387
|
+
saddlebrown: '#8B4513',
|
388
|
+
salmon: '#FA8072',
|
389
|
+
sandybrown: '#F4A460',
|
390
|
+
seagreen: '#2E8B57',
|
391
|
+
seashell: '#FFF5EE',
|
392
|
+
sienna: '#A0522D',
|
393
|
+
skyblue: '#87CEEB',
|
394
|
+
slateblue: '#6A5ACD',
|
395
|
+
slategray: '#708090',
|
396
|
+
slategrey: '#708090',
|
397
|
+
snow: '#FFFAFA',
|
398
|
+
springgreen: '#00FF7F',
|
399
|
+
steelblue: '#4682B4',
|
400
|
+
tan: '#D2B48C',
|
401
|
+
thistle: '#D8BFD8',
|
402
|
+
tomato: '#FF6347',
|
403
|
+
turquoise: '#40E0D0',
|
404
|
+
violet: '#EE82EE',
|
405
|
+
wheat: '#F5DEB3',
|
406
|
+
whitesmoke: '#F5F5F5',
|
407
|
+
yellowgreen: '#9ACD32'
|
408
|
+
};
|
409
|
+
|
410
|
+
|
411
|
+
function getRgbHslContent(styleString) {
|
412
|
+
var start = styleString.indexOf('(', 3);
|
413
|
+
var end = styleString.indexOf(')', start + 1);
|
414
|
+
var parts = styleString.substring(start + 1, end).split(',');
|
415
|
+
// add alpha if needed
|
416
|
+
if (parts.length != 4 || styleString.charAt(3) != 'a') {
|
417
|
+
parts[3] = 1;
|
418
|
+
}
|
419
|
+
return parts;
|
420
|
+
}
|
421
|
+
|
422
|
+
function percent(s) {
|
423
|
+
return parseFloat(s) / 100;
|
424
|
+
}
|
425
|
+
|
426
|
+
function clamp(v, min, max) {
|
427
|
+
return Math.min(max, Math.max(min, v));
|
428
|
+
}
|
429
|
+
|
430
|
+
function hslToRgb(parts){
|
431
|
+
var r, g, b, h, s, l;
|
432
|
+
h = parseFloat(parts[0]) / 360 % 360;
|
433
|
+
if (h < 0)
|
434
|
+
h++;
|
435
|
+
s = clamp(percent(parts[1]), 0, 1);
|
436
|
+
l = clamp(percent(parts[2]), 0, 1);
|
437
|
+
if (s == 0) {
|
438
|
+
r = g = b = l; // achromatic
|
439
|
+
} else {
|
440
|
+
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
441
|
+
var p = 2 * l - q;
|
442
|
+
r = hueToRgb(p, q, h + 1 / 3);
|
443
|
+
g = hueToRgb(p, q, h);
|
444
|
+
b = hueToRgb(p, q, h - 1 / 3);
|
445
|
+
}
|
446
|
+
|
447
|
+
return '#' + decToHex[Math.floor(r * 255)] +
|
448
|
+
decToHex[Math.floor(g * 255)] +
|
449
|
+
decToHex[Math.floor(b * 255)];
|
450
|
+
}
|
451
|
+
|
452
|
+
function hueToRgb(m1, m2, h) {
|
453
|
+
if (h < 0)
|
454
|
+
h++;
|
455
|
+
if (h > 1)
|
456
|
+
h--;
|
457
|
+
|
458
|
+
if (6 * h < 1)
|
459
|
+
return m1 + (m2 - m1) * 6 * h;
|
460
|
+
else if (2 * h < 1)
|
461
|
+
return m2;
|
462
|
+
else if (3 * h < 2)
|
463
|
+
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
464
|
+
else
|
465
|
+
return m1;
|
466
|
+
}
|
467
|
+
|
468
|
+
var processStyleCache = {};
|
469
|
+
|
470
|
+
function processStyle(styleString) {
|
471
|
+
if (styleString in processStyleCache) {
|
472
|
+
return processStyleCache[styleString];
|
473
|
+
}
|
474
|
+
|
475
|
+
var str, alpha = 1;
|
476
|
+
|
477
|
+
styleString = String(styleString);
|
478
|
+
if (styleString.charAt(0) == '#') {
|
479
|
+
str = styleString;
|
480
|
+
} else if (/^rgb/.test(styleString)) {
|
481
|
+
var parts = getRgbHslContent(styleString);
|
482
|
+
var str = '#', n;
|
483
|
+
for (var i = 0; i < 3; i++) {
|
484
|
+
if (parts[i].indexOf('%') != -1) {
|
485
|
+
n = Math.floor(percent(parts[i]) * 255);
|
486
|
+
} else {
|
487
|
+
n = +parts[i];
|
488
|
+
}
|
489
|
+
str += decToHex[clamp(n, 0, 255)];
|
490
|
+
}
|
491
|
+
alpha = +parts[3];
|
492
|
+
} else if (/^hsl/.test(styleString)) {
|
493
|
+
var parts = getRgbHslContent(styleString);
|
494
|
+
str = hslToRgb(parts);
|
495
|
+
alpha = parts[3];
|
496
|
+
} else {
|
497
|
+
str = colorData[styleString] || styleString;
|
498
|
+
}
|
499
|
+
return processStyleCache[styleString] = {color: str, alpha: alpha};
|
500
|
+
}
|
501
|
+
|
502
|
+
var DEFAULT_STYLE = {
|
503
|
+
style: 'normal',
|
504
|
+
variant: 'normal',
|
505
|
+
weight: 'normal',
|
506
|
+
size: 10,
|
507
|
+
family: 'sans-serif'
|
508
|
+
};
|
509
|
+
|
510
|
+
// Internal text style cache
|
511
|
+
var fontStyleCache = {};
|
512
|
+
|
513
|
+
function processFontStyle(styleString) {
|
514
|
+
if (fontStyleCache[styleString]) {
|
515
|
+
return fontStyleCache[styleString];
|
516
|
+
}
|
517
|
+
|
518
|
+
var el = document.createElement('div');
|
519
|
+
var style = el.style;
|
520
|
+
try {
|
521
|
+
style.font = styleString;
|
522
|
+
} catch (ex) {
|
523
|
+
// Ignore failures to set to invalid font.
|
524
|
+
}
|
525
|
+
|
526
|
+
return fontStyleCache[styleString] = {
|
527
|
+
style: style.fontStyle || DEFAULT_STYLE.style,
|
528
|
+
variant: style.fontVariant || DEFAULT_STYLE.variant,
|
529
|
+
weight: style.fontWeight || DEFAULT_STYLE.weight,
|
530
|
+
size: style.fontSize || DEFAULT_STYLE.size,
|
531
|
+
family: style.fontFamily || DEFAULT_STYLE.family
|
532
|
+
};
|
533
|
+
}
|
534
|
+
|
535
|
+
function getComputedStyle(style, element) {
|
536
|
+
var computedStyle = {};
|
537
|
+
|
538
|
+
for (var p in style) {
|
539
|
+
computedStyle[p] = style[p];
|
540
|
+
}
|
541
|
+
|
542
|
+
// Compute the size
|
543
|
+
var canvasFontSize = parseFloat(element.currentStyle.fontSize),
|
544
|
+
fontSize = parseFloat(style.size);
|
545
|
+
|
546
|
+
if (typeof style.size == 'number') {
|
547
|
+
computedStyle.size = style.size;
|
548
|
+
} else if (style.size.indexOf('px') != -1) {
|
549
|
+
computedStyle.size = fontSize;
|
550
|
+
} else if (style.size.indexOf('em') != -1) {
|
551
|
+
computedStyle.size = canvasFontSize * fontSize;
|
552
|
+
} else if(style.size.indexOf('%') != -1) {
|
553
|
+
computedStyle.size = (canvasFontSize / 100) * fontSize;
|
554
|
+
} else if (style.size.indexOf('pt') != -1) {
|
555
|
+
computedStyle.size = fontSize / .75;
|
556
|
+
} else {
|
557
|
+
computedStyle.size = canvasFontSize;
|
558
|
+
}
|
559
|
+
|
560
|
+
// Different scaling between normal text and VML text. This was found using
|
561
|
+
// trial and error to get the same size as non VML text.
|
562
|
+
computedStyle.size *= 0.981;
|
563
|
+
|
564
|
+
// Fix for VML handling of bare font family names. Add a '' around font family names.
|
565
|
+
computedStyle.family = "'" + computedStyle.family.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
|
566
|
+
|
567
|
+
return computedStyle;
|
568
|
+
}
|
569
|
+
|
570
|
+
function buildStyle(style) {
|
571
|
+
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
|
572
|
+
style.size + 'px ' + style.family;
|
573
|
+
}
|
574
|
+
|
575
|
+
var lineCapMap = {
|
576
|
+
'butt': 'flat',
|
577
|
+
'round': 'round'
|
578
|
+
};
|
579
|
+
|
580
|
+
function processLineCap(lineCap) {
|
581
|
+
return lineCapMap[lineCap] || 'square';
|
582
|
+
}
|
583
|
+
|
584
|
+
/**
|
585
|
+
* This class implements CanvasRenderingContext2D interface as described by
|
586
|
+
* the WHATWG.
|
587
|
+
* @param {HTMLElement} canvasElement The element that the 2D context should
|
588
|
+
* be associated with
|
589
|
+
*/
|
590
|
+
function CanvasRenderingContext2D_(canvasElement) {
|
591
|
+
this.m_ = createMatrixIdentity();
|
592
|
+
|
593
|
+
this.mStack_ = [];
|
594
|
+
this.aStack_ = [];
|
595
|
+
this.currentPath_ = [];
|
596
|
+
|
597
|
+
// Canvas context properties
|
598
|
+
this.strokeStyle = '#000';
|
599
|
+
this.fillStyle = '#000';
|
600
|
+
|
601
|
+
this.lineWidth = 1;
|
602
|
+
this.lineJoin = 'miter';
|
603
|
+
this.lineCap = 'butt';
|
604
|
+
this.miterLimit = Z * 1;
|
605
|
+
this.globalAlpha = 1;
|
606
|
+
this.font = '10px sans-serif';
|
607
|
+
this.textAlign = 'left';
|
608
|
+
this.textBaseline = 'alphabetic';
|
609
|
+
this.canvas = canvasElement;
|
610
|
+
|
611
|
+
var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
|
612
|
+
canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
|
613
|
+
var el = canvasElement.ownerDocument.createElement('div');
|
614
|
+
el.style.cssText = cssText;
|
615
|
+
canvasElement.appendChild(el);
|
616
|
+
|
617
|
+
var overlayEl = el.cloneNode(false);
|
618
|
+
// Use a non transparent background.
|
619
|
+
overlayEl.style.backgroundColor = 'red';
|
620
|
+
overlayEl.style.filter = 'alpha(opacity=0)';
|
621
|
+
canvasElement.appendChild(overlayEl);
|
622
|
+
|
623
|
+
this.element_ = el;
|
624
|
+
this.arcScaleX_ = 1;
|
625
|
+
this.arcScaleY_ = 1;
|
626
|
+
this.lineScale_ = 1;
|
627
|
+
}
|
628
|
+
|
629
|
+
var contextPrototype = CanvasRenderingContext2D_.prototype;
|
630
|
+
contextPrototype.clearRect = function() {
|
631
|
+
if (this.textMeasureEl_) {
|
632
|
+
this.textMeasureEl_.removeNode(true);
|
633
|
+
this.textMeasureEl_ = null;
|
634
|
+
}
|
635
|
+
this.element_.innerHTML = '';
|
636
|
+
};
|
637
|
+
|
638
|
+
contextPrototype.beginPath = function() {
|
639
|
+
// TODO: Branch current matrix so that save/restore has no effect
|
640
|
+
// as per safari docs.
|
641
|
+
this.currentPath_ = [];
|
642
|
+
};
|
643
|
+
|
644
|
+
contextPrototype.moveTo = function(aX, aY) {
|
645
|
+
var p = getCoords(this, aX, aY);
|
646
|
+
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
|
647
|
+
this.currentX_ = p.x;
|
648
|
+
this.currentY_ = p.y;
|
649
|
+
};
|
650
|
+
|
651
|
+
contextPrototype.lineTo = function(aX, aY) {
|
652
|
+
var p = getCoords(this, aX, aY);
|
653
|
+
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
|
654
|
+
|
655
|
+
this.currentX_ = p.x;
|
656
|
+
this.currentY_ = p.y;
|
657
|
+
};
|
658
|
+
|
659
|
+
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
|
660
|
+
aCP2x, aCP2y,
|
661
|
+
aX, aY) {
|
662
|
+
var p = getCoords(this, aX, aY);
|
663
|
+
var cp1 = getCoords(this, aCP1x, aCP1y);
|
664
|
+
var cp2 = getCoords(this, aCP2x, aCP2y);
|
665
|
+
bezierCurveTo(this, cp1, cp2, p);
|
666
|
+
};
|
667
|
+
|
668
|
+
// Helper function that takes the already fixed cordinates.
|
669
|
+
function bezierCurveTo(self, cp1, cp2, p) {
|
670
|
+
self.currentPath_.push({
|
671
|
+
type: 'bezierCurveTo',
|
672
|
+
cp1x: cp1.x,
|
673
|
+
cp1y: cp1.y,
|
674
|
+
cp2x: cp2.x,
|
675
|
+
cp2y: cp2.y,
|
676
|
+
x: p.x,
|
677
|
+
y: p.y
|
678
|
+
});
|
679
|
+
self.currentX_ = p.x;
|
680
|
+
self.currentY_ = p.y;
|
681
|
+
}
|
682
|
+
|
683
|
+
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
|
684
|
+
// the following is lifted almost directly from
|
685
|
+
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
|
686
|
+
|
687
|
+
var cp = getCoords(this, aCPx, aCPy);
|
688
|
+
var p = getCoords(this, aX, aY);
|
689
|
+
|
690
|
+
var cp1 = {
|
691
|
+
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
|
692
|
+
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
|
693
|
+
};
|
694
|
+
var cp2 = {
|
695
|
+
x: cp1.x + (p.x - this.currentX_) / 3.0,
|
696
|
+
y: cp1.y + (p.y - this.currentY_) / 3.0
|
697
|
+
};
|
698
|
+
|
699
|
+
bezierCurveTo(this, cp1, cp2, p);
|
700
|
+
};
|
701
|
+
|
702
|
+
contextPrototype.arc = function(aX, aY, aRadius,
|
703
|
+
aStartAngle, aEndAngle, aClockwise) {
|
704
|
+
aRadius *= Z;
|
705
|
+
var arcType = aClockwise ? 'at' : 'wa';
|
706
|
+
|
707
|
+
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
|
708
|
+
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
|
709
|
+
|
710
|
+
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
|
711
|
+
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
|
712
|
+
|
713
|
+
// IE won't render arches drawn counter clockwise if xStart == xEnd.
|
714
|
+
if (xStart == xEnd && !aClockwise) {
|
715
|
+
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
|
716
|
+
// that can be represented in binary
|
717
|
+
}
|
718
|
+
|
719
|
+
var p = getCoords(this, aX, aY);
|
720
|
+
var pStart = getCoords(this, xStart, yStart);
|
721
|
+
var pEnd = getCoords(this, xEnd, yEnd);
|
722
|
+
|
723
|
+
this.currentPath_.push({type: arcType,
|
724
|
+
x: p.x,
|
725
|
+
y: p.y,
|
726
|
+
radius: aRadius,
|
727
|
+
xStart: pStart.x,
|
728
|
+
yStart: pStart.y,
|
729
|
+
xEnd: pEnd.x,
|
730
|
+
yEnd: pEnd.y});
|
731
|
+
|
732
|
+
};
|
733
|
+
|
734
|
+
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
|
735
|
+
this.moveTo(aX, aY);
|
736
|
+
this.lineTo(aX + aWidth, aY);
|
737
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
738
|
+
this.lineTo(aX, aY + aHeight);
|
739
|
+
this.closePath();
|
740
|
+
};
|
741
|
+
|
742
|
+
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
|
743
|
+
var oldPath = this.currentPath_;
|
744
|
+
this.beginPath();
|
745
|
+
|
746
|
+
this.moveTo(aX, aY);
|
747
|
+
this.lineTo(aX + aWidth, aY);
|
748
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
749
|
+
this.lineTo(aX, aY + aHeight);
|
750
|
+
this.closePath();
|
751
|
+
this.stroke();
|
752
|
+
|
753
|
+
this.currentPath_ = oldPath;
|
754
|
+
};
|
755
|
+
|
756
|
+
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
|
757
|
+
var oldPath = this.currentPath_;
|
758
|
+
this.beginPath();
|
759
|
+
|
760
|
+
this.moveTo(aX, aY);
|
761
|
+
this.lineTo(aX + aWidth, aY);
|
762
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
763
|
+
this.lineTo(aX, aY + aHeight);
|
764
|
+
this.closePath();
|
765
|
+
this.fill();
|
766
|
+
|
767
|
+
this.currentPath_ = oldPath;
|
768
|
+
};
|
769
|
+
|
770
|
+
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
|
771
|
+
var gradient = new CanvasGradient_('gradient');
|
772
|
+
gradient.x0_ = aX0;
|
773
|
+
gradient.y0_ = aY0;
|
774
|
+
gradient.x1_ = aX1;
|
775
|
+
gradient.y1_ = aY1;
|
776
|
+
return gradient;
|
777
|
+
};
|
778
|
+
|
779
|
+
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
|
780
|
+
aX1, aY1, aR1) {
|
781
|
+
var gradient = new CanvasGradient_('gradientradial');
|
782
|
+
gradient.x0_ = aX0;
|
783
|
+
gradient.y0_ = aY0;
|
784
|
+
gradient.r0_ = aR0;
|
785
|
+
gradient.x1_ = aX1;
|
786
|
+
gradient.y1_ = aY1;
|
787
|
+
gradient.r1_ = aR1;
|
788
|
+
return gradient;
|
789
|
+
};
|
790
|
+
|
791
|
+
contextPrototype.drawImage = function(image, var_args) {
|
792
|
+
var dx, dy, dw, dh, sx, sy, sw, sh;
|
793
|
+
|
794
|
+
// to find the original width we overide the width and height
|
795
|
+
var oldRuntimeWidth = image.runtimeStyle.width;
|
796
|
+
var oldRuntimeHeight = image.runtimeStyle.height;
|
797
|
+
image.runtimeStyle.width = 'auto';
|
798
|
+
image.runtimeStyle.height = 'auto';
|
799
|
+
|
800
|
+
// get the original size
|
801
|
+
var w = image.width;
|
802
|
+
var h = image.height;
|
803
|
+
|
804
|
+
// and remove overides
|
805
|
+
image.runtimeStyle.width = oldRuntimeWidth;
|
806
|
+
image.runtimeStyle.height = oldRuntimeHeight;
|
807
|
+
|
808
|
+
if (arguments.length == 3) {
|
809
|
+
dx = arguments[1];
|
810
|
+
dy = arguments[2];
|
811
|
+
sx = sy = 0;
|
812
|
+
sw = dw = w;
|
813
|
+
sh = dh = h;
|
814
|
+
} else if (arguments.length == 5) {
|
815
|
+
dx = arguments[1];
|
816
|
+
dy = arguments[2];
|
817
|
+
dw = arguments[3];
|
818
|
+
dh = arguments[4];
|
819
|
+
sx = sy = 0;
|
820
|
+
sw = w;
|
821
|
+
sh = h;
|
822
|
+
} else if (arguments.length == 9) {
|
823
|
+
sx = arguments[1];
|
824
|
+
sy = arguments[2];
|
825
|
+
sw = arguments[3];
|
826
|
+
sh = arguments[4];
|
827
|
+
dx = arguments[5];
|
828
|
+
dy = arguments[6];
|
829
|
+
dw = arguments[7];
|
830
|
+
dh = arguments[8];
|
831
|
+
} else {
|
832
|
+
throw Error('Invalid number of arguments');
|
833
|
+
}
|
834
|
+
|
835
|
+
var d = getCoords(this, dx, dy);
|
836
|
+
|
837
|
+
var w2 = sw / 2;
|
838
|
+
var h2 = sh / 2;
|
839
|
+
|
840
|
+
var vmlStr = [];
|
841
|
+
|
842
|
+
var W = 10;
|
843
|
+
var H = 10;
|
844
|
+
|
845
|
+
// For some reason that I've now forgotten, using divs didn't work
|
846
|
+
vmlStr.push(' <g_vml_:group',
|
847
|
+
' coordsize="', Z * W, ',', Z * H, '"',
|
848
|
+
' coordorigin="0,0"' ,
|
849
|
+
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
|
850
|
+
|
851
|
+
// If filters are necessary (rotation exists), create them
|
852
|
+
// filters are bog-slow, so only create them if abbsolutely necessary
|
853
|
+
// The following check doesn't account for skews (which don't exist
|
854
|
+
// in the canvas spec (yet) anyway.
|
855
|
+
|
856
|
+
if (this.m_[0][0] != 1 || this.m_[0][1] ||
|
857
|
+
this.m_[1][1] != 1 || this.m_[1][0]) {
|
858
|
+
var filter = [];
|
859
|
+
|
860
|
+
// Note the 12/21 reversal
|
861
|
+
filter.push('M11=', this.m_[0][0], ',',
|
862
|
+
'M12=', this.m_[1][0], ',',
|
863
|
+
'M21=', this.m_[0][1], ',',
|
864
|
+
'M22=', this.m_[1][1], ',',
|
865
|
+
'Dx=', mr(d.x / Z), ',',
|
866
|
+
'Dy=', mr(d.y / Z), '');
|
867
|
+
|
868
|
+
// Bounding box calculation (need to minimize displayed area so that
|
869
|
+
// filters don't waste time on unused pixels.
|
870
|
+
var max = d;
|
871
|
+
var c2 = getCoords(this, dx + dw, dy);
|
872
|
+
var c3 = getCoords(this, dx, dy + dh);
|
873
|
+
var c4 = getCoords(this, dx + dw, dy + dh);
|
874
|
+
|
875
|
+
max.x = m.max(max.x, c2.x, c3.x, c4.x);
|
876
|
+
max.y = m.max(max.y, c2.y, c3.y, c4.y);
|
877
|
+
|
878
|
+
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
|
879
|
+
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
|
880
|
+
filter.join(''), ", sizingmethod='clip');");
|
881
|
+
|
882
|
+
} else {
|
883
|
+
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
|
884
|
+
}
|
885
|
+
|
886
|
+
vmlStr.push(' ">' ,
|
887
|
+
'<g_vml_:image src="', image.src, '"',
|
888
|
+
' style="width:', Z * dw, 'px;',
|
889
|
+
' height:', Z * dh, 'px"',
|
890
|
+
' cropleft="', sx / w, '"',
|
891
|
+
' croptop="', sy / h, '"',
|
892
|
+
' cropright="', (w - sx - sw) / w, '"',
|
893
|
+
' cropbottom="', (h - sy - sh) / h, '"',
|
894
|
+
' />',
|
895
|
+
'</g_vml_:group>');
|
896
|
+
|
897
|
+
this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
|
898
|
+
};
|
899
|
+
|
900
|
+
contextPrototype.stroke = function(aFill) {
|
901
|
+
var lineStr = [];
|
902
|
+
var lineOpen = false;
|
903
|
+
|
904
|
+
var W = 10;
|
905
|
+
var H = 10;
|
906
|
+
|
907
|
+
lineStr.push('<g_vml_:shape',
|
908
|
+
' filled="', !!aFill, '"',
|
909
|
+
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
|
910
|
+
' coordorigin="0,0"',
|
911
|
+
' coordsize="', Z * W, ',', Z * H, '"',
|
912
|
+
' stroked="', !aFill, '"',
|
913
|
+
' path="');
|
914
|
+
|
915
|
+
var newSeq = false;
|
916
|
+
var min = {x: null, y: null};
|
917
|
+
var max = {x: null, y: null};
|
918
|
+
|
919
|
+
for (var i = 0; i < this.currentPath_.length; i++) {
|
920
|
+
var p = this.currentPath_[i];
|
921
|
+
var c;
|
922
|
+
|
923
|
+
switch (p.type) {
|
924
|
+
case 'moveTo':
|
925
|
+
c = p;
|
926
|
+
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
|
927
|
+
break;
|
928
|
+
case 'lineTo':
|
929
|
+
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
|
930
|
+
break;
|
931
|
+
case 'close':
|
932
|
+
lineStr.push(' x ');
|
933
|
+
p = null;
|
934
|
+
break;
|
935
|
+
case 'bezierCurveTo':
|
936
|
+
lineStr.push(' c ',
|
937
|
+
mr(p.cp1x), ',', mr(p.cp1y), ',',
|
938
|
+
mr(p.cp2x), ',', mr(p.cp2y), ',',
|
939
|
+
mr(p.x), ',', mr(p.y));
|
940
|
+
break;
|
941
|
+
case 'at':
|
942
|
+
case 'wa':
|
943
|
+
lineStr.push(' ', p.type, ' ',
|
944
|
+
mr(p.x - this.arcScaleX_ * p.radius), ',',
|
945
|
+
mr(p.y - this.arcScaleY_ * p.radius), ' ',
|
946
|
+
mr(p.x + this.arcScaleX_ * p.radius), ',',
|
947
|
+
mr(p.y + this.arcScaleY_ * p.radius), ' ',
|
948
|
+
mr(p.xStart), ',', mr(p.yStart), ' ',
|
949
|
+
mr(p.xEnd), ',', mr(p.yEnd));
|
950
|
+
break;
|
951
|
+
}
|
952
|
+
|
953
|
+
|
954
|
+
// TODO: Following is broken for curves due to
|
955
|
+
// move to proper paths.
|
956
|
+
|
957
|
+
// Figure out dimensions so we can do gradient fills
|
958
|
+
// properly
|
959
|
+
if (p) {
|
960
|
+
if (min.x == null || p.x < min.x) {
|
961
|
+
min.x = p.x;
|
962
|
+
}
|
963
|
+
if (max.x == null || p.x > max.x) {
|
964
|
+
max.x = p.x;
|
965
|
+
}
|
966
|
+
if (min.y == null || p.y < min.y) {
|
967
|
+
min.y = p.y;
|
968
|
+
}
|
969
|
+
if (max.y == null || p.y > max.y) {
|
970
|
+
max.y = p.y;
|
971
|
+
}
|
972
|
+
}
|
973
|
+
}
|
974
|
+
lineStr.push(' ">');
|
975
|
+
|
976
|
+
if (!aFill) {
|
977
|
+
appendStroke(this, lineStr);
|
978
|
+
} else {
|
979
|
+
appendFill(this, lineStr, min, max);
|
980
|
+
}
|
981
|
+
|
982
|
+
lineStr.push('</g_vml_:shape>');
|
983
|
+
|
984
|
+
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
985
|
+
};
|
986
|
+
|
987
|
+
function appendStroke(ctx, lineStr) {
|
988
|
+
var a = processStyle(ctx.strokeStyle);
|
989
|
+
var color = a.color;
|
990
|
+
var opacity = a.alpha * ctx.globalAlpha;
|
991
|
+
var lineWidth = ctx.lineScale_ * ctx.lineWidth;
|
992
|
+
|
993
|
+
// VML cannot correctly render a line if the width is less than 1px.
|
994
|
+
// In that case, we dilute the color to make the line look thinner.
|
995
|
+
if (lineWidth < 1) {
|
996
|
+
opacity *= lineWidth;
|
997
|
+
}
|
998
|
+
|
999
|
+
lineStr.push(
|
1000
|
+
'<g_vml_:stroke',
|
1001
|
+
' opacity="', opacity, '"',
|
1002
|
+
' joinstyle="', ctx.lineJoin, '"',
|
1003
|
+
' miterlimit="', ctx.miterLimit, '"',
|
1004
|
+
' endcap="', processLineCap(ctx.lineCap), '"',
|
1005
|
+
' weight="', lineWidth, 'px"',
|
1006
|
+
' color="', color, '" />'
|
1007
|
+
);
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
function appendFill(ctx, lineStr, min, max) {
|
1011
|
+
var fillStyle = ctx.fillStyle;
|
1012
|
+
var arcScaleX = ctx.arcScaleX_;
|
1013
|
+
var arcScaleY = ctx.arcScaleY_;
|
1014
|
+
var width = max.x - min.x;
|
1015
|
+
var height = max.y - min.y;
|
1016
|
+
if (fillStyle instanceof CanvasGradient_) {
|
1017
|
+
// TODO: Gradients transformed with the transformation matrix.
|
1018
|
+
var angle = 0;
|
1019
|
+
var focus = {x: 0, y: 0};
|
1020
|
+
|
1021
|
+
// additional offset
|
1022
|
+
var shift = 0;
|
1023
|
+
// scale factor for offset
|
1024
|
+
var expansion = 1;
|
1025
|
+
|
1026
|
+
if (fillStyle.type_ == 'gradient') {
|
1027
|
+
var x0 = fillStyle.x0_ / arcScaleX;
|
1028
|
+
var y0 = fillStyle.y0_ / arcScaleY;
|
1029
|
+
var x1 = fillStyle.x1_ / arcScaleX;
|
1030
|
+
var y1 = fillStyle.y1_ / arcScaleY;
|
1031
|
+
var p0 = getCoords(ctx, x0, y0);
|
1032
|
+
var p1 = getCoords(ctx, x1, y1);
|
1033
|
+
var dx = p1.x - p0.x;
|
1034
|
+
var dy = p1.y - p0.y;
|
1035
|
+
angle = Math.atan2(dx, dy) * 180 / Math.PI;
|
1036
|
+
|
1037
|
+
// The angle should be a non-negative number.
|
1038
|
+
if (angle < 0) {
|
1039
|
+
angle += 360;
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
// Very small angles produce an unexpected result because they are
|
1043
|
+
// converted to a scientific notation string.
|
1044
|
+
if (angle < 1e-6) {
|
1045
|
+
angle = 0;
|
1046
|
+
}
|
1047
|
+
} else {
|
1048
|
+
var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
|
1049
|
+
focus = {
|
1050
|
+
x: (p0.x - min.x) / width,
|
1051
|
+
y: (p0.y - min.y) / height
|
1052
|
+
};
|
1053
|
+
|
1054
|
+
width /= arcScaleX * Z;
|
1055
|
+
height /= arcScaleY * Z;
|
1056
|
+
var dimension = m.max(width, height);
|
1057
|
+
shift = 2 * fillStyle.r0_ / dimension;
|
1058
|
+
expansion = 2 * fillStyle.r1_ / dimension - shift;
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
// We need to sort the color stops in ascending order by offset,
|
1062
|
+
// otherwise IE won't interpret it correctly.
|
1063
|
+
var stops = fillStyle.colors_;
|
1064
|
+
stops.sort(function(cs1, cs2) {
|
1065
|
+
return cs1.offset - cs2.offset;
|
1066
|
+
});
|
1067
|
+
|
1068
|
+
var length = stops.length;
|
1069
|
+
var color1 = stops[0].color;
|
1070
|
+
var color2 = stops[length - 1].color;
|
1071
|
+
var opacity1 = stops[0].alpha * ctx.globalAlpha;
|
1072
|
+
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
|
1073
|
+
|
1074
|
+
var colors = [];
|
1075
|
+
for (var i = 0; i < length; i++) {
|
1076
|
+
var stop = stops[i];
|
1077
|
+
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
// When colors attribute is used, the meanings of opacity and o:opacity2
|
1081
|
+
// are reversed.
|
1082
|
+
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
|
1083
|
+
' method="none" focus="100%"',
|
1084
|
+
' color="', color1, '"',
|
1085
|
+
' color2="', color2, '"',
|
1086
|
+
' colors="', colors.join(','), '"',
|
1087
|
+
' opacity="', opacity2, '"',
|
1088
|
+
' g_o_:opacity2="', opacity1, '"',
|
1089
|
+
' angle="', angle, '"',
|
1090
|
+
' focusposition="', focus.x, ',', focus.y, '" />');
|
1091
|
+
} else if (fillStyle instanceof CanvasPattern_) {
|
1092
|
+
if (width && height) {
|
1093
|
+
var deltaLeft = -min.x;
|
1094
|
+
var deltaTop = -min.y;
|
1095
|
+
lineStr.push('<g_vml_:fill',
|
1096
|
+
' position="',
|
1097
|
+
deltaLeft / width * arcScaleX * arcScaleX, ',',
|
1098
|
+
deltaTop / height * arcScaleY * arcScaleY, '"',
|
1099
|
+
' type="tile"',
|
1100
|
+
// TODO: Figure out the correct size to fit the scale.
|
1101
|
+
//' size="', w, 'px ', h, 'px"',
|
1102
|
+
' src="', fillStyle.src_, '" />');
|
1103
|
+
}
|
1104
|
+
} else {
|
1105
|
+
var a = processStyle(ctx.fillStyle);
|
1106
|
+
var color = a.color;
|
1107
|
+
var opacity = a.alpha * ctx.globalAlpha;
|
1108
|
+
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
|
1109
|
+
'" />');
|
1110
|
+
}
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
contextPrototype.fill = function() {
|
1114
|
+
this.stroke(true);
|
1115
|
+
};
|
1116
|
+
|
1117
|
+
contextPrototype.closePath = function() {
|
1118
|
+
this.currentPath_.push({type: 'close'});
|
1119
|
+
};
|
1120
|
+
|
1121
|
+
function getCoords(ctx, aX, aY) {
|
1122
|
+
var m = ctx.m_;
|
1123
|
+
return {
|
1124
|
+
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
|
1125
|
+
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
|
1126
|
+
};
|
1127
|
+
};
|
1128
|
+
|
1129
|
+
contextPrototype.save = function() {
|
1130
|
+
var o = {};
|
1131
|
+
copyState(this, o);
|
1132
|
+
this.aStack_.push(o);
|
1133
|
+
this.mStack_.push(this.m_);
|
1134
|
+
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
|
1135
|
+
};
|
1136
|
+
|
1137
|
+
contextPrototype.restore = function() {
|
1138
|
+
if (this.aStack_.length) {
|
1139
|
+
copyState(this.aStack_.pop(), this);
|
1140
|
+
this.m_ = this.mStack_.pop();
|
1141
|
+
}
|
1142
|
+
};
|
1143
|
+
|
1144
|
+
function matrixIsFinite(m) {
|
1145
|
+
return isFinite(m[0][0]) && isFinite(m[0][1]) &&
|
1146
|
+
isFinite(m[1][0]) && isFinite(m[1][1]) &&
|
1147
|
+
isFinite(m[2][0]) && isFinite(m[2][1]);
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
function setM(ctx, m, updateLineScale) {
|
1151
|
+
if (!matrixIsFinite(m)) {
|
1152
|
+
return;
|
1153
|
+
}
|
1154
|
+
ctx.m_ = m;
|
1155
|
+
|
1156
|
+
if (updateLineScale) {
|
1157
|
+
// Get the line scale.
|
1158
|
+
// Determinant of this.m_ means how much the area is enlarged by the
|
1159
|
+
// transformation. So its square root can be used as a scale factor
|
1160
|
+
// for width.
|
1161
|
+
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
1162
|
+
ctx.lineScale_ = sqrt(abs(det));
|
1163
|
+
}
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
contextPrototype.translate = function(aX, aY) {
|
1167
|
+
var m1 = [
|
1168
|
+
[1, 0, 0],
|
1169
|
+
[0, 1, 0],
|
1170
|
+
[aX, aY, 1]
|
1171
|
+
];
|
1172
|
+
|
1173
|
+
setM(this, matrixMultiply(m1, this.m_), false);
|
1174
|
+
};
|
1175
|
+
|
1176
|
+
contextPrototype.rotate = function(aRot) {
|
1177
|
+
var c = mc(aRot);
|
1178
|
+
var s = ms(aRot);
|
1179
|
+
|
1180
|
+
var m1 = [
|
1181
|
+
[c, s, 0],
|
1182
|
+
[-s, c, 0],
|
1183
|
+
[0, 0, 1]
|
1184
|
+
];
|
1185
|
+
|
1186
|
+
setM(this, matrixMultiply(m1, this.m_), false);
|
1187
|
+
};
|
1188
|
+
|
1189
|
+
contextPrototype.scale = function(aX, aY) {
|
1190
|
+
this.arcScaleX_ *= aX;
|
1191
|
+
this.arcScaleY_ *= aY;
|
1192
|
+
var m1 = [
|
1193
|
+
[aX, 0, 0],
|
1194
|
+
[0, aY, 0],
|
1195
|
+
[0, 0, 1]
|
1196
|
+
];
|
1197
|
+
|
1198
|
+
setM(this, matrixMultiply(m1, this.m_), true);
|
1199
|
+
};
|
1200
|
+
|
1201
|
+
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
|
1202
|
+
var m1 = [
|
1203
|
+
[m11, m12, 0],
|
1204
|
+
[m21, m22, 0],
|
1205
|
+
[dx, dy, 1]
|
1206
|
+
];
|
1207
|
+
|
1208
|
+
setM(this, matrixMultiply(m1, this.m_), true);
|
1209
|
+
};
|
1210
|
+
|
1211
|
+
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
|
1212
|
+
var m = [
|
1213
|
+
[m11, m12, 0],
|
1214
|
+
[m21, m22, 0],
|
1215
|
+
[dx, dy, 1]
|
1216
|
+
];
|
1217
|
+
|
1218
|
+
setM(this, m, true);
|
1219
|
+
};
|
1220
|
+
|
1221
|
+
/**
|
1222
|
+
* The text drawing function.
|
1223
|
+
* The maxWidth argument isn't taken in account, since no browser supports
|
1224
|
+
* it yet.
|
1225
|
+
*/
|
1226
|
+
contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
|
1227
|
+
var m = this.m_,
|
1228
|
+
delta = 1000,
|
1229
|
+
left = 0,
|
1230
|
+
right = delta,
|
1231
|
+
offset = {x: 0, y: 0},
|
1232
|
+
lineStr = [];
|
1233
|
+
|
1234
|
+
var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_);
|
1235
|
+
|
1236
|
+
var fontStyleString = buildStyle(fontStyle);
|
1237
|
+
|
1238
|
+
var elementStyle = this.element_.currentStyle;
|
1239
|
+
var textAlign = this.textAlign.toLowerCase();
|
1240
|
+
switch (textAlign) {
|
1241
|
+
case 'left':
|
1242
|
+
case 'center':
|
1243
|
+
case 'right':
|
1244
|
+
break;
|
1245
|
+
case 'end':
|
1246
|
+
textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
|
1247
|
+
break;
|
1248
|
+
case 'start':
|
1249
|
+
textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
|
1250
|
+
break;
|
1251
|
+
default:
|
1252
|
+
textAlign = 'left';
|
1253
|
+
}
|
1254
|
+
|
1255
|
+
// 1.75 is an arbitrary number, as there is no info about the text baseline
|
1256
|
+
switch (this.textBaseline) {
|
1257
|
+
case 'hanging':
|
1258
|
+
case 'top':
|
1259
|
+
offset.y = fontStyle.size / 1.75;
|
1260
|
+
break;
|
1261
|
+
case 'middle':
|
1262
|
+
break;
|
1263
|
+
default:
|
1264
|
+
case null:
|
1265
|
+
case 'alphabetic':
|
1266
|
+
case 'ideographic':
|
1267
|
+
case 'bottom':
|
1268
|
+
offset.y = -fontStyle.size / 2.25;
|
1269
|
+
break;
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
switch(textAlign) {
|
1273
|
+
case 'right':
|
1274
|
+
left = delta;
|
1275
|
+
right = 0.05;
|
1276
|
+
break;
|
1277
|
+
case 'center':
|
1278
|
+
left = right = delta / 2;
|
1279
|
+
break;
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
var d = getCoords(this, x + offset.x, y + offset.y);
|
1283
|
+
|
1284
|
+
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
|
1285
|
+
' coordsize="100 100" coordorigin="0 0"',
|
1286
|
+
' filled="', !stroke, '" stroked="', !!stroke,
|
1287
|
+
'" style="position:absolute;width:1px;height:1px;">');
|
1288
|
+
|
1289
|
+
if (stroke) {
|
1290
|
+
appendStroke(this, lineStr);
|
1291
|
+
} else {
|
1292
|
+
// TODO: Fix the min and max params.
|
1293
|
+
appendFill(this, lineStr, {x: -left, y: 0},
|
1294
|
+
{x: right, y: fontStyle.size});
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
|
1298
|
+
m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
|
1299
|
+
|
1300
|
+
var skewOffset = mr(d.x / Z + 1 - m[0][0]) + ',' + mr(d.y / Z - 2 * m[1][0]);
|
1301
|
+
|
1302
|
+
|
1303
|
+
lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
|
1304
|
+
' offset="', skewOffset, '" origin="', left ,' 0" />',
|
1305
|
+
'<g_vml_:path textpathok="true" />',
|
1306
|
+
'<g_vml_:textpath on="true" string="',
|
1307
|
+
encodeHtmlAttribute(text),
|
1308
|
+
'" style="v-text-align:', textAlign,
|
1309
|
+
';font:', encodeHtmlAttribute(fontStyleString),
|
1310
|
+
'" /></g_vml_:line>');
|
1311
|
+
|
1312
|
+
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
1313
|
+
};
|
1314
|
+
|
1315
|
+
contextPrototype.fillText = function(text, x, y, maxWidth) {
|
1316
|
+
this.drawText_(text, x, y, maxWidth, false);
|
1317
|
+
};
|
1318
|
+
|
1319
|
+
contextPrototype.strokeText = function(text, x, y, maxWidth) {
|
1320
|
+
this.drawText_(text, x, y, maxWidth, true);
|
1321
|
+
};
|
1322
|
+
|
1323
|
+
contextPrototype.measureText = function(text) {
|
1324
|
+
if (!this.textMeasureEl_) {
|
1325
|
+
var s = '<span style="position:absolute;' +
|
1326
|
+
'top:-20000px;left:0;padding:0;margin:0;border:none;' +
|
1327
|
+
'white-space:pre;"></span>';
|
1328
|
+
this.element_.insertAdjacentHTML('beforeEnd', s);
|
1329
|
+
this.textMeasureEl_ = this.element_.lastChild;
|
1330
|
+
}
|
1331
|
+
var doc = this.element_.ownerDocument;
|
1332
|
+
this.textMeasureEl_.innerHTML = '';
|
1333
|
+
this.textMeasureEl_.style.font = this.font;
|
1334
|
+
// Don't use innerHTML or innerText because they allow markup/whitespace.
|
1335
|
+
this.textMeasureEl_.appendChild(doc.createTextNode(text));
|
1336
|
+
return {width: this.textMeasureEl_.offsetWidth};
|
1337
|
+
};
|
1338
|
+
|
1339
|
+
/******** STUBS ********/
|
1340
|
+
contextPrototype.clip = function() {
|
1341
|
+
// TODO: Implement
|
1342
|
+
};
|
1343
|
+
|
1344
|
+
contextPrototype.arcTo = function() {
|
1345
|
+
// TODO: Implement
|
1346
|
+
};
|
1347
|
+
|
1348
|
+
contextPrototype.createPattern = function(image, repetition) {
|
1349
|
+
return new CanvasPattern_(image, repetition);
|
1350
|
+
};
|
1351
|
+
|
1352
|
+
// Gradient / Pattern Stubs
|
1353
|
+
function CanvasGradient_(aType) {
|
1354
|
+
this.type_ = aType;
|
1355
|
+
this.x0_ = 0;
|
1356
|
+
this.y0_ = 0;
|
1357
|
+
this.r0_ = 0;
|
1358
|
+
this.x1_ = 0;
|
1359
|
+
this.y1_ = 0;
|
1360
|
+
this.r1_ = 0;
|
1361
|
+
this.colors_ = [];
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
|
1365
|
+
aColor = processStyle(aColor);
|
1366
|
+
this.colors_.push({offset: aOffset,
|
1367
|
+
color: aColor.color,
|
1368
|
+
alpha: aColor.alpha});
|
1369
|
+
};
|
1370
|
+
|
1371
|
+
function CanvasPattern_(image, repetition) {
|
1372
|
+
assertImageIsValid(image);
|
1373
|
+
switch (repetition) {
|
1374
|
+
case 'repeat':
|
1375
|
+
case null:
|
1376
|
+
case '':
|
1377
|
+
this.repetition_ = 'repeat';
|
1378
|
+
break;
|
1379
|
+
case 'repeat-x':
|
1380
|
+
case 'repeat-y':
|
1381
|
+
case 'no-repeat':
|
1382
|
+
this.repetition_ = repetition;
|
1383
|
+
break;
|
1384
|
+
default:
|
1385
|
+
throwException('SYNTAX_ERR');
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
this.src_ = image.src;
|
1389
|
+
this.width_ = image.width;
|
1390
|
+
this.height_ = image.height;
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
function throwException(s) {
|
1394
|
+
throw new DOMException_(s);
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
function assertImageIsValid(img) {
|
1398
|
+
if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
|
1399
|
+
throwException('TYPE_MISMATCH_ERR');
|
1400
|
+
}
|
1401
|
+
if (img.readyState != 'complete') {
|
1402
|
+
throwException('INVALID_STATE_ERR');
|
1403
|
+
}
|
1404
|
+
}
|
1405
|
+
|
1406
|
+
function DOMException_(s) {
|
1407
|
+
this.code = this[s];
|
1408
|
+
this.message = s +': DOM Exception ' + this.code;
|
1409
|
+
}
|
1410
|
+
var p = DOMException_.prototype = new Error;
|
1411
|
+
p.INDEX_SIZE_ERR = 1;
|
1412
|
+
p.DOMSTRING_SIZE_ERR = 2;
|
1413
|
+
p.HIERARCHY_REQUEST_ERR = 3;
|
1414
|
+
p.WRONG_DOCUMENT_ERR = 4;
|
1415
|
+
p.INVALID_CHARACTER_ERR = 5;
|
1416
|
+
p.NO_DATA_ALLOWED_ERR = 6;
|
1417
|
+
p.NO_MODIFICATION_ALLOWED_ERR = 7;
|
1418
|
+
p.NOT_FOUND_ERR = 8;
|
1419
|
+
p.NOT_SUPPORTED_ERR = 9;
|
1420
|
+
p.INUSE_ATTRIBUTE_ERR = 10;
|
1421
|
+
p.INVALID_STATE_ERR = 11;
|
1422
|
+
p.SYNTAX_ERR = 12;
|
1423
|
+
p.INVALID_MODIFICATION_ERR = 13;
|
1424
|
+
p.NAMESPACE_ERR = 14;
|
1425
|
+
p.INVALID_ACCESS_ERR = 15;
|
1426
|
+
p.VALIDATION_ERR = 16;
|
1427
|
+
p.TYPE_MISMATCH_ERR = 17;
|
1428
|
+
|
1429
|
+
// set up externs
|
1430
|
+
G_vmlCanvasManager = G_vmlCanvasManager_;
|
1431
|
+
CanvasRenderingContext2D = CanvasRenderingContext2D_;
|
1432
|
+
CanvasGradient = CanvasGradient_;
|
1433
|
+
CanvasPattern = CanvasPattern_;
|
1434
|
+
DOMException = DOMException_;
|
1435
|
+
G_vmlCanvasManager._version = 888;
|
1436
|
+
})();
|
1437
|
+
|
1438
|
+
} // if
|