reportbuilder 1.2.5 → 1.3.0

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.
Files changed (392) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +6 -0
  3. data/Manifest.txt +377 -0
  4. data/data/flot/API.txt +1024 -0
  5. data/data/flot/FAQ.txt +71 -0
  6. data/data/flot/LICENSE.txt +22 -0
  7. data/data/flot/Makefile +15 -0
  8. data/data/flot/NEWS.txt +340 -0
  9. data/data/flot/PLUGINS.txt +105 -0
  10. data/data/flot/README.txt +81 -0
  11. data/data/flot/examples/ajax.html +143 -0
  12. data/data/flot/examples/annotating.html +75 -0
  13. data/data/flot/examples/arrow-down.gif +0 -0
  14. data/data/flot/examples/arrow-left.gif +0 -0
  15. data/data/flot/examples/arrow-right.gif +0 -0
  16. data/data/flot/examples/arrow-up.gif +0 -0
  17. data/data/flot/examples/basic.html +38 -0
  18. data/data/flot/examples/data-eu-gdp-growth-1.json +4 -0
  19. data/data/flot/examples/data-eu-gdp-growth-2.json +4 -0
  20. data/data/flot/examples/data-eu-gdp-growth-3.json +4 -0
  21. data/data/flot/examples/data-eu-gdp-growth-4.json +4 -0
  22. data/data/flot/examples/data-eu-gdp-growth-5.json +4 -0
  23. data/data/flot/examples/data-eu-gdp-growth.json +4 -0
  24. data/data/flot/examples/data-japan-gdp-growth.json +4 -0
  25. data/data/flot/examples/data-usa-gdp-growth.json +4 -0
  26. data/data/flot/examples/dual-axis.html +39 -0
  27. data/data/flot/examples/graph-types.html +75 -0
  28. data/data/flot/examples/hs-2004-27-a-large_web.jpg +0 -0
  29. data/data/flot/examples/image.html +45 -0
  30. data/data/flot/examples/index.html +43 -0
  31. data/data/flot/examples/interacting.html +93 -0
  32. data/data/flot/examples/layout.css +6 -0
  33. data/data/flot/examples/navigate.html +118 -0
  34. data/data/flot/examples/selection.html +114 -0
  35. data/data/flot/examples/setting-options.html +65 -0
  36. data/data/flot/examples/stacking.html +77 -0
  37. data/data/flot/examples/thresholding.html +54 -0
  38. data/data/flot/examples/time.html +71 -0
  39. data/data/flot/examples/tracking.html +95 -0
  40. data/data/flot/examples/turning-series.html +98 -0
  41. data/data/flot/examples/visitors.html +90 -0
  42. data/data/flot/examples/zooming.html +98 -0
  43. data/data/flot/excanvas.js +1427 -0
  44. data/data/flot/excanvas.min.js +1 -0
  45. data/data/flot/jquery.colorhelpers.js +174 -0
  46. data/data/flot/jquery.colorhelpers.min.js +1 -0
  47. data/data/flot/jquery.flot.crosshair.js +156 -0
  48. data/data/flot/jquery.flot.crosshair.min.js +1 -0
  49. data/data/flot/jquery.flot.image.js +237 -0
  50. data/data/flot/jquery.flot.image.min.js +1 -0
  51. data/data/flot/jquery.flot.js +2119 -0
  52. data/data/flot/jquery.flot.min.js +1 -0
  53. data/data/flot/jquery.flot.navigate.js +272 -0
  54. data/data/flot/jquery.flot.navigate.min.js +1 -0
  55. data/data/flot/jquery.flot.selection.js +299 -0
  56. data/data/flot/jquery.flot.selection.min.js +1 -0
  57. data/data/flot/jquery.flot.stack.js +152 -0
  58. data/data/flot/jquery.flot.stack.min.js +1 -0
  59. data/data/flot/jquery.flot.threshold.js +103 -0
  60. data/data/flot/jquery.flot.threshold.min.js +1 -0
  61. data/data/flot/jquery.js +4376 -0
  62. data/data/flot/jquery.min.js +19 -0
  63. data/data/jqplot/MIT-LICENSE.txt +21 -0
  64. data/data/jqplot/README.txt +73 -0
  65. data/data/jqplot/changes.txt +261 -0
  66. data/data/jqplot/copyright.txt +33 -0
  67. data/data/jqplot/docs/files/MIT-LICENSE-txt.html +39 -0
  68. data/data/jqplot/docs/files/changes-txt.html +39 -0
  69. data/data/jqplot/docs/files/gpl-2-0-txt.html +39 -0
  70. data/data/jqplot/docs/files/images/background.jpg +0 -0
  71. data/data/jqplot/docs/files/images/basicline.png +0 -0
  72. data/data/jqplot/docs/files/images/basiclogaxis.png +0 -0
  73. data/data/jqplot/docs/files/images/basiclogoptions.png +0 -0
  74. data/data/jqplot/docs/files/images/basicoptions.png +0 -0
  75. data/data/jqplot/docs/files/images/dualaxis.png +0 -0
  76. data/data/jqplot/docs/files/images/logo.jpg +0 -0
  77. data/data/jqplot/docs/files/images/navdocs.png +0 -0
  78. data/data/jqplot/docs/files/images/navdocsover.png +0 -0
  79. data/data/jqplot/docs/files/images/navdownload.png +0 -0
  80. data/data/jqplot/docs/files/images/navdownloadover.png +0 -0
  81. data/data/jqplot/docs/files/images/navexamples.png +0 -0
  82. data/data/jqplot/docs/files/images/navexamplesover.png +0 -0
  83. data/data/jqplot/docs/files/images/navhome.png +0 -0
  84. data/data/jqplot/docs/files/images/navhomeover.png +0 -0
  85. data/data/jqplot/docs/files/images/new.png +0 -0
  86. data/data/jqplot/docs/files/images/sample3.png +0 -0
  87. data/data/jqplot/docs/files/images/samplesm.png +0 -0
  88. data/data/jqplot/docs/files/jqPlotCssStyling-txt.html +39 -0
  89. data/data/jqplot/docs/files/jqPlotOptions-txt.html +292 -0
  90. data/data/jqplot/docs/files/jqplot-axisLabelRenderer-js.html +47 -0
  91. data/data/jqplot/docs/files/jqplot-axisTickRenderer-js.html +69 -0
  92. data/data/jqplot/docs/files/jqplot-canvasGridRenderer-js.html +39 -0
  93. data/data/jqplot/docs/files/jqplot-core-js.html +353 -0
  94. data/data/jqplot/docs/files/jqplot-divTitleRenderer-js.html +39 -0
  95. data/data/jqplot/docs/files/jqplot-lineRenderer-js.html +53 -0
  96. data/data/jqplot/docs/files/jqplot-linearAxisRenderer-js.html +39 -0
  97. data/data/jqplot/docs/files/jqplot-markerRenderer-js.html +65 -0
  98. data/data/jqplot/docs/files/jqplot-shadowRenderer-js.html +61 -0
  99. data/data/jqplot/docs/files/jqplot-shapeRenderer-js.html +63 -0
  100. data/data/jqplot/docs/files/jqplot-themeEngine-js.html +190 -0
  101. data/data/jqplot/docs/files/optionsTutorial-txt.html +119 -0
  102. data/data/jqplot/docs/files/plugins/jqplot-BezierCurveRenderer-js.html +45 -0
  103. data/data/jqplot/docs/files/plugins/jqplot-barRenderer-js.html +67 -0
  104. data/data/jqplot/docs/files/plugins/jqplot-blockRenderer-js.html +53 -0
  105. data/data/jqplot/docs/files/plugins/jqplot-bubbleRenderer-js.html +71 -0
  106. data/data/jqplot/docs/files/plugins/jqplot-canvasAxisLabelRenderer-js.html +63 -0
  107. data/data/jqplot/docs/files/plugins/jqplot-canvasAxisTickRenderer-js.html +79 -0
  108. data/data/jqplot/docs/files/plugins/jqplot-categoryAxisRenderer-js.html +46 -0
  109. data/data/jqplot/docs/files/plugins/jqplot-cursor-js.html +91 -0
  110. data/data/jqplot/docs/files/plugins/jqplot-dateAxisRenderer-js.html +93 -0
  111. data/data/jqplot/docs/files/plugins/jqplot-donutRenderer-js.html +98 -0
  112. data/data/jqplot/docs/files/plugins/jqplot-dragable-js.html +45 -0
  113. data/data/jqplot/docs/files/plugins/jqplot-enhancedLegendRenderer-js.html +49 -0
  114. data/data/jqplot/docs/files/plugins/jqplot-funnelRenderer-js.html +87 -0
  115. data/data/jqplot/docs/files/plugins/jqplot-highlighter-js.html +80 -0
  116. data/data/jqplot/docs/files/plugins/jqplot-logAxisRenderer-js.html +45 -0
  117. data/data/jqplot/docs/files/plugins/jqplot-mekkoAxisRenderer-js.html +49 -0
  118. data/data/jqplot/docs/files/plugins/jqplot-mekkoRenderer-js.html +62 -0
  119. data/data/jqplot/docs/files/plugins/jqplot-meterGaugeRenderer-js.html +103 -0
  120. data/data/jqplot/docs/files/plugins/jqplot-ohlcRenderer-js.html +65 -0
  121. data/data/jqplot/docs/files/plugins/jqplot-pieRenderer-js.html +93 -0
  122. data/data/jqplot/docs/files/plugins/jqplot-pointLabels-js.html +72 -0
  123. data/data/jqplot/docs/files/plugins/jqplot-trendline-js.html +67 -0
  124. data/data/jqplot/docs/files/usage-txt.html +58 -0
  125. data/data/jqplot/docs/index.html +1 -0
  126. data/data/jqplot/docs/index/Classes.html +58 -0
  127. data/data/jqplot/docs/index/Files.html +34 -0
  128. data/data/jqplot/docs/index/Functions.html +66 -0
  129. data/data/jqplot/docs/index/General.html +46 -0
  130. data/data/jqplot/docs/index/General2.html +46 -0
  131. data/data/jqplot/docs/index/General3.html +46 -0
  132. data/data/jqplot/docs/index/General4.html +50 -0
  133. data/data/jqplot/docs/index/General5.html +34 -0
  134. data/data/jqplot/docs/index/General6.html +58 -0
  135. data/data/jqplot/docs/index/Hooks.html +46 -0
  136. data/data/jqplot/docs/index/Properties.html +50 -0
  137. data/data/jqplot/docs/index/Properties2.html +50 -0
  138. data/data/jqplot/docs/index/Properties3.html +50 -0
  139. data/data/jqplot/docs/index/Properties4.html +34 -0
  140. data/data/jqplot/docs/index/Properties5.html +58 -0
  141. data/data/jqplot/docs/javascript/main.js +836 -0
  142. data/data/jqplot/docs/javascript/searchdata.js +182 -0
  143. data/data/jqplot/docs/search/ClassesA.html +20 -0
  144. data/data/jqplot/docs/search/ClassesG.html +20 -0
  145. data/data/jqplot/docs/search/ClassesJ.html +20 -0
  146. data/data/jqplot/docs/search/ClassesL.html +20 -0
  147. data/data/jqplot/docs/search/ClassesS.html +20 -0
  148. data/data/jqplot/docs/search/ClassesSymbols.html +20 -0
  149. data/data/jqplot/docs/search/ClassesT.html +20 -0
  150. data/data/jqplot/docs/search/FilesJ.html +20 -0
  151. data/data/jqplot/docs/search/FunctionsC.html +20 -0
  152. data/data/jqplot/docs/search/FunctionsD.html +20 -0
  153. data/data/jqplot/docs/search/FunctionsG.html +20 -0
  154. data/data/jqplot/docs/search/FunctionsI.html +20 -0
  155. data/data/jqplot/docs/search/FunctionsM.html +20 -0
  156. data/data/jqplot/docs/search/FunctionsN.html +20 -0
  157. data/data/jqplot/docs/search/FunctionsR.html +20 -0
  158. data/data/jqplot/docs/search/FunctionsS.html +20 -0
  159. data/data/jqplot/docs/search/FunctionsZ.html +20 -0
  160. data/data/jqplot/docs/search/GeneralA.html +20 -0
  161. data/data/jqplot/docs/search/GeneralB.html +20 -0
  162. data/data/jqplot/docs/search/GeneralC.html +20 -0
  163. data/data/jqplot/docs/search/GeneralD.html +20 -0
  164. data/data/jqplot/docs/search/GeneralE.html +20 -0
  165. data/data/jqplot/docs/search/GeneralF.html +20 -0
  166. data/data/jqplot/docs/search/GeneralG.html +20 -0
  167. data/data/jqplot/docs/search/GeneralH.html +20 -0
  168. data/data/jqplot/docs/search/GeneralI.html +20 -0
  169. data/data/jqplot/docs/search/GeneralJ.html +20 -0
  170. data/data/jqplot/docs/search/GeneralL.html +20 -0
  171. data/data/jqplot/docs/search/GeneralM.html +20 -0
  172. data/data/jqplot/docs/search/GeneralN.html +20 -0
  173. data/data/jqplot/docs/search/GeneralO.html +20 -0
  174. data/data/jqplot/docs/search/GeneralP.html +20 -0
  175. data/data/jqplot/docs/search/GeneralR.html +20 -0
  176. data/data/jqplot/docs/search/GeneralS.html +20 -0
  177. data/data/jqplot/docs/search/GeneralSymbols.html +20 -0
  178. data/data/jqplot/docs/search/GeneralT.html +20 -0
  179. data/data/jqplot/docs/search/GeneralU.html +20 -0
  180. data/data/jqplot/docs/search/GeneralV.html +20 -0
  181. data/data/jqplot/docs/search/GeneralW.html +20 -0
  182. data/data/jqplot/docs/search/GeneralX.html +20 -0
  183. data/data/jqplot/docs/search/GeneralY.html +20 -0
  184. data/data/jqplot/docs/search/GeneralZ.html +20 -0
  185. data/data/jqplot/docs/search/HooksA.html +20 -0
  186. data/data/jqplot/docs/search/HooksE.html +20 -0
  187. data/data/jqplot/docs/search/HooksJ.html +20 -0
  188. data/data/jqplot/docs/search/HooksP.html +20 -0
  189. data/data/jqplot/docs/search/NoResults.html +15 -0
  190. data/data/jqplot/docs/search/PropertiesA.html +20 -0
  191. data/data/jqplot/docs/search/PropertiesB.html +20 -0
  192. data/data/jqplot/docs/search/PropertiesC.html +20 -0
  193. data/data/jqplot/docs/search/PropertiesD.html +20 -0
  194. data/data/jqplot/docs/search/PropertiesE.html +20 -0
  195. data/data/jqplot/docs/search/PropertiesF.html +20 -0
  196. data/data/jqplot/docs/search/PropertiesG.html +20 -0
  197. data/data/jqplot/docs/search/PropertiesH.html +20 -0
  198. data/data/jqplot/docs/search/PropertiesI.html +20 -0
  199. data/data/jqplot/docs/search/PropertiesL.html +20 -0
  200. data/data/jqplot/docs/search/PropertiesM.html +20 -0
  201. data/data/jqplot/docs/search/PropertiesN.html +20 -0
  202. data/data/jqplot/docs/search/PropertiesO.html +20 -0
  203. data/data/jqplot/docs/search/PropertiesP.html +20 -0
  204. data/data/jqplot/docs/search/PropertiesR.html +20 -0
  205. data/data/jqplot/docs/search/PropertiesS.html +20 -0
  206. data/data/jqplot/docs/search/PropertiesT.html +20 -0
  207. data/data/jqplot/docs/search/PropertiesU.html +20 -0
  208. data/data/jqplot/docs/search/PropertiesV.html +20 -0
  209. data/data/jqplot/docs/search/PropertiesW.html +20 -0
  210. data/data/jqplot/docs/search/PropertiesX.html +20 -0
  211. data/data/jqplot/docs/search/PropertiesY.html +20 -0
  212. data/data/jqplot/docs/search/PropertiesZ.html +20 -0
  213. data/data/jqplot/docs/styles/1.css +767 -0
  214. data/data/jqplot/docs/styles/2.css +174 -0
  215. data/data/jqplot/docs/styles/main.css +2 -0
  216. data/data/jqplot/examples/.htaccess +1 -0
  217. data/data/jqplot/examples/OHLC.html +333 -0
  218. data/data/jqplot/examples/OHLC2.html +193 -0
  219. data/data/jqplot/examples/area.html +107 -0
  220. data/data/jqplot/examples/axisLabel.html +117 -0
  221. data/data/jqplot/examples/axisLabelsRotatedText.html +131 -0
  222. data/data/jqplot/examples/axisLabelsRotatedText2.html +155 -0
  223. data/data/jqplot/examples/barLinePieStack.html +198 -0
  224. data/data/jqplot/examples/barMissingValues.html +64 -0
  225. data/data/jqplot/examples/barTest.html +283 -0
  226. data/data/jqplot/examples/barTest2.html +74 -0
  227. data/data/jqplot/examples/bezierCurve.html +96 -0
  228. data/data/jqplot/examples/blockPlot.html +149 -0
  229. data/data/jqplot/examples/bubbleChart2.html +253 -0
  230. data/data/jqplot/examples/bubblechart.html +69 -0
  231. data/data/jqplot/examples/catchError.html +53 -0
  232. data/data/jqplot/examples/categoryHorizontalBar.html +81 -0
  233. data/data/jqplot/examples/categoryVsLinearAxes.html +74 -0
  234. data/data/jqplot/examples/chartInTable.html +33 -0
  235. data/data/jqplot/examples/customHighlighterCursorTrendline.html +72 -0
  236. data/data/jqplot/examples/customPieTests.html +73 -0
  237. data/data/jqplot/examples/dataLabels.html +192 -0
  238. data/data/jqplot/examples/dataTracking.html +91 -0
  239. data/data/jqplot/examples/donutTest.html +89 -0
  240. data/data/jqplot/examples/donutTest.js +96 -0
  241. data/data/jqplot/examples/examples.css +19 -0
  242. data/data/jqplot/examples/fillToZero.html +126 -0
  243. data/data/jqplot/examples/filledLine.html +78 -0
  244. data/data/jqplot/examples/filledLineCategoryAxis.html +80 -0
  245. data/data/jqplot/examples/funnelTest.html +82 -0
  246. data/data/jqplot/examples/funnelTest.js +74 -0
  247. data/data/jqplot/examples/gridCustomization.html +56 -0
  248. data/data/jqplot/examples/hiddenPlot.html +216 -0
  249. data/data/jqplot/examples/highlighter.html +95 -0
  250. data/data/jqplot/examples/highlighter2.html +63 -0
  251. data/data/jqplot/examples/horizontalLine.html +51 -0
  252. data/data/jqplot/examples/intticks.html +178 -0
  253. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  254. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  255. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
  256. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  257. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  258. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  259. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  260. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  261. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  262. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
  263. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
  264. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
  265. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
  266. data/data/jqplot/examples/jquery-ui/css/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
  267. data/data/jqplot/examples/jquery-ui/css/ui-lightness/jquery-ui-1.8.1.custom.css +486 -0
  268. data/data/jqplot/examples/jquery-ui/js/jquery-1.4.2.min.js +154 -0
  269. data/data/jqplot/examples/jquery-ui/js/jquery-ui-1.8.1.custom.min.js +756 -0
  270. data/data/jqplot/examples/legendLabels.html +205 -0
  271. data/data/jqplot/examples/legendLabels2.html +228 -0
  272. data/data/jqplot/examples/liz.zip +0 -0
  273. data/data/jqplot/examples/markerStyles.html +44 -0
  274. data/data/jqplot/examples/mekkoChart.html +217 -0
  275. data/data/jqplot/examples/meterGauge.html +132 -0
  276. data/data/jqplot/examples/meterGauge2.html +158 -0
  277. data/data/jqplot/examples/minMaxLines.html +61 -0
  278. data/data/jqplot/examples/missingValues.html +119 -0
  279. data/data/jqplot/examples/multiAxesRotatedText.html +70 -0
  280. data/data/jqplot/examples/multipleBarColors.html +149 -0
  281. data/data/jqplot/examples/multipleLines.html +47 -0
  282. data/data/jqplot/examples/multipleYAxes.html +85 -0
  283. data/data/jqplot/examples/nav.inc +35 -0
  284. data/data/jqplot/examples/pieTest.html +77 -0
  285. data/data/jqplot/examples/pieTest2.html +87 -0
  286. data/data/jqplot/examples/pieTest2.js +80 -0
  287. data/data/jqplot/examples/pieTest3.html +100 -0
  288. data/data/jqplot/examples/pointLabels.html +94 -0
  289. data/data/jqplot/examples/pointLabels2.html +47 -0
  290. data/data/jqplot/examples/prefix.html +90 -0
  291. data/data/jqplot/examples/resizablePlot.html +150 -0
  292. data/data/jqplot/examples/rotatedTickLabels.html +61 -0
  293. data/data/jqplot/examples/rotatedTickLabelsZoom.html +68 -0
  294. data/data/jqplot/examples/seriesCanvasReorder.html +93 -0
  295. data/data/jqplot/examples/seriesUpdate.html +123 -0
  296. data/data/jqplot/examples/shadowTests.html +133 -0
  297. data/data/jqplot/examples/singlePoint.html +70 -0
  298. data/data/jqplot/examples/sparkLine.html +48 -0
  299. data/data/jqplot/examples/stackedBar2.html +104 -0
  300. data/data/jqplot/examples/stackedBar3.html +76 -0
  301. data/data/jqplot/examples/stackedBarCategoryVsLinearAxes.html +121 -0
  302. data/data/jqplot/examples/stackedCategoryAxis.html +89 -0
  303. data/data/jqplot/examples/stackedFilledLine.html +77 -0
  304. data/data/jqplot/examples/stackedLine.html +56 -0
  305. data/data/jqplot/examples/test2.html +64 -0
  306. data/data/jqplot/examples/theming.html +483 -0
  307. data/data/jqplot/examples/trendlineDragableCustomization.html +79 -0
  308. data/data/jqplot/examples/verticalLine.html +52 -0
  309. data/data/jqplot/examples/waterfall.html +135 -0
  310. data/data/jqplot/examples/zoom1.html +125 -0
  311. data/data/jqplot/examples/zoom2.html +73 -0
  312. data/data/jqplot/examples/zoom3.html +69 -0
  313. data/data/jqplot/examples/zoomOptions.html +101 -0
  314. data/data/jqplot/examples/zoomProxy.html +108 -0
  315. data/data/jqplot/excanvas.js +1416 -0
  316. data/data/jqplot/excanvas.min.js +35 -0
  317. data/data/jqplot/gpl-2.0.txt +280 -0
  318. data/data/jqplot/jqPlotCssStyling.txt +53 -0
  319. data/data/jqplot/jqPlotOptions.txt +276 -0
  320. data/data/jqplot/jquery-1.4.1.min.js +152 -0
  321. data/data/jqplot/jquery-1.4.2.min.js +154 -0
  322. data/data/jqplot/jquery.jqplot.css +212 -0
  323. data/data/jqplot/jquery.jqplot.js +7004 -0
  324. data/data/jqplot/jquery.jqplot.min.css +1 -0
  325. data/data/jqplot/jquery.jqplot.min.js +34 -0
  326. data/data/jqplot/optionsTutorial.txt +239 -0
  327. data/data/jqplot/plugins/jqplot.BezierCurveRenderer.js +300 -0
  328. data/data/jqplot/plugins/jqplot.BezierCurveRenderer.min.js +34 -0
  329. data/data/jqplot/plugins/jqplot.barRenderer.js +629 -0
  330. data/data/jqplot/plugins/jqplot.barRenderer.min.js +34 -0
  331. data/data/jqplot/plugins/jqplot.blockRenderer.js +221 -0
  332. data/data/jqplot/plugins/jqplot.blockRenderer.min.js +34 -0
  333. data/data/jqplot/plugins/jqplot.bubbleRenderer.js +724 -0
  334. data/data/jqplot/plugins/jqplot.bubbleRenderer.min.js +34 -0
  335. data/data/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js +187 -0
  336. data/data/jqplot/plugins/jqplot.canvasAxisLabelRenderer.min.js +34 -0
  337. data/data/jqplot/plugins/jqplot.canvasAxisTickRenderer.js +226 -0
  338. data/data/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js +34 -0
  339. data/data/jqplot/plugins/jqplot.canvasTextRenderer.js +408 -0
  340. data/data/jqplot/plugins/jqplot.canvasTextRenderer.min.js +34 -0
  341. data/data/jqplot/plugins/jqplot.categoryAxisRenderer.js +630 -0
  342. data/data/jqplot/plugins/jqplot.categoryAxisRenderer.min.js +34 -0
  343. data/data/jqplot/plugins/jqplot.cursor.js +952 -0
  344. data/data/jqplot/plugins/jqplot.cursor.min.js +34 -0
  345. data/data/jqplot/plugins/jqplot.dateAxisRenderer.js +313 -0
  346. data/data/jqplot/plugins/jqplot.dateAxisRenderer.min.js +34 -0
  347. data/data/jqplot/plugins/jqplot.donutRenderer.js +876 -0
  348. data/data/jqplot/plugins/jqplot.donutRenderer.min.js +34 -0
  349. data/data/jqplot/plugins/jqplot.dragable.js +206 -0
  350. data/data/jqplot/plugins/jqplot.dragable.min.js +34 -0
  351. data/data/jqplot/plugins/jqplot.enhancedLegendRenderer.js +186 -0
  352. data/data/jqplot/plugins/jqplot.enhancedLegendRenderer.min.js +34 -0
  353. data/data/jqplot/plugins/jqplot.funnelRenderer.js +918 -0
  354. data/data/jqplot/plugins/jqplot.funnelRenderer.min.js +34 -0
  355. data/data/jqplot/plugins/jqplot.highlighter.js +374 -0
  356. data/data/jqplot/plugins/jqplot.highlighter.min.js +34 -0
  357. data/data/jqplot/plugins/jqplot.logAxisRenderer.js +434 -0
  358. data/data/jqplot/plugins/jqplot.logAxisRenderer.min.js +34 -0
  359. data/data/jqplot/plugins/jqplot.mekkoAxisRenderer.js +595 -0
  360. data/data/jqplot/plugins/jqplot.mekkoAxisRenderer.min.js +34 -0
  361. data/data/jqplot/plugins/jqplot.mekkoRenderer.js +419 -0
  362. data/data/jqplot/plugins/jqplot.mekkoRenderer.min.js +34 -0
  363. data/data/jqplot/plugins/jqplot.meterGaugeRenderer.js +1112 -0
  364. data/data/jqplot/plugins/jqplot.meterGaugeRenderer.min.js +34 -0
  365. data/data/jqplot/plugins/jqplot.ohlcRenderer.js +343 -0
  366. data/data/jqplot/plugins/jqplot.ohlcRenderer.min.js +34 -0
  367. data/data/jqplot/plugins/jqplot.pieRenderer.js +749 -0
  368. data/data/jqplot/plugins/jqplot.pieRenderer.min.js +34 -0
  369. data/data/jqplot/plugins/jqplot.pointLabels.js +325 -0
  370. data/data/jqplot/plugins/jqplot.pointLabels.min.js +34 -0
  371. data/data/jqplot/plugins/jqplot.trendline.js +208 -0
  372. data/data/jqplot/plugins/jqplot.trendline.min.js +34 -0
  373. data/data/jqplot/usage.txt +119 -0
  374. data/examples/graph.rb +17 -0
  375. data/lib/reportbuilder.rb +21 -2
  376. data/lib/reportbuilder/builder.rb +31 -3
  377. data/lib/reportbuilder/builder/html.rb +39 -5
  378. data/lib/reportbuilder/graph.rb +252 -0
  379. data/lib/reportbuilder/graph/html_flot.rb +149 -0
  380. data/lib/reportbuilder/graph/html_jqplot.rb +145 -0
  381. data/lib/reportbuilder/image.rb +178 -78
  382. data/lib/reportbuilder/table/rtfbuilder.rb +2 -2
  383. data/test/helper_test.rb +6 -7
  384. data/test/test_graph.rb +44 -0
  385. data/test/test_graph_html_flot.rb +36 -0
  386. data/test/test_graph_html_jqplot.rb +36 -0
  387. data/test/test_html.rb +4 -7
  388. data/test/test_image.rb +35 -7
  389. data/test/test_reportbuilder.rb +4 -6
  390. data/test/test_table.rb +0 -2
  391. metadata +402 -7
  392. metadata.gz.sig +4 -2
@@ -0,0 +1,98 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>Flot Examples</title>
6
+ <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+ <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+ <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+ <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+ <body>
12
+ <h1>Flot Examples</h1>
13
+
14
+ <div id="placeholder" style="width:600px;height:300px;"></div>
15
+
16
+ <p>Here is an example with real data: military budgets for
17
+ various countries in constant (2005) million US dollars (source: <a href="http://www.sipri.org/">SIPRI</a>).</p>
18
+
19
+ <p>Since all data is available client-side, it's pretty easy to
20
+ make the plot interactive. Try turning countries on/off with the
21
+ checkboxes below.</p>
22
+
23
+ <p id="choices">Show:</p>
24
+
25
+ <script id="source" language="javascript" type="text/javascript">
26
+ $(function () {
27
+ var datasets = {
28
+ "usa": {
29
+ label: "USA",
30
+ data: [[1988, 483994], [1989, 479060], [1990, 457648], [1991, 401949], [1992, 424705], [1993, 402375], [1994, 377867], [1995, 357382], [1996, 337946], [1997, 336185], [1998, 328611], [1999, 329421], [2000, 342172], [2001, 344932], [2002, 387303], [2003, 440813], [2004, 480451], [2005, 504638], [2006, 528692]]
31
+ },
32
+ "russia": {
33
+ label: "Russia",
34
+ data: [[1988, 218000], [1989, 203000], [1990, 171000], [1992, 42500], [1993, 37600], [1994, 36600], [1995, 21700], [1996, 19200], [1997, 21300], [1998, 13600], [1999, 14000], [2000, 19100], [2001, 21300], [2002, 23600], [2003, 25100], [2004, 26100], [2005, 31100], [2006, 34700]]
35
+ },
36
+ "uk": {
37
+ label: "UK",
38
+ data: [[1988, 62982], [1989, 62027], [1990, 60696], [1991, 62348], [1992, 58560], [1993, 56393], [1994, 54579], [1995, 50818], [1996, 50554], [1997, 48276], [1998, 47691], [1999, 47529], [2000, 47778], [2001, 48760], [2002, 50949], [2003, 57452], [2004, 60234], [2005, 60076], [2006, 59213]]
39
+ },
40
+ "germany": {
41
+ label: "Germany",
42
+ data: [[1988, 55627], [1989, 55475], [1990, 58464], [1991, 55134], [1992, 52436], [1993, 47139], [1994, 43962], [1995, 43238], [1996, 42395], [1997, 40854], [1998, 40993], [1999, 41822], [2000, 41147], [2001, 40474], [2002, 40604], [2003, 40044], [2004, 38816], [2005, 38060], [2006, 36984]]
43
+ },
44
+ "denmark": {
45
+ label: "Denmark",
46
+ data: [[1988, 3813], [1989, 3719], [1990, 3722], [1991, 3789], [1992, 3720], [1993, 3730], [1994, 3636], [1995, 3598], [1996, 3610], [1997, 3655], [1998, 3695], [1999, 3673], [2000, 3553], [2001, 3774], [2002, 3728], [2003, 3618], [2004, 3638], [2005, 3467], [2006, 3770]]
47
+ },
48
+ "sweden": {
49
+ label: "Sweden",
50
+ data: [[1988, 6402], [1989, 6474], [1990, 6605], [1991, 6209], [1992, 6035], [1993, 6020], [1994, 6000], [1995, 6018], [1996, 3958], [1997, 5780], [1998, 5954], [1999, 6178], [2000, 6411], [2001, 5993], [2002, 5833], [2003, 5791], [2004, 5450], [2005, 5521], [2006, 5271]]
51
+ },
52
+ "norway": {
53
+ label: "Norway",
54
+ data: [[1988, 4382], [1989, 4498], [1990, 4535], [1991, 4398], [1992, 4766], [1993, 4441], [1994, 4670], [1995, 4217], [1996, 4275], [1997, 4203], [1998, 4482], [1999, 4506], [2000, 4358], [2001, 4385], [2002, 5269], [2003, 5066], [2004, 5194], [2005, 4887], [2006, 4891]]
55
+ }
56
+ };
57
+
58
+ // hard-code color indices to prevent them from shifting as
59
+ // countries are turned on/off
60
+ var i = 0;
61
+ $.each(datasets, function(key, val) {
62
+ val.color = i;
63
+ ++i;
64
+ });
65
+
66
+ // insert checkboxes
67
+ var choiceContainer = $("#choices");
68
+ $.each(datasets, function(key, val) {
69
+ choiceContainer.append('<br/><input type="checkbox" name="' + key +
70
+ '" checked="checked" id="id' + key + '">' +
71
+ '<label for="id' + key + '">'
72
+ + val.label + '</label>');
73
+ });
74
+ choiceContainer.find("input").click(plotAccordingToChoices);
75
+
76
+
77
+ function plotAccordingToChoices() {
78
+ var data = [];
79
+
80
+ choiceContainer.find("input:checked").each(function () {
81
+ var key = $(this).attr("name");
82
+ if (key && datasets[key])
83
+ data.push(datasets[key]);
84
+ });
85
+
86
+ if (data.length > 0)
87
+ $.plot($("#placeholder"), data, {
88
+ yaxis: { min: 0 },
89
+ xaxis: { tickDecimals: 0 }
90
+ });
91
+ }
92
+
93
+ plotAccordingToChoices();
94
+ });
95
+ </script>
96
+
97
+ </body>
98
+ </html>
@@ -0,0 +1,90 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>Flot Examples</title>
6
+ <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+ <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+ <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+ <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
11
+ </head>
12
+ <body>
13
+ <h1>Flot Examples</h1>
14
+
15
+ <div id="placeholder" style="width:600px;height:300px;"></div>
16
+
17
+ <p>Visitors per day to the Flot homepage. Weekends are colored. Try zooming.
18
+ The plot below shows an overview.</p>
19
+
20
+ <div id="overview" style="margin-left:50px;margin-top:20px;width:400px;height:50px"></div>
21
+
22
+ <script id="source">
23
+ $(function () {
24
+ var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], [1196722800000, 77], [1196809200000, 3636], [1196895600000, 3575], [1196982000000, 2736], [1197068400000, 1086], [1197154800000, 676], [1197241200000, 1205], [1197327600000, 906], [1197414000000, 710], [1197500400000, 639], [1197586800000, 540], [1197673200000, 435], [1197759600000, 301], [1197846000000, 575], [1197932400000, 481], [1198018800000, 591], [1198105200000, 608], [1198191600000, 459], [1198278000000, 234], [1198364400000, 1352], [1198450800000, 686], [1198537200000, 279], [1198623600000, 449], [1198710000000, 468], [1198796400000, 392], [1198882800000, 282], [1198969200000, 208], [1199055600000, 229], [1199142000000, 177], [1199228400000, 374], [1199314800000, 436], [1199401200000, 404], [1199487600000, 253], [1199574000000, 218], [1199660400000, 476], [1199746800000, 462], [1199833200000, 448], [1199919600000, 442], [1200006000000, 403], [1200092400000, 204], [1200178800000, 194], [1200265200000, 327], [1200351600000, 374], [1200438000000, 507], [1200524400000, 546], [1200610800000, 482], [1200697200000, 283], [1200783600000, 221], [1200870000000, 483], [1200956400000, 523], [1201042800000, 528], [1201129200000, 483], [1201215600000, 452], [1201302000000, 270], [1201388400000, 222], [1201474800000, 439], [1201561200000, 559], [1201647600000, 521], [1201734000000, 477], [1201820400000, 442], [1201906800000, 252], [1201993200000, 236], [1202079600000, 525], [1202166000000, 477], [1202252400000, 386], [1202338800000, 409], [1202425200000, 408], [1202511600000, 237], [1202598000000, 193], [1202684400000, 357], [1202770800000, 414], [1202857200000, 393], [1202943600000, 353], [1203030000000, 364], [1203116400000, 215], [1203202800000, 214], [1203289200000, 356], [1203375600000, 399], [1203462000000, 334], [1203548400000, 348], [1203634800000, 243], [1203721200000, 126], [1203807600000, 157], [1203894000000, 288]];
25
+
26
+ // first correct the timestamps - they are recorded as the daily
27
+ // midnights in UTC+0100, but Flot always displays dates in UTC
28
+ // so we have to add one hour to hit the midnights in the plot
29
+ for (var i = 0; i < d.length; ++i)
30
+ d[i][0] += 60 * 60 * 1000;
31
+
32
+ // helper for returning the weekends in a period
33
+ function weekendAreas(axes) {
34
+ var markings = [];
35
+ var d = new Date(axes.xaxis.min);
36
+ // go to the first Saturday
37
+ d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
38
+ d.setUTCSeconds(0);
39
+ d.setUTCMinutes(0);
40
+ d.setUTCHours(0);
41
+ var i = d.getTime();
42
+ do {
43
+ // when we don't set yaxis, the rectangle automatically
44
+ // extends to infinity upwards and downwards
45
+ markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });
46
+ i += 7 * 24 * 60 * 60 * 1000;
47
+ } while (i < axes.xaxis.max);
48
+
49
+ return markings;
50
+ }
51
+
52
+ var options = {
53
+ xaxis: { mode: "time" },
54
+ selection: { mode: "x" },
55
+ grid: { markings: weekendAreas }
56
+ };
57
+
58
+ var plot = $.plot($("#placeholder"), [d], options);
59
+
60
+ var overview = $.plot($("#overview"), [d], {
61
+ series: {
62
+ lines: { show: true, lineWidth: 1 },
63
+ shadowSize: 0
64
+ },
65
+ xaxis: { ticks: [], mode: "time" },
66
+ yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
67
+ selection: { mode: "x" }
68
+ });
69
+
70
+ // now connect the two
71
+
72
+ $("#placeholder").bind("plotselected", function (event, ranges) {
73
+ // do the zooming
74
+ plot = $.plot($("#placeholder"), [d],
75
+ $.extend(true, {}, options, {
76
+ xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
77
+ }));
78
+
79
+ // don't fire event on the overview to prevent eternal loop
80
+ overview.setSelection(ranges, true);
81
+ });
82
+
83
+ $("#overview").bind("plotselected", function (event, ranges) {
84
+ plot.setSelection(ranges);
85
+ });
86
+ });
87
+ </script>
88
+
89
+ </body>
90
+ </html>
@@ -0,0 +1,98 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>Flot Examples</title>
6
+ <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+ <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+ <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+ <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
11
+ </head>
12
+ <body>
13
+ <h1>Flot Examples</h1>
14
+
15
+ <div style="float:left">
16
+ <div id="placeholder" style="width:500px;height:300px"></div>
17
+ </div>
18
+
19
+ <div id="miniature" style="float:left;margin-left:20px;margin-top:50px">
20
+ <div id="overview" style="width:166px;height:100px"></div>
21
+
22
+ <p id="overviewLegend" style="margin-left:10px"></p>
23
+ </div>
24
+
25
+ <p style="clear:left"> The selection support makes
26
+ pretty advanced zooming schemes possible. With a few lines of code,
27
+ the small overview plot to the right has been connected to the large
28
+ plot. Try selecting a rectangle on either of them.</p>
29
+
30
+ <script id="source">
31
+ $(function () {
32
+ // setup plot
33
+ function getData(x1, x2) {
34
+ var d = [];
35
+ for (var i = 0; i <= 100; ++i) {
36
+ var x = x1 + i * (x2 - x1) / 100;
37
+ d.push([x, Math.sin(x * Math.sin(x))]);
38
+ }
39
+
40
+ return [
41
+ { label: "sin(x sin(x))", data: d }
42
+ ];
43
+ }
44
+
45
+ var options = {
46
+ legend: { show: false },
47
+ series: {
48
+ lines: { show: true },
49
+ points: { show: true }
50
+ },
51
+ yaxis: { ticks: 10 },
52
+ selection: { mode: "xy" }
53
+ };
54
+
55
+ var startData = getData(0, 3 * Math.PI);
56
+
57
+ var plot = $.plot($("#placeholder"), startData, options);
58
+
59
+ // setup overview
60
+ var overview = $.plot($("#overview"), startData, {
61
+ legend: { show: true, container: $("#overviewLegend") },
62
+ series: {
63
+ lines: { show: true, lineWidth: 1 },
64
+ shadowSize: 0
65
+ },
66
+ xaxis: { ticks: 4 },
67
+ yaxis: { ticks: 3, min: -2, max: 2 },
68
+ grid: { color: "#999" },
69
+ selection: { mode: "xy" }
70
+ });
71
+
72
+ // now connect the two
73
+
74
+ $("#placeholder").bind("plotselected", function (event, ranges) {
75
+ // clamp the zooming to prevent eternal zoom
76
+ if (ranges.xaxis.to - ranges.xaxis.from < 0.00001)
77
+ ranges.xaxis.to = ranges.xaxis.from + 0.00001;
78
+ if (ranges.yaxis.to - ranges.yaxis.from < 0.00001)
79
+ ranges.yaxis.to = ranges.yaxis.from + 0.00001;
80
+
81
+ // do the zooming
82
+ plot = $.plot($("#placeholder"), getData(ranges.xaxis.from, ranges.xaxis.to),
83
+ $.extend(true, {}, options, {
84
+ xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
85
+ yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
86
+ }));
87
+
88
+ // don't fire event on the overview to prevent eternal loop
89
+ overview.setSelection(ranges, true);
90
+ });
91
+ $("#overview").bind("plotselected", function (event, ranges) {
92
+ plot.setSelection(ranges);
93
+ });
94
+ });
95
+ </script>
96
+
97
+ </body>
98
+ </html>
@@ -0,0 +1,1427 @@
1
+ // Copyright 2006 Google Inc.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+
16
+ // Known Issues:
17
+ //
18
+ // * Patterns only support repeat.
19
+ // * Radial gradient are not implemented. The VML version of these look very
20
+ // different from the canvas one.
21
+ // * Clipping paths are not implemented.
22
+ // * Coordsize. The width and height attribute have higher priority than the
23
+ // width and height style values which isn't correct.
24
+ // * Painting mode isn't implemented.
25
+ // * Canvas width/height should is using content-box by default. IE in
26
+ // Quirks mode will draw the canvas using border-box. Either change your
27
+ // doctype to HTML5
28
+ // (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
29
+ // or use Box Sizing Behavior from WebFX
30
+ // (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
31
+ // * Non uniform scaling does not correctly scale strokes.
32
+ // * Filling very large shapes (above 5000 points) is buggy.
33
+ // * Optimize. There is always room for speed improvements.
34
+
35
+ // Only add this code if we do not already have a canvas implementation
36
+ if (!document.createElement('canvas').getContext) {
37
+
38
+ (function() {
39
+
40
+ // alias some functions to make (compiled) code shorter
41
+ var m = Math;
42
+ var mr = m.round;
43
+ var ms = m.sin;
44
+ var mc = m.cos;
45
+ var abs = m.abs;
46
+ var sqrt = m.sqrt;
47
+
48
+ // this is used for sub pixel precision
49
+ var Z = 10;
50
+ var Z2 = Z / 2;
51
+
52
+ /**
53
+ * This funtion is assigned to the <canvas> elements as element.getContext().
54
+ * @this {HTMLElement}
55
+ * @return {CanvasRenderingContext2D_}
56
+ */
57
+ function getContext() {
58
+ return this.context_ ||
59
+ (this.context_ = new CanvasRenderingContext2D_(this));
60
+ }
61
+
62
+ var slice = Array.prototype.slice;
63
+
64
+ /**
65
+ * Binds a function to an object. The returned function will always use the
66
+ * passed in {@code obj} as {@code this}.
67
+ *
68
+ * Example:
69
+ *
70
+ * g = bind(f, obj, a, b)
71
+ * g(c, d) // will do f.call(obj, a, b, c, d)
72
+ *
73
+ * @param {Function} f The function to bind the object to
74
+ * @param {Object} obj The object that should act as this when the function
75
+ * is called
76
+ * @param {*} var_args Rest arguments that will be used as the initial
77
+ * arguments when the function is called
78
+ * @return {Function} A new function that has bound this
79
+ */
80
+ function bind(f, obj, var_args) {
81
+ var a = slice.call(arguments, 2);
82
+ return function() {
83
+ return f.apply(obj, a.concat(slice.call(arguments)));
84
+ };
85
+ }
86
+
87
+ function encodeHtmlAttribute(s) {
88
+ return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
89
+ }
90
+
91
+ function addNamespacesAndStylesheet(doc) {
92
+ // create xmlns
93
+ if (!doc.namespaces['g_vml_']) {
94
+ doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
95
+ '#default#VML');
96
+
97
+ }
98
+ if (!doc.namespaces['g_o_']) {
99
+ doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
100
+ '#default#VML');
101
+ }
102
+
103
+ // Setup default CSS. Only add one style sheet per document
104
+ if (!doc.styleSheets['ex_canvas_']) {
105
+ var ss = doc.createStyleSheet();
106
+ ss.owningElement.id = 'ex_canvas_';
107
+ ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
108
+ // default size is 300x150 in Gecko and Opera
109
+ 'text-align:left;width:300px;height:150px}';
110
+ }
111
+ }
112
+
113
+ // Add namespaces and stylesheet at startup.
114
+ addNamespacesAndStylesheet(document);
115
+
116
+ var G_vmlCanvasManager_ = {
117
+ init: function(opt_doc) {
118
+ if (/MSIE/.test(navigator.userAgent) && !window.opera) {
119
+ var doc = opt_doc || document;
120
+ // Create a dummy element so that IE will allow canvas elements to be
121
+ // recognized.
122
+ doc.createElement('canvas');
123
+ doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
124
+ }
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
+
180
+ function onPropertyChange(e) {
181
+ var el = e.srcElement;
182
+
183
+ switch (e.propertyName) {
184
+ case 'width':
185
+ el.getContext().clearRect();
186
+ el.style.width = el.attributes.width.nodeValue + 'px';
187
+ // In IE8 this does not trigger onresize.
188
+ el.firstChild.style.width = el.clientWidth + 'px';
189
+ break;
190
+ case 'height':
191
+ el.getContext().clearRect();
192
+ el.style.height = el.attributes.height.nodeValue + 'px';
193
+ el.firstChild.style.height = el.clientHeight + 'px';
194
+ break;
195
+ }
196
+ }
197
+
198
+ function onResize(e) {
199
+ var el = e.srcElement;
200
+ if (el.firstChild) {
201
+ el.firstChild.style.width = el.clientWidth + 'px';
202
+ el.firstChild.style.height = el.clientHeight + 'px';
203
+ }
204
+ }
205
+
206
+ G_vmlCanvasManager_.init();
207
+
208
+ // precompute "00" to "FF"
209
+ var decToHex = [];
210
+ for (var i = 0; i < 16; i++) {
211
+ for (var j = 0; j < 16; j++) {
212
+ decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
213
+ }
214
+ }
215
+
216
+ function createMatrixIdentity() {
217
+ return [
218
+ [1, 0, 0],
219
+ [0, 1, 0],
220
+ [0, 0, 1]
221
+ ];
222
+ }
223
+
224
+ function matrixMultiply(m1, m2) {
225
+ var result = createMatrixIdentity();
226
+
227
+ for (var x = 0; x < 3; x++) {
228
+ for (var y = 0; y < 3; y++) {
229
+ var sum = 0;
230
+
231
+ for (var z = 0; z < 3; z++) {
232
+ sum += m1[x][z] * m2[z][y];
233
+ }
234
+
235
+ result[x][y] = sum;
236
+ }
237
+ }
238
+ return result;
239
+ }
240
+
241
+ function copyState(o1, o2) {
242
+ o2.fillStyle = o1.fillStyle;
243
+ o2.lineCap = o1.lineCap;
244
+ o2.lineJoin = o1.lineJoin;
245
+ o2.lineWidth = o1.lineWidth;
246
+ o2.miterLimit = o1.miterLimit;
247
+ o2.shadowBlur = o1.shadowBlur;
248
+ o2.shadowColor = o1.shadowColor;
249
+ o2.shadowOffsetX = o1.shadowOffsetX;
250
+ o2.shadowOffsetY = o1.shadowOffsetY;
251
+ o2.strokeStyle = o1.strokeStyle;
252
+ o2.globalAlpha = o1.globalAlpha;
253
+ o2.font = o1.font;
254
+ o2.textAlign = o1.textAlign;
255
+ o2.textBaseline = o1.textBaseline;
256
+ o2.arcScaleX_ = o1.arcScaleX_;
257
+ o2.arcScaleY_ = o1.arcScaleY_;
258
+ o2.lineScale_ = o1.lineScale_;
259
+ }
260
+
261
+ var colorData = {
262
+ aliceblue: '#F0F8FF',
263
+ antiquewhite: '#FAEBD7',
264
+ aquamarine: '#7FFFD4',
265
+ azure: '#F0FFFF',
266
+ beige: '#F5F5DC',
267
+ bisque: '#FFE4C4',
268
+ black: '#000000',
269
+ blanchedalmond: '#FFEBCD',
270
+ blueviolet: '#8A2BE2',
271
+ brown: '#A52A2A',
272
+ burlywood: '#DEB887',
273
+ cadetblue: '#5F9EA0',
274
+ chartreuse: '#7FFF00',
275
+ chocolate: '#D2691E',
276
+ coral: '#FF7F50',
277
+ cornflowerblue: '#6495ED',
278
+ cornsilk: '#FFF8DC',
279
+ crimson: '#DC143C',
280
+ cyan: '#00FFFF',
281
+ darkblue: '#00008B',
282
+ darkcyan: '#008B8B',
283
+ darkgoldenrod: '#B8860B',
284
+ darkgray: '#A9A9A9',
285
+ darkgreen: '#006400',
286
+ darkgrey: '#A9A9A9',
287
+ darkkhaki: '#BDB76B',
288
+ darkmagenta: '#8B008B',
289
+ darkolivegreen: '#556B2F',
290
+ darkorange: '#FF8C00',
291
+ darkorchid: '#9932CC',
292
+ darkred: '#8B0000',
293
+ darksalmon: '#E9967A',
294
+ darkseagreen: '#8FBC8F',
295
+ darkslateblue: '#483D8B',
296
+ darkslategray: '#2F4F4F',
297
+ darkslategrey: '#2F4F4F',
298
+ darkturquoise: '#00CED1',
299
+ darkviolet: '#9400D3',
300
+ deeppink: '#FF1493',
301
+ deepskyblue: '#00BFFF',
302
+ dimgray: '#696969',
303
+ dimgrey: '#696969',
304
+ dodgerblue: '#1E90FF',
305
+ firebrick: '#B22222',
306
+ floralwhite: '#FFFAF0',
307
+ forestgreen: '#228B22',
308
+ gainsboro: '#DCDCDC',
309
+ ghostwhite: '#F8F8FF',
310
+ gold: '#FFD700',
311
+ goldenrod: '#DAA520',
312
+ grey: '#808080',
313
+ greenyellow: '#ADFF2F',
314
+ honeydew: '#F0FFF0',
315
+ hotpink: '#FF69B4',
316
+ indianred: '#CD5C5C',
317
+ indigo: '#4B0082',
318
+ ivory: '#FFFFF0',
319
+ khaki: '#F0E68C',
320
+ lavender: '#E6E6FA',
321
+ lavenderblush: '#FFF0F5',
322
+ lawngreen: '#7CFC00',
323
+ lemonchiffon: '#FFFACD',
324
+ lightblue: '#ADD8E6',
325
+ lightcoral: '#F08080',
326
+ lightcyan: '#E0FFFF',
327
+ lightgoldenrodyellow: '#FAFAD2',
328
+ lightgreen: '#90EE90',
329
+ lightgrey: '#D3D3D3',
330
+ lightpink: '#FFB6C1',
331
+ lightsalmon: '#FFA07A',
332
+ lightseagreen: '#20B2AA',
333
+ lightskyblue: '#87CEFA',
334
+ lightslategray: '#778899',
335
+ lightslategrey: '#778899',
336
+ lightsteelblue: '#B0C4DE',
337
+ lightyellow: '#FFFFE0',
338
+ limegreen: '#32CD32',
339
+ linen: '#FAF0E6',
340
+ magenta: '#FF00FF',
341
+ mediumaquamarine: '#66CDAA',
342
+ mediumblue: '#0000CD',
343
+ mediumorchid: '#BA55D3',
344
+ mediumpurple: '#9370DB',
345
+ mediumseagreen: '#3CB371',
346
+ mediumslateblue: '#7B68EE',
347
+ mediumspringgreen: '#00FA9A',
348
+ mediumturquoise: '#48D1CC',
349
+ mediumvioletred: '#C71585',
350
+ midnightblue: '#191970',
351
+ mintcream: '#F5FFFA',
352
+ mistyrose: '#FFE4E1',
353
+ moccasin: '#FFE4B5',
354
+ navajowhite: '#FFDEAD',
355
+ oldlace: '#FDF5E6',
356
+ olivedrab: '#6B8E23',
357
+ orange: '#FFA500',
358
+ orangered: '#FF4500',
359
+ orchid: '#DA70D6',
360
+ palegoldenrod: '#EEE8AA',
361
+ palegreen: '#98FB98',
362
+ paleturquoise: '#AFEEEE',
363
+ palevioletred: '#DB7093',
364
+ papayawhip: '#FFEFD5',
365
+ peachpuff: '#FFDAB9',
366
+ peru: '#CD853F',
367
+ pink: '#FFC0CB',
368
+ plum: '#DDA0DD',
369
+ powderblue: '#B0E0E6',
370
+ rosybrown: '#BC8F8F',
371
+ royalblue: '#4169E1',
372
+ saddlebrown: '#8B4513',
373
+ salmon: '#FA8072',
374
+ sandybrown: '#F4A460',
375
+ seagreen: '#2E8B57',
376
+ seashell: '#FFF5EE',
377
+ sienna: '#A0522D',
378
+ skyblue: '#87CEEB',
379
+ slateblue: '#6A5ACD',
380
+ slategray: '#708090',
381
+ slategrey: '#708090',
382
+ snow: '#FFFAFA',
383
+ springgreen: '#00FF7F',
384
+ steelblue: '#4682B4',
385
+ tan: '#D2B48C',
386
+ thistle: '#D8BFD8',
387
+ tomato: '#FF6347',
388
+ turquoise: '#40E0D0',
389
+ violet: '#EE82EE',
390
+ wheat: '#F5DEB3',
391
+ whitesmoke: '#F5F5F5',
392
+ yellowgreen: '#9ACD32'
393
+ };
394
+
395
+
396
+ function getRgbHslContent(styleString) {
397
+ var start = styleString.indexOf('(', 3);
398
+ var end = styleString.indexOf(')', start + 1);
399
+ var parts = styleString.substring(start + 1, end).split(',');
400
+ // add alpha if needed
401
+ if (parts.length == 4 && styleString.substr(3, 1) == 'a') {
402
+ alpha = Number(parts[3]);
403
+ } else {
404
+ parts[3] = 1;
405
+ }
406
+ return parts;
407
+ }
408
+
409
+ function percent(s) {
410
+ return parseFloat(s) / 100;
411
+ }
412
+
413
+ function clamp(v, min, max) {
414
+ return Math.min(max, Math.max(min, v));
415
+ }
416
+
417
+ function hslToRgb(parts){
418
+ var r, g, b;
419
+ h = parseFloat(parts[0]) / 360 % 360;
420
+ if (h < 0)
421
+ h++;
422
+ s = clamp(percent(parts[1]), 0, 1);
423
+ l = clamp(percent(parts[2]), 0, 1);
424
+ if (s == 0) {
425
+ r = g = b = l; // achromatic
426
+ } else {
427
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
428
+ var p = 2 * l - q;
429
+ r = hueToRgb(p, q, h + 1 / 3);
430
+ g = hueToRgb(p, q, h);
431
+ b = hueToRgb(p, q, h - 1 / 3);
432
+ }
433
+
434
+ return '#' + decToHex[Math.floor(r * 255)] +
435
+ decToHex[Math.floor(g * 255)] +
436
+ decToHex[Math.floor(b * 255)];
437
+ }
438
+
439
+ function hueToRgb(m1, m2, h) {
440
+ if (h < 0)
441
+ h++;
442
+ if (h > 1)
443
+ h--;
444
+
445
+ if (6 * h < 1)
446
+ return m1 + (m2 - m1) * 6 * h;
447
+ else if (2 * h < 1)
448
+ return m2;
449
+ else if (3 * h < 2)
450
+ return m1 + (m2 - m1) * (2 / 3 - h) * 6;
451
+ else
452
+ return m1;
453
+ }
454
+
455
+ function processStyle(styleString) {
456
+ var str, alpha = 1;
457
+
458
+ styleString = String(styleString);
459
+ if (styleString.charAt(0) == '#') {
460
+ str = styleString;
461
+ } else if (/^rgb/.test(styleString)) {
462
+ var parts = getRgbHslContent(styleString);
463
+ var str = '#', n;
464
+ for (var i = 0; i < 3; i++) {
465
+ if (parts[i].indexOf('%') != -1) {
466
+ n = Math.floor(percent(parts[i]) * 255);
467
+ } else {
468
+ n = Number(parts[i]);
469
+ }
470
+ str += decToHex[clamp(n, 0, 255)];
471
+ }
472
+ alpha = parts[3];
473
+ } else if (/^hsl/.test(styleString)) {
474
+ var parts = getRgbHslContent(styleString);
475
+ str = hslToRgb(parts);
476
+ alpha = parts[3];
477
+ } else {
478
+ str = colorData[styleString] || styleString;
479
+ }
480
+ return {color: str, alpha: alpha};
481
+ }
482
+
483
+ var DEFAULT_STYLE = {
484
+ style: 'normal',
485
+ variant: 'normal',
486
+ weight: 'normal',
487
+ size: 10,
488
+ family: 'sans-serif'
489
+ };
490
+
491
+ // Internal text style cache
492
+ var fontStyleCache = {};
493
+
494
+ function processFontStyle(styleString) {
495
+ if (fontStyleCache[styleString]) {
496
+ return fontStyleCache[styleString];
497
+ }
498
+
499
+ var el = document.createElement('div');
500
+ var style = el.style;
501
+ try {
502
+ style.font = styleString;
503
+ } catch (ex) {
504
+ // Ignore failures to set to invalid font.
505
+ }
506
+
507
+ return fontStyleCache[styleString] = {
508
+ style: style.fontStyle || DEFAULT_STYLE.style,
509
+ variant: style.fontVariant || DEFAULT_STYLE.variant,
510
+ weight: style.fontWeight || DEFAULT_STYLE.weight,
511
+ size: style.fontSize || DEFAULT_STYLE.size,
512
+ family: style.fontFamily || DEFAULT_STYLE.family
513
+ };
514
+ }
515
+
516
+ function getComputedStyle(style, element) {
517
+ var computedStyle = {};
518
+
519
+ for (var p in style) {
520
+ computedStyle[p] = style[p];
521
+ }
522
+
523
+ // Compute the size
524
+ var canvasFontSize = parseFloat(element.currentStyle.fontSize),
525
+ fontSize = parseFloat(style.size);
526
+
527
+ if (typeof style.size == 'number') {
528
+ computedStyle.size = style.size;
529
+ } else if (style.size.indexOf('px') != -1) {
530
+ computedStyle.size = fontSize;
531
+ } else if (style.size.indexOf('em') != -1) {
532
+ computedStyle.size = canvasFontSize * fontSize;
533
+ } else if(style.size.indexOf('%') != -1) {
534
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
535
+ } else if (style.size.indexOf('pt') != -1) {
536
+ computedStyle.size = fontSize / .75;
537
+ } else {
538
+ computedStyle.size = canvasFontSize;
539
+ }
540
+
541
+ // Different scaling between normal text and VML text. This was found using
542
+ // trial and error to get the same size as non VML text.
543
+ computedStyle.size *= 0.981;
544
+
545
+ return computedStyle;
546
+ }
547
+
548
+ function buildStyle(style) {
549
+ return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
550
+ style.size + 'px ' + style.family;
551
+ }
552
+
553
+ function processLineCap(lineCap) {
554
+ switch (lineCap) {
555
+ case 'butt':
556
+ return 'flat';
557
+ case 'round':
558
+ return 'round';
559
+ case 'square':
560
+ default:
561
+ return 'square';
562
+ }
563
+ }
564
+
565
+ /**
566
+ * This class implements CanvasRenderingContext2D interface as described by
567
+ * the WHATWG.
568
+ * @param {HTMLElement} surfaceElement The element that the 2D context should
569
+ * be associated with
570
+ */
571
+ function CanvasRenderingContext2D_(surfaceElement) {
572
+ this.m_ = createMatrixIdentity();
573
+
574
+ this.mStack_ = [];
575
+ this.aStack_ = [];
576
+ this.currentPath_ = [];
577
+
578
+ // Canvas context properties
579
+ this.strokeStyle = '#000';
580
+ this.fillStyle = '#000';
581
+
582
+ this.lineWidth = 1;
583
+ this.lineJoin = 'miter';
584
+ this.lineCap = 'butt';
585
+ this.miterLimit = Z * 1;
586
+ this.globalAlpha = 1;
587
+ this.font = '10px sans-serif';
588
+ this.textAlign = 'left';
589
+ this.textBaseline = 'alphabetic';
590
+ this.canvas = surfaceElement;
591
+
592
+ var el = surfaceElement.ownerDocument.createElement('div');
593
+ el.style.width = surfaceElement.clientWidth + 'px';
594
+ el.style.height = surfaceElement.clientHeight + 'px';
595
+ el.style.overflow = 'hidden';
596
+ el.style.position = 'absolute';
597
+ surfaceElement.appendChild(el);
598
+
599
+ this.element_ = el;
600
+ this.arcScaleX_ = 1;
601
+ this.arcScaleY_ = 1;
602
+ this.lineScale_ = 1;
603
+ }
604
+
605
+ var contextPrototype = CanvasRenderingContext2D_.prototype;
606
+ contextPrototype.clearRect = function() {
607
+ if (this.textMeasureEl_) {
608
+ this.textMeasureEl_.removeNode(true);
609
+ this.textMeasureEl_ = null;
610
+ }
611
+ this.element_.innerHTML = '';
612
+ };
613
+
614
+ contextPrototype.beginPath = function() {
615
+ // TODO: Branch current matrix so that save/restore has no effect
616
+ // as per safari docs.
617
+ this.currentPath_ = [];
618
+ };
619
+
620
+ contextPrototype.moveTo = function(aX, aY) {
621
+ var p = this.getCoords_(aX, aY);
622
+ this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
623
+ this.currentX_ = p.x;
624
+ this.currentY_ = p.y;
625
+ };
626
+
627
+ contextPrototype.lineTo = function(aX, aY) {
628
+ var p = this.getCoords_(aX, aY);
629
+ this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
630
+
631
+ this.currentX_ = p.x;
632
+ this.currentY_ = p.y;
633
+ };
634
+
635
+ contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
636
+ aCP2x, aCP2y,
637
+ aX, aY) {
638
+ var p = this.getCoords_(aX, aY);
639
+ var cp1 = this.getCoords_(aCP1x, aCP1y);
640
+ var cp2 = this.getCoords_(aCP2x, aCP2y);
641
+ bezierCurveTo(this, cp1, cp2, p);
642
+ };
643
+
644
+ // Helper function that takes the already fixed cordinates.
645
+ function bezierCurveTo(self, cp1, cp2, p) {
646
+ self.currentPath_.push({
647
+ type: 'bezierCurveTo',
648
+ cp1x: cp1.x,
649
+ cp1y: cp1.y,
650
+ cp2x: cp2.x,
651
+ cp2y: cp2.y,
652
+ x: p.x,
653
+ y: p.y
654
+ });
655
+ self.currentX_ = p.x;
656
+ self.currentY_ = p.y;
657
+ }
658
+
659
+ contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
660
+ // the following is lifted almost directly from
661
+ // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
662
+
663
+ var cp = this.getCoords_(aCPx, aCPy);
664
+ var p = this.getCoords_(aX, aY);
665
+
666
+ var cp1 = {
667
+ x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
668
+ y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
669
+ };
670
+ var cp2 = {
671
+ x: cp1.x + (p.x - this.currentX_) / 3.0,
672
+ y: cp1.y + (p.y - this.currentY_) / 3.0
673
+ };
674
+
675
+ bezierCurveTo(this, cp1, cp2, p);
676
+ };
677
+
678
+ contextPrototype.arc = function(aX, aY, aRadius,
679
+ aStartAngle, aEndAngle, aClockwise) {
680
+ aRadius *= Z;
681
+ var arcType = aClockwise ? 'at' : 'wa';
682
+
683
+ var xStart = aX + mc(aStartAngle) * aRadius - Z2;
684
+ var yStart = aY + ms(aStartAngle) * aRadius - Z2;
685
+
686
+ var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
687
+ var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
688
+
689
+ // IE won't render arches drawn counter clockwise if xStart == xEnd.
690
+ if (xStart == xEnd && !aClockwise) {
691
+ xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
692
+ // that can be represented in binary
693
+ }
694
+
695
+ var p = this.getCoords_(aX, aY);
696
+ var pStart = this.getCoords_(xStart, yStart);
697
+ var pEnd = this.getCoords_(xEnd, yEnd);
698
+
699
+ this.currentPath_.push({type: arcType,
700
+ x: p.x,
701
+ y: p.y,
702
+ radius: aRadius,
703
+ xStart: pStart.x,
704
+ yStart: pStart.y,
705
+ xEnd: pEnd.x,
706
+ yEnd: pEnd.y});
707
+
708
+ };
709
+
710
+ contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
711
+ this.moveTo(aX, aY);
712
+ this.lineTo(aX + aWidth, aY);
713
+ this.lineTo(aX + aWidth, aY + aHeight);
714
+ this.lineTo(aX, aY + aHeight);
715
+ this.closePath();
716
+ };
717
+
718
+ contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
719
+ var oldPath = this.currentPath_;
720
+ this.beginPath();
721
+
722
+ this.moveTo(aX, aY);
723
+ this.lineTo(aX + aWidth, aY);
724
+ this.lineTo(aX + aWidth, aY + aHeight);
725
+ this.lineTo(aX, aY + aHeight);
726
+ this.closePath();
727
+ this.stroke();
728
+
729
+ this.currentPath_ = oldPath;
730
+ };
731
+
732
+ contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
733
+ var oldPath = this.currentPath_;
734
+ this.beginPath();
735
+
736
+ this.moveTo(aX, aY);
737
+ this.lineTo(aX + aWidth, aY);
738
+ this.lineTo(aX + aWidth, aY + aHeight);
739
+ this.lineTo(aX, aY + aHeight);
740
+ this.closePath();
741
+ this.fill();
742
+
743
+ this.currentPath_ = oldPath;
744
+ };
745
+
746
+ contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
747
+ var gradient = new CanvasGradient_('gradient');
748
+ gradient.x0_ = aX0;
749
+ gradient.y0_ = aY0;
750
+ gradient.x1_ = aX1;
751
+ gradient.y1_ = aY1;
752
+ return gradient;
753
+ };
754
+
755
+ contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
756
+ aX1, aY1, aR1) {
757
+ var gradient = new CanvasGradient_('gradientradial');
758
+ gradient.x0_ = aX0;
759
+ gradient.y0_ = aY0;
760
+ gradient.r0_ = aR0;
761
+ gradient.x1_ = aX1;
762
+ gradient.y1_ = aY1;
763
+ gradient.r1_ = aR1;
764
+ return gradient;
765
+ };
766
+
767
+ contextPrototype.drawImage = function(image, var_args) {
768
+ var dx, dy, dw, dh, sx, sy, sw, sh;
769
+
770
+ // to find the original width we overide the width and height
771
+ var oldRuntimeWidth = image.runtimeStyle.width;
772
+ var oldRuntimeHeight = image.runtimeStyle.height;
773
+ image.runtimeStyle.width = 'auto';
774
+ image.runtimeStyle.height = 'auto';
775
+
776
+ // get the original size
777
+ var w = image.width;
778
+ var h = image.height;
779
+
780
+ // and remove overides
781
+ image.runtimeStyle.width = oldRuntimeWidth;
782
+ image.runtimeStyle.height = oldRuntimeHeight;
783
+
784
+ if (arguments.length == 3) {
785
+ dx = arguments[1];
786
+ dy = arguments[2];
787
+ sx = sy = 0;
788
+ sw = dw = w;
789
+ sh = dh = h;
790
+ } else if (arguments.length == 5) {
791
+ dx = arguments[1];
792
+ dy = arguments[2];
793
+ dw = arguments[3];
794
+ dh = arguments[4];
795
+ sx = sy = 0;
796
+ sw = w;
797
+ sh = h;
798
+ } else if (arguments.length == 9) {
799
+ sx = arguments[1];
800
+ sy = arguments[2];
801
+ sw = arguments[3];
802
+ sh = arguments[4];
803
+ dx = arguments[5];
804
+ dy = arguments[6];
805
+ dw = arguments[7];
806
+ dh = arguments[8];
807
+ } else {
808
+ throw Error('Invalid number of arguments');
809
+ }
810
+
811
+ var d = this.getCoords_(dx, dy);
812
+
813
+ var w2 = sw / 2;
814
+ var h2 = sh / 2;
815
+
816
+ var vmlStr = [];
817
+
818
+ var W = 10;
819
+ var H = 10;
820
+
821
+ // For some reason that I've now forgotten, using divs didn't work
822
+ vmlStr.push(' <g_vml_:group',
823
+ ' coordsize="', Z * W, ',', Z * H, '"',
824
+ ' coordorigin="0,0"' ,
825
+ ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
826
+
827
+ // If filters are necessary (rotation exists), create them
828
+ // filters are bog-slow, so only create them if abbsolutely necessary
829
+ // The following check doesn't account for skews (which don't exist
830
+ // in the canvas spec (yet) anyway.
831
+
832
+ if (this.m_[0][0] != 1 || this.m_[0][1] ||
833
+ this.m_[1][1] != 1 || this.m_[1][0]) {
834
+ var filter = [];
835
+
836
+ // Note the 12/21 reversal
837
+ filter.push('M11=', this.m_[0][0], ',',
838
+ 'M12=', this.m_[1][0], ',',
839
+ 'M21=', this.m_[0][1], ',',
840
+ 'M22=', this.m_[1][1], ',',
841
+ 'Dx=', mr(d.x / Z), ',',
842
+ 'Dy=', mr(d.y / Z), '');
843
+
844
+ // Bounding box calculation (need to minimize displayed area so that
845
+ // filters don't waste time on unused pixels.
846
+ var max = d;
847
+ var c2 = this.getCoords_(dx + dw, dy);
848
+ var c3 = this.getCoords_(dx, dy + dh);
849
+ var c4 = this.getCoords_(dx + dw, dy + dh);
850
+
851
+ max.x = m.max(max.x, c2.x, c3.x, c4.x);
852
+ max.y = m.max(max.y, c2.y, c3.y, c4.y);
853
+
854
+ vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
855
+ 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
856
+ filter.join(''), ", sizingmethod='clip');");
857
+
858
+ } else {
859
+ vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
860
+ }
861
+
862
+ vmlStr.push(' ">' ,
863
+ '<g_vml_:image src="', image.src, '"',
864
+ ' style="width:', Z * dw, 'px;',
865
+ ' height:', Z * dh, 'px"',
866
+ ' cropleft="', sx / w, '"',
867
+ ' croptop="', sy / h, '"',
868
+ ' cropright="', (w - sx - sw) / w, '"',
869
+ ' cropbottom="', (h - sy - sh) / h, '"',
870
+ ' />',
871
+ '</g_vml_:group>');
872
+
873
+ this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
874
+ };
875
+
876
+ contextPrototype.stroke = function(aFill) {
877
+ var W = 10;
878
+ var H = 10;
879
+ // Divide the shape into chunks if it's too long because IE has a limit
880
+ // somewhere for how long a VML shape can be. This simple division does
881
+ // not work with fills, only strokes, unfortunately.
882
+ var chunkSize = 5000;
883
+
884
+ var min = {x: null, y: null};
885
+ var max = {x: null, y: null};
886
+
887
+ for (var j = 0; j < this.currentPath_.length; j += chunkSize) {
888
+ var lineStr = [];
889
+ var lineOpen = false;
890
+
891
+ lineStr.push('<g_vml_:shape',
892
+ ' filled="', !!aFill, '"',
893
+ ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
894
+ ' coordorigin="0,0"',
895
+ ' coordsize="', Z * W, ',', Z * H, '"',
896
+ ' stroked="', !aFill, '"',
897
+ ' path="');
898
+
899
+ var newSeq = false;
900
+
901
+ for (var i = j; i < Math.min(j + chunkSize, this.currentPath_.length); i++) {
902
+ if (i % chunkSize == 0 && i > 0) { // move into position for next chunk
903
+ lineStr.push(' m ', mr(this.currentPath_[i-1].x), ',', mr(this.currentPath_[i-1].y));
904
+ }
905
+
906
+ var p = this.currentPath_[i];
907
+ var c;
908
+
909
+ switch (p.type) {
910
+ case 'moveTo':
911
+ c = p;
912
+ lineStr.push(' m ', mr(p.x), ',', mr(p.y));
913
+ break;
914
+ case 'lineTo':
915
+ lineStr.push(' l ', mr(p.x), ',', mr(p.y));
916
+ break;
917
+ case 'close':
918
+ lineStr.push(' x ');
919
+ p = null;
920
+ break;
921
+ case 'bezierCurveTo':
922
+ lineStr.push(' c ',
923
+ mr(p.cp1x), ',', mr(p.cp1y), ',',
924
+ mr(p.cp2x), ',', mr(p.cp2y), ',',
925
+ mr(p.x), ',', mr(p.y));
926
+ break;
927
+ case 'at':
928
+ case 'wa':
929
+ lineStr.push(' ', p.type, ' ',
930
+ mr(p.x - this.arcScaleX_ * p.radius), ',',
931
+ mr(p.y - this.arcScaleY_ * p.radius), ' ',
932
+ mr(p.x + this.arcScaleX_ * p.radius), ',',
933
+ mr(p.y + this.arcScaleY_ * p.radius), ' ',
934
+ mr(p.xStart), ',', mr(p.yStart), ' ',
935
+ mr(p.xEnd), ',', mr(p.yEnd));
936
+ break;
937
+ }
938
+
939
+
940
+ // TODO: Following is broken for curves due to
941
+ // move to proper paths.
942
+
943
+ // Figure out dimensions so we can do gradient fills
944
+ // properly
945
+ if (p) {
946
+ if (min.x == null || p.x < min.x) {
947
+ min.x = p.x;
948
+ }
949
+ if (max.x == null || p.x > max.x) {
950
+ max.x = p.x;
951
+ }
952
+ if (min.y == null || p.y < min.y) {
953
+ min.y = p.y;
954
+ }
955
+ if (max.y == null || p.y > max.y) {
956
+ max.y = p.y;
957
+ }
958
+ }
959
+ }
960
+ lineStr.push(' ">');
961
+
962
+ if (!aFill) {
963
+ appendStroke(this, lineStr);
964
+ } else {
965
+ appendFill(this, lineStr, min, max);
966
+ }
967
+
968
+ lineStr.push('</g_vml_:shape>');
969
+
970
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
971
+ }
972
+ };
973
+
974
+ function appendStroke(ctx, lineStr) {
975
+ var a = processStyle(ctx.strokeStyle);
976
+ var color = a.color;
977
+ var opacity = a.alpha * ctx.globalAlpha;
978
+ var lineWidth = ctx.lineScale_ * ctx.lineWidth;
979
+
980
+ // VML cannot correctly render a line if the width is less than 1px.
981
+ // In that case, we dilute the color to make the line look thinner.
982
+ if (lineWidth < 1) {
983
+ opacity *= lineWidth;
984
+ }
985
+
986
+ lineStr.push(
987
+ '<g_vml_:stroke',
988
+ ' opacity="', opacity, '"',
989
+ ' joinstyle="', ctx.lineJoin, '"',
990
+ ' miterlimit="', ctx.miterLimit, '"',
991
+ ' endcap="', processLineCap(ctx.lineCap), '"',
992
+ ' weight="', lineWidth, 'px"',
993
+ ' color="', color, '" />'
994
+ );
995
+ }
996
+
997
+ function appendFill(ctx, lineStr, min, max) {
998
+ var fillStyle = ctx.fillStyle;
999
+ var arcScaleX = ctx.arcScaleX_;
1000
+ var arcScaleY = ctx.arcScaleY_;
1001
+ var width = max.x - min.x;
1002
+ var height = max.y - min.y;
1003
+ if (fillStyle instanceof CanvasGradient_) {
1004
+ // TODO: Gradients transformed with the transformation matrix.
1005
+ var angle = 0;
1006
+ var focus = {x: 0, y: 0};
1007
+
1008
+ // additional offset
1009
+ var shift = 0;
1010
+ // scale factor for offset
1011
+ var expansion = 1;
1012
+
1013
+ if (fillStyle.type_ == 'gradient') {
1014
+ var x0 = fillStyle.x0_ / arcScaleX;
1015
+ var y0 = fillStyle.y0_ / arcScaleY;
1016
+ var x1 = fillStyle.x1_ / arcScaleX;
1017
+ var y1 = fillStyle.y1_ / arcScaleY;
1018
+ var p0 = ctx.getCoords_(x0, y0);
1019
+ var p1 = ctx.getCoords_(x1, y1);
1020
+ var dx = p1.x - p0.x;
1021
+ var dy = p1.y - p0.y;
1022
+ angle = Math.atan2(dx, dy) * 180 / Math.PI;
1023
+
1024
+ // The angle should be a non-negative number.
1025
+ if (angle < 0) {
1026
+ angle += 360;
1027
+ }
1028
+
1029
+ // Very small angles produce an unexpected result because they are
1030
+ // converted to a scientific notation string.
1031
+ if (angle < 1e-6) {
1032
+ angle = 0;
1033
+ }
1034
+ } else {
1035
+ var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_);
1036
+ focus = {
1037
+ x: (p0.x - min.x) / width,
1038
+ y: (p0.y - min.y) / height
1039
+ };
1040
+
1041
+ width /= arcScaleX * Z;
1042
+ height /= arcScaleY * Z;
1043
+ var dimension = m.max(width, height);
1044
+ shift = 2 * fillStyle.r0_ / dimension;
1045
+ expansion = 2 * fillStyle.r1_ / dimension - shift;
1046
+ }
1047
+
1048
+ // We need to sort the color stops in ascending order by offset,
1049
+ // otherwise IE won't interpret it correctly.
1050
+ var stops = fillStyle.colors_;
1051
+ stops.sort(function(cs1, cs2) {
1052
+ return cs1.offset - cs2.offset;
1053
+ });
1054
+
1055
+ var length = stops.length;
1056
+ var color1 = stops[0].color;
1057
+ var color2 = stops[length - 1].color;
1058
+ var opacity1 = stops[0].alpha * ctx.globalAlpha;
1059
+ var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
1060
+
1061
+ var colors = [];
1062
+ for (var i = 0; i < length; i++) {
1063
+ var stop = stops[i];
1064
+ colors.push(stop.offset * expansion + shift + ' ' + stop.color);
1065
+ }
1066
+
1067
+ // When colors attribute is used, the meanings of opacity and o:opacity2
1068
+ // are reversed.
1069
+ lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
1070
+ ' method="none" focus="100%"',
1071
+ ' color="', color1, '"',
1072
+ ' color2="', color2, '"',
1073
+ ' colors="', colors.join(','), '"',
1074
+ ' opacity="', opacity2, '"',
1075
+ ' g_o_:opacity2="', opacity1, '"',
1076
+ ' angle="', angle, '"',
1077
+ ' focusposition="', focus.x, ',', focus.y, '" />');
1078
+ } else if (fillStyle instanceof CanvasPattern_) {
1079
+ if (width && height) {
1080
+ var deltaLeft = -min.x;
1081
+ var deltaTop = -min.y;
1082
+ lineStr.push('<g_vml_:fill',
1083
+ ' position="',
1084
+ deltaLeft / width * arcScaleX * arcScaleX, ',',
1085
+ deltaTop / height * arcScaleY * arcScaleY, '"',
1086
+ ' type="tile"',
1087
+ // TODO: Figure out the correct size to fit the scale.
1088
+ //' size="', w, 'px ', h, 'px"',
1089
+ ' src="', fillStyle.src_, '" />');
1090
+ }
1091
+ } else {
1092
+ var a = processStyle(ctx.fillStyle);
1093
+ var color = a.color;
1094
+ var opacity = a.alpha * ctx.globalAlpha;
1095
+ lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
1096
+ '" />');
1097
+ }
1098
+ }
1099
+
1100
+ contextPrototype.fill = function() {
1101
+ this.stroke(true);
1102
+ };
1103
+
1104
+ contextPrototype.closePath = function() {
1105
+ this.currentPath_.push({type: 'close'});
1106
+ };
1107
+
1108
+ /**
1109
+ * @private
1110
+ */
1111
+ contextPrototype.getCoords_ = function(aX, aY) {
1112
+ var m = this.m_;
1113
+ return {
1114
+ x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
1115
+ y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
1116
+ };
1117
+ };
1118
+
1119
+ contextPrototype.save = function() {
1120
+ var o = {};
1121
+ copyState(this, o);
1122
+ this.aStack_.push(o);
1123
+ this.mStack_.push(this.m_);
1124
+ this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
1125
+ };
1126
+
1127
+ contextPrototype.restore = function() {
1128
+ if (this.aStack_.length) {
1129
+ copyState(this.aStack_.pop(), this);
1130
+ this.m_ = this.mStack_.pop();
1131
+ }
1132
+ };
1133
+
1134
+ function matrixIsFinite(m) {
1135
+ return isFinite(m[0][0]) && isFinite(m[0][1]) &&
1136
+ isFinite(m[1][0]) && isFinite(m[1][1]) &&
1137
+ isFinite(m[2][0]) && isFinite(m[2][1]);
1138
+ }
1139
+
1140
+ function setM(ctx, m, updateLineScale) {
1141
+ if (!matrixIsFinite(m)) {
1142
+ return;
1143
+ }
1144
+ ctx.m_ = m;
1145
+
1146
+ if (updateLineScale) {
1147
+ // Get the line scale.
1148
+ // Determinant of this.m_ means how much the area is enlarged by the
1149
+ // transformation. So its square root can be used as a scale factor
1150
+ // for width.
1151
+ var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
1152
+ ctx.lineScale_ = sqrt(abs(det));
1153
+ }
1154
+ }
1155
+
1156
+ contextPrototype.translate = function(aX, aY) {
1157
+ var m1 = [
1158
+ [1, 0, 0],
1159
+ [0, 1, 0],
1160
+ [aX, aY, 1]
1161
+ ];
1162
+
1163
+ setM(this, matrixMultiply(m1, this.m_), false);
1164
+ };
1165
+
1166
+ contextPrototype.rotate = function(aRot) {
1167
+ var c = mc(aRot);
1168
+ var s = ms(aRot);
1169
+
1170
+ var m1 = [
1171
+ [c, s, 0],
1172
+ [-s, c, 0],
1173
+ [0, 0, 1]
1174
+ ];
1175
+
1176
+ setM(this, matrixMultiply(m1, this.m_), false);
1177
+ };
1178
+
1179
+ contextPrototype.scale = function(aX, aY) {
1180
+ this.arcScaleX_ *= aX;
1181
+ this.arcScaleY_ *= aY;
1182
+ var m1 = [
1183
+ [aX, 0, 0],
1184
+ [0, aY, 0],
1185
+ [0, 0, 1]
1186
+ ];
1187
+
1188
+ setM(this, matrixMultiply(m1, this.m_), true);
1189
+ };
1190
+
1191
+ contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
1192
+ var m1 = [
1193
+ [m11, m12, 0],
1194
+ [m21, m22, 0],
1195
+ [dx, dy, 1]
1196
+ ];
1197
+
1198
+ setM(this, matrixMultiply(m1, this.m_), true);
1199
+ };
1200
+
1201
+ contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
1202
+ var m = [
1203
+ [m11, m12, 0],
1204
+ [m21, m22, 0],
1205
+ [dx, dy, 1]
1206
+ ];
1207
+
1208
+ setM(this, m, true);
1209
+ };
1210
+
1211
+ /**
1212
+ * The text drawing function.
1213
+ * The maxWidth argument isn't taken in account, since no browser supports
1214
+ * it yet.
1215
+ */
1216
+ contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
1217
+ var m = this.m_,
1218
+ delta = 1000,
1219
+ left = 0,
1220
+ right = delta,
1221
+ offset = {x: 0, y: 0},
1222
+ lineStr = [];
1223
+
1224
+ var fontStyle = getComputedStyle(processFontStyle(this.font),
1225
+ this.element_);
1226
+
1227
+ var fontStyleString = buildStyle(fontStyle);
1228
+
1229
+ var elementStyle = this.element_.currentStyle;
1230
+ var textAlign = this.textAlign.toLowerCase();
1231
+ switch (textAlign) {
1232
+ case 'left':
1233
+ case 'center':
1234
+ case 'right':
1235
+ break;
1236
+ case 'end':
1237
+ textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
1238
+ break;
1239
+ case 'start':
1240
+ textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
1241
+ break;
1242
+ default:
1243
+ textAlign = 'left';
1244
+ }
1245
+
1246
+ // 1.75 is an arbitrary number, as there is no info about the text baseline
1247
+ switch (this.textBaseline) {
1248
+ case 'hanging':
1249
+ case 'top':
1250
+ offset.y = fontStyle.size / 1.75;
1251
+ break;
1252
+ case 'middle':
1253
+ break;
1254
+ default:
1255
+ case null:
1256
+ case 'alphabetic':
1257
+ case 'ideographic':
1258
+ case 'bottom':
1259
+ offset.y = -fontStyle.size / 2.25;
1260
+ break;
1261
+ }
1262
+
1263
+ switch(textAlign) {
1264
+ case 'right':
1265
+ left = delta;
1266
+ right = 0.05;
1267
+ break;
1268
+ case 'center':
1269
+ left = right = delta / 2;
1270
+ break;
1271
+ }
1272
+
1273
+ var d = this.getCoords_(x + offset.x, y + offset.y);
1274
+
1275
+ lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
1276
+ ' coordsize="100 100" coordorigin="0 0"',
1277
+ ' filled="', !stroke, '" stroked="', !!stroke,
1278
+ '" style="position:absolute;width:1px;height:1px;">');
1279
+
1280
+ if (stroke) {
1281
+ appendStroke(this, lineStr);
1282
+ } else {
1283
+ // TODO: Fix the min and max params.
1284
+ appendFill(this, lineStr, {x: -left, y: 0},
1285
+ {x: right, y: fontStyle.size});
1286
+ }
1287
+
1288
+ var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
1289
+ m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
1290
+
1291
+ var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
1292
+
1293
+ lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
1294
+ ' offset="', skewOffset, '" origin="', left ,' 0" />',
1295
+ '<g_vml_:path textpathok="true" />',
1296
+ '<g_vml_:textpath on="true" string="',
1297
+ encodeHtmlAttribute(text),
1298
+ '" style="v-text-align:', textAlign,
1299
+ ';font:', encodeHtmlAttribute(fontStyleString),
1300
+ '" /></g_vml_:line>');
1301
+
1302
+ this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
1303
+ };
1304
+
1305
+ contextPrototype.fillText = function(text, x, y, maxWidth) {
1306
+ this.drawText_(text, x, y, maxWidth, false);
1307
+ };
1308
+
1309
+ contextPrototype.strokeText = function(text, x, y, maxWidth) {
1310
+ this.drawText_(text, x, y, maxWidth, true);
1311
+ };
1312
+
1313
+ contextPrototype.measureText = function(text) {
1314
+ if (!this.textMeasureEl_) {
1315
+ var s = '<span style="position:absolute;' +
1316
+ 'top:-20000px;left:0;padding:0;margin:0;border:none;' +
1317
+ 'white-space:pre;"></span>';
1318
+ this.element_.insertAdjacentHTML('beforeEnd', s);
1319
+ this.textMeasureEl_ = this.element_.lastChild;
1320
+ }
1321
+ var doc = this.element_.ownerDocument;
1322
+ this.textMeasureEl_.innerHTML = '';
1323
+ this.textMeasureEl_.style.font = this.font;
1324
+ // Don't use innerHTML or innerText because they allow markup/whitespace.
1325
+ this.textMeasureEl_.appendChild(doc.createTextNode(text));
1326
+ return {width: this.textMeasureEl_.offsetWidth};
1327
+ };
1328
+
1329
+ /******** STUBS ********/
1330
+ contextPrototype.clip = function() {
1331
+ // TODO: Implement
1332
+ };
1333
+
1334
+ contextPrototype.arcTo = function() {
1335
+ // TODO: Implement
1336
+ };
1337
+
1338
+ contextPrototype.createPattern = function(image, repetition) {
1339
+ return new CanvasPattern_(image, repetition);
1340
+ };
1341
+
1342
+ // Gradient / Pattern Stubs
1343
+ function CanvasGradient_(aType) {
1344
+ this.type_ = aType;
1345
+ this.x0_ = 0;
1346
+ this.y0_ = 0;
1347
+ this.r0_ = 0;
1348
+ this.x1_ = 0;
1349
+ this.y1_ = 0;
1350
+ this.r1_ = 0;
1351
+ this.colors_ = [];
1352
+ }
1353
+
1354
+ CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
1355
+ aColor = processStyle(aColor);
1356
+ this.colors_.push({offset: aOffset,
1357
+ color: aColor.color,
1358
+ alpha: aColor.alpha});
1359
+ };
1360
+
1361
+ function CanvasPattern_(image, repetition) {
1362
+ assertImageIsValid(image);
1363
+ switch (repetition) {
1364
+ case 'repeat':
1365
+ case null:
1366
+ case '':
1367
+ this.repetition_ = 'repeat';
1368
+ break
1369
+ case 'repeat-x':
1370
+ case 'repeat-y':
1371
+ case 'no-repeat':
1372
+ this.repetition_ = repetition;
1373
+ break;
1374
+ default:
1375
+ throwException('SYNTAX_ERR');
1376
+ }
1377
+
1378
+ this.src_ = image.src;
1379
+ this.width_ = image.width;
1380
+ this.height_ = image.height;
1381
+ }
1382
+
1383
+ function throwException(s) {
1384
+ throw new DOMException_(s);
1385
+ }
1386
+
1387
+ function assertImageIsValid(img) {
1388
+ if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
1389
+ throwException('TYPE_MISMATCH_ERR');
1390
+ }
1391
+ if (img.readyState != 'complete') {
1392
+ throwException('INVALID_STATE_ERR');
1393
+ }
1394
+ }
1395
+
1396
+ function DOMException_(s) {
1397
+ this.code = this[s];
1398
+ this.message = s +': DOM Exception ' + this.code;
1399
+ }
1400
+ var p = DOMException_.prototype = new Error;
1401
+ p.INDEX_SIZE_ERR = 1;
1402
+ p.DOMSTRING_SIZE_ERR = 2;
1403
+ p.HIERARCHY_REQUEST_ERR = 3;
1404
+ p.WRONG_DOCUMENT_ERR = 4;
1405
+ p.INVALID_CHARACTER_ERR = 5;
1406
+ p.NO_DATA_ALLOWED_ERR = 6;
1407
+ p.NO_MODIFICATION_ALLOWED_ERR = 7;
1408
+ p.NOT_FOUND_ERR = 8;
1409
+ p.NOT_SUPPORTED_ERR = 9;
1410
+ p.INUSE_ATTRIBUTE_ERR = 10;
1411
+ p.INVALID_STATE_ERR = 11;
1412
+ p.SYNTAX_ERR = 12;
1413
+ p.INVALID_MODIFICATION_ERR = 13;
1414
+ p.NAMESPACE_ERR = 14;
1415
+ p.INVALID_ACCESS_ERR = 15;
1416
+ p.VALIDATION_ERR = 16;
1417
+ p.TYPE_MISMATCH_ERR = 17;
1418
+
1419
+ // set up externs
1420
+ G_vmlCanvasManager = G_vmlCanvasManager_;
1421
+ CanvasRenderingContext2D = CanvasRenderingContext2D_;
1422
+ CanvasGradient = CanvasGradient_;
1423
+ CanvasPattern = CanvasPattern_;
1424
+ DOMException = DOMException_;
1425
+ })();
1426
+
1427
+ } // if