ela 1.1.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 (300) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.gitlab-ci.yml +23 -0
  4. data/Gemfile +7 -0
  5. data/Gemfile.lock +139 -0
  6. data/Guardfile +25 -0
  7. data/LICENSE.txt +205 -0
  8. data/README.de.md +195 -0
  9. data/README.md +66 -0
  10. data/Rakefile +96 -0
  11. data/app/css/screen.styl +425 -0
  12. data/app/css/vendor/stackedit.styl +140 -0
  13. data/app/fonts/Roboto-Italic-webfont.eot +0 -0
  14. data/app/fonts/Roboto-Italic-webfont.svg +642 -0
  15. data/app/fonts/Roboto-Italic-webfont.ttf +0 -0
  16. data/app/fonts/Roboto-Italic-webfont.woff +0 -0
  17. data/app/fonts/Roboto-Light-webfont.eot +0 -0
  18. data/app/fonts/Roboto-Light-webfont.svg +641 -0
  19. data/app/fonts/Roboto-Light-webfont.ttf +0 -0
  20. data/app/fonts/Roboto-Light-webfont.woff +0 -0
  21. data/app/fonts/Roboto-LightItalic-webfont.eot +0 -0
  22. data/app/fonts/Roboto-LightItalic-webfont.svg +641 -0
  23. data/app/fonts/Roboto-LightItalic-webfont.ttf +0 -0
  24. data/app/fonts/Roboto-LightItalic-webfont.woff +0 -0
  25. data/app/fonts/Roboto-Medium-webfont.eot +0 -0
  26. data/app/fonts/Roboto-Medium-webfont.svg +593 -0
  27. data/app/fonts/Roboto-Medium-webfont.ttf +0 -0
  28. data/app/fonts/Roboto-Medium-webfont.woff +0 -0
  29. data/app/fonts/Roboto-MediumItalic-webfont.eot +0 -0
  30. data/app/fonts/Roboto-MediumItalic-webfont.svg +642 -0
  31. data/app/fonts/Roboto-MediumItalic-webfont.ttf +0 -0
  32. data/app/fonts/Roboto-MediumItalic-webfont.woff +0 -0
  33. data/app/fonts/Roboto-Regular-webfont.eot +0 -0
  34. data/app/fonts/Roboto-Regular-webfont.svg +621 -0
  35. data/app/fonts/Roboto-Regular-webfont.ttf +0 -0
  36. data/app/fonts/Roboto-Regular-webfont.woff +0 -0
  37. data/app/fonts/Roboto-Thin-webfont.eot +0 -0
  38. data/app/fonts/Roboto-Thin-webfont.svg +631 -0
  39. data/app/fonts/Roboto-Thin-webfont.ttf +0 -0
  40. data/app/fonts/Roboto-Thin-webfont.woff +0 -0
  41. data/app/fonts/Roboto-ThinItalic-webfont.eot +0 -0
  42. data/app/fonts/Roboto-ThinItalic-webfont.svg +631 -0
  43. data/app/fonts/Roboto-ThinItalic-webfont.ttf +0 -0
  44. data/app/fonts/Roboto-ThinItalic-webfont.woff +0 -0
  45. data/app/fonts/droid_sans_regular.typeface.svg +1 -0
  46. data/app/fonts/fontawesome-webfont.eot +0 -0
  47. data/app/fonts/fontawesome-webfont.svg +2671 -0
  48. data/app/fonts/fontawesome-webfont.ttf +0 -0
  49. data/app/fonts/fontawesome-webfont.woff +0 -0
  50. data/app/fonts/fontawesome-webfont.woff2 +0 -0
  51. data/app/js/lib/application.coffee +83 -0
  52. data/app/js/lib/bootstrap_data.coffee +70 -0
  53. data/app/js/lib/collections/00_limited_collection.coffee +85 -0
  54. data/app/js/lib/collections/curves.coffee +3 -0
  55. data/app/js/lib/collections/named_object_collection.coffee +7 -0
  56. data/app/js/lib/mathjaxConfig.coffee +241 -0
  57. data/app/js/lib/models/app.coffee +58 -0
  58. data/app/js/lib/models/base_app.coffee +62 -0
  59. data/app/js/lib/models/base_app_model.coffee +61 -0
  60. data/app/js/lib/models/base_calculator.coffee +212 -0
  61. data/app/js/lib/models/base_subapp_container.coffee +35 -0
  62. data/app/js/lib/models/curve.coffee +179 -0
  63. data/app/js/lib/router.coffee +26 -0
  64. data/app/js/lib/views/app.coffee +56 -0
  65. data/app/js/lib/views/base_app.coffee +274 -0
  66. data/app/js/lib/views/base_aside.coffee +9 -0
  67. data/app/js/lib/views/base_graph.coffee +477 -0
  68. data/app/js/lib/views/base_subapp_container.coffee +44 -0
  69. data/app/js/lib/views/canvas.coffee +73 -0
  70. data/app/js/lib/views/curve_graph.coffee +163 -0
  71. data/app/js/lib/views/curves_aside.coffee +21 -0
  72. data/app/js/lib/views/curves_list_item.coffee +8 -0
  73. data/app/js/lib/views/grouped_parameters_aside.coffee +14 -0
  74. data/app/js/lib/views/headup.coffee +15 -0
  75. data/app/js/lib/views/help.coffee +86 -0
  76. data/app/js/lib/views/interpolated_graph.coffee +281 -0
  77. data/app/js/lib/views/legend.coffee +138 -0
  78. data/app/js/lib/views/legend_handler.coffee +51 -0
  79. data/app/js/lib/views/overview.coffee +85 -0
  80. data/app/js/lib/views/overview_tile.coffee +18 -0
  81. data/app/js/lib/views/parameters_aside.coffee +12 -0
  82. data/app/js/lib/views/three_graph.coffee +92 -0
  83. data/app/js/vendor/Markdown.Converter.js +1519 -0
  84. data/app/js/vendor/Markdown.Extra.js +874 -0
  85. data/app/js/vendor/Markdown.Toc.coffee +79 -0
  86. data/app/js/vendor/backbone-1.3.3.min.js +2 -0
  87. data/app/js/vendor/backbone-validation-0.11.5.js +8 -0
  88. data/app/js/vendor/backbone.poised/form.coffee +156 -0
  89. data/app/js/vendor/backbone.poised/form/anchor.coffee +26 -0
  90. data/app/js/vendor/backbone.poised/form/base_control.coffee +42 -0
  91. data/app/js/vendor/backbone.poised/form/linked_control.coffee +79 -0
  92. data/app/js/vendor/backbone.poised/form/linked_number_control.coffee +27 -0
  93. data/app/js/vendor/backbone.poised/form/linked_range_control.coffee +53 -0
  94. data/app/js/vendor/backbone.poised/form/linked_select_control.coffee +18 -0
  95. data/app/js/vendor/backbone.poised/form/linked_string_control.coffee +27 -0
  96. data/app/js/vendor/backbone.poised/form/number_control.coffee +25 -0
  97. data/app/js/vendor/backbone.poised/form/range_control.coffee +48 -0
  98. data/app/js/vendor/backbone.poised/form/select_control.coffee +16 -0
  99. data/app/js/vendor/backbone.poised/form/selectbox.coffee +78 -0
  100. data/app/js/vendor/backbone.poised/form/slider.coffee +109 -0
  101. data/app/js/vendor/backbone.poised/form/string_control.coffee +23 -0
  102. data/app/js/vendor/backbone.poised/form/submit_control.coffee +39 -0
  103. data/app/js/vendor/backbone.poised/form/textarea.coffee +36 -0
  104. data/app/js/vendor/backbone.poised/form/textfield.coffee +86 -0
  105. data/app/js/vendor/backbone.poised/form/value.coffee +33 -0
  106. data/app/js/vendor/backbone.poised/form/value_control.coffee +15 -0
  107. data/app/js/vendor/backbone.poised/linked_form.coffee +43 -0
  108. data/app/js/vendor/backbone.poised/list.coffee +97 -0
  109. data/app/js/vendor/backbone.poised/list/add_button.coffee +16 -0
  110. data/app/js/vendor/backbone.poised/list/anchor.coffee +32 -0
  111. data/app/js/vendor/backbone.poised/list/item.coffee +68 -0
  112. data/app/js/vendor/backbone.poised/list/searchfield.coffee +26 -0
  113. data/app/js/vendor/backbone.poised/list/selectable_item.coffee +65 -0
  114. data/app/js/vendor/backbone.poised/patches.coffee +6 -0
  115. data/app/js/vendor/backbone.poised/string_mixin.coffee +23 -0
  116. data/app/js/vendor/backbone.poised/underscore_ext.coffee +2 -0
  117. data/app/js/vendor/backbone.poised/view.coffee +59 -0
  118. data/app/js/vendor/gaussianElimination.coffee +40 -0
  119. data/app/js/vendor/hammer-2.0.8.min.js +7 -0
  120. data/app/js/vendor/jquery-3.1.1.min.js +4 -0
  121. data/app/js/vendor/jquery.after-transition.coffee +20 -0
  122. data/app/js/vendor/jquery.backbone-hammer.coffee +28 -0
  123. data/app/js/vendor/jquery.keyboard-modifiers.coffee +22 -0
  124. data/app/js/vendor/jquery.mark-5.2.3.min.js +7 -0
  125. data/app/js/vendor/jquery.scrollTo-2.1.2.min.js +7 -0
  126. data/app/js/vendor/js-yaml-3.4.3.min.js +3 -0
  127. data/app/js/vendor/markup_text.coffee +95 -0
  128. data/app/js/vendor/mathjax/MathJax.js +19 -0
  129. data/app/js/vendor/mathjax/extensions/MathEvents.js +19 -0
  130. data/app/js/vendor/mathjax/extensions/tex2jax.js +19 -0
  131. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot +0 -0
  132. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot +0 -0
  133. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot +0 -0
  134. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot +0 -0
  135. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot +0 -0
  136. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot +0 -0
  137. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot +0 -0
  138. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot +0 -0
  139. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot +0 -0
  140. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot +0 -0
  141. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Regular.eot +0 -0
  142. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot +0 -0
  143. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot +0 -0
  144. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot +0 -0
  145. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot +0 -0
  146. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot +0 -0
  147. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot +0 -0
  148. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot +0 -0
  149. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot +0 -0
  150. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot +0 -0
  151. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_WinIE6-Regular.eot +0 -0
  152. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf +0 -0
  153. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf +0 -0
  154. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf +0 -0
  155. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf +0 -0
  156. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf +0 -0
  157. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf +0 -0
  158. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf +0 -0
  159. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf +0 -0
  160. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf +0 -0
  161. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf +0 -0
  162. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Regular.otf +0 -0
  163. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf +0 -0
  164. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf +0 -0
  165. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf +0 -0
  166. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf +0 -0
  167. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf +0 -0
  168. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf +0 -0
  169. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf +0 -0
  170. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf +0 -0
  171. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf +0 -0
  172. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinChrome-Regular.otf +0 -0
  173. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinIE6-Regular.otf +0 -0
  174. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_AMS-Regular.svg +765 -0
  175. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Bold.svg +136 -0
  176. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Regular.svg +134 -0
  177. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Bold.svg +319 -0
  178. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Regular.svg +309 -0
  179. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Bold.svg +656 -0
  180. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Italic.svg +374 -0
  181. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Regular.svg +659 -0
  182. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-BoldItalic.svg +331 -0
  183. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Italic.svg +331 -0
  184. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Regular.svg +330 -0
  185. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Bold.svg +280 -0
  186. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Italic.svg +245 -0
  187. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Regular.svg +211 -0
  188. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Script-Regular.svg +160 -0
  189. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size1-Regular.svg +110 -0
  190. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size2-Regular.svg +109 -0
  191. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size3-Regular.svg +49 -0
  192. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size4-Regular.svg +102 -0
  193. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Typewriter-Regular.svg +322 -0
  194. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_WinChrome-Regular.svg +39 -0
  195. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff +0 -0
  196. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff +0 -0
  197. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff +0 -0
  198. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff +0 -0
  199. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff +0 -0
  200. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff +0 -0
  201. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff +0 -0
  202. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff +0 -0
  203. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff +0 -0
  204. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff +0 -0
  205. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Regular.woff +0 -0
  206. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff +0 -0
  207. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff +0 -0
  208. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff +0 -0
  209. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff +0 -0
  210. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff +0 -0
  211. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff +0 -0
  212. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff +0 -0
  213. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff +0 -0
  214. data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff +0 -0
  215. data/app/js/vendor/mathjax/jax/element/mml/jax.js +19 -0
  216. data/app/js/vendor/mathjax/jax/element/mml/optable/Arrows.js +19 -0
  217. data/app/js/vendor/mathjax/jax/element/mml/optable/BasicLatin.js +19 -0
  218. data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiacritMarks.js +19 -0
  219. data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiactForSymbols.js +19 -0
  220. data/app/js/vendor/mathjax/jax/element/mml/optable/Dingbats.js +19 -0
  221. data/app/js/vendor/mathjax/jax/element/mml/optable/GeneralPunctuation.js +19 -0
  222. data/app/js/vendor/mathjax/jax/element/mml/optable/GeometricShapes.js +19 -0
  223. data/app/js/vendor/mathjax/jax/element/mml/optable/GreekAndCoptic.js +19 -0
  224. data/app/js/vendor/mathjax/jax/element/mml/optable/Latin1Supplement.js +19 -0
  225. data/app/js/vendor/mathjax/jax/element/mml/optable/LetterlikeSymbols.js +19 -0
  226. data/app/js/vendor/mathjax/jax/element/mml/optable/MathOperators.js +19 -0
  227. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsA.js +19 -0
  228. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsB.js +19 -0
  229. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscSymbolsAndArrows.js +19 -0
  230. data/app/js/vendor/mathjax/jax/element/mml/optable/MiscTechnical.js +19 -0
  231. data/app/js/vendor/mathjax/jax/element/mml/optable/SpacingModLetters.js +19 -0
  232. data/app/js/vendor/mathjax/jax/element/mml/optable/SuppMathOperators.js +19 -0
  233. data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsA.js +19 -0
  234. data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsB.js +19 -0
  235. data/app/js/vendor/mathjax/jax/input/TeX/config.js +19 -0
  236. data/app/js/vendor/mathjax/jax/input/TeX/jax.js +19 -0
  237. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/annotation-xml.js +19 -0
  238. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/maction.js +19 -0
  239. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/menclose.js +19 -0
  240. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mglyph.js +19 -0
  241. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mmultiscripts.js +19 -0
  242. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/ms.js +19 -0
  243. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mtable.js +19 -0
  244. data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/multiline.js +19 -0
  245. data/app/js/vendor/mathjax/jax/output/CommonHTML/config.js +19 -0
  246. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/AMS-Regular.js +19 -0
  247. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Caligraphic-Bold.js +19 -0
  248. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Bold.js +19 -0
  249. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Regular.js +19 -0
  250. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Main-Bold.js +19 -0
  251. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Math-BoldItalic.js +19 -0
  252. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Bold.js +19 -0
  253. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Italic.js +19 -0
  254. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Regular.js +19 -0
  255. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Script-Regular.js +19 -0
  256. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Typewriter-Regular.js +19 -0
  257. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata-extra.js +19 -0
  258. data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata.js +19 -0
  259. data/app/js/vendor/mathjax/jax/output/CommonHTML/jax.js +19 -0
  260. data/app/js/vendor/modernizr-custom-3.3.1.min.js +3 -0
  261. data/app/js/vendor/persistjs-git.js +1136 -0
  262. data/app/js/vendor/poised/poised.general.coffee +21 -0
  263. data/app/js/vendor/poised/poised.tabs.coffee +31 -0
  264. data/app/js/vendor/poised/utils.coffee +11 -0
  265. data/app/js/vendor/request_animation_frame.coffee +19 -0
  266. data/app/js/vendor/three-82.min.js +15 -0
  267. data/app/js/vendor/three-CanvasRenderer-82.js +1118 -0
  268. data/app/js/vendor/three-Projector-82.js +929 -0
  269. data/app/js/vendor/underscore-1.8.3.min.js +6 -0
  270. data/app/js/vendor/webfontloader-1.6.26.min.js +33 -0
  271. data/app/views/aliasing/legend.jst.hamlc +6 -0
  272. data/app/views/composites/composites_list_item_label.jst.hamlc +3 -0
  273. data/app/views/composites/import_composites_aside.jst.hamlc +6 -0
  274. data/app/views/composites/mix_preset_list_item_label.jst.hamlc +8 -0
  275. data/app/views/composites/share_aside.jst.hamlc +7 -0
  276. data/app/views/doc/airplanes_list_item_label.jst.hamlc +3 -0
  277. data/app/views/doc/import_airplanes_aside.jst.hamlc +6 -0
  278. data/app/views/doc/share_aside.jst.hamlc +7 -0
  279. data/app/views/general/app.jst.hamlc +42 -0
  280. data/app/views/general/curves_list_item_label.jst.hamlc +5 -0
  281. data/app/views/general/help.jst.hamlc +7 -0
  282. data/app/views/general/tabs.jst.hamlc +6 -0
  283. data/app/views/index.haml +24 -0
  284. data/app/views/overview/app.jst.hamlc +7 -0
  285. data/app/views/overview/tile.jst.hamlc +4 -0
  286. data/bin/console +14 -0
  287. data/bin/setup +8 -0
  288. data/ela.gemspec +50 -0
  289. data/exe/ela +59 -0
  290. data/lib/ela.rb +8 -0
  291. data/lib/ela/jasmine.rb +87 -0
  292. data/lib/ela/server.rb +136 -0
  293. data/lib/ela/utils.rb +131 -0
  294. data/lib/ela/version.rb +3 -0
  295. data/package-lock.json +899 -0
  296. data/package.json +11 -0
  297. data/support/project/Guardfile +64 -0
  298. data/support/project/jasmine.yml +3 -0
  299. data/support/server.ru +5 -0
  300. metadata +4365 -0
@@ -0,0 +1,26 @@
1
+ class ELA.Router extends Backbone.Router
2
+ routes:
3
+ '': 'index'
4
+ '(app/)*path': 'load'
5
+
6
+ initialize: ->
7
+ ELA.store = new Persist.Store('ilr_app')
8
+ ELA.app = new ELA.Models.App()
9
+ ELA.view = new ELA.Views.App
10
+ model: ELA.app
11
+ el: $('#app')
12
+ ELA.view.render()
13
+
14
+ index: ->
15
+ ELA.app.set(path: null)
16
+
17
+ load: (path, params) ->
18
+ if params?
19
+ try
20
+ params = JSON.parse(decodeURI(params))
21
+ catch
22
+ alert(t('messages.invalidParameters'))
23
+ params = null
24
+ ELA.app.set
25
+ path: path.split('/')
26
+ params: params
@@ -0,0 +1,56 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.App extends Backbone.View
3
+ initialize: ->
4
+ @subviews = {}
5
+ @listenTo @model, 'change:currentAppModel', @render
6
+ @listenTo @model, 'change:showAbout', @renderAbout
7
+
8
+ # @returns BaseApp or BaseSubappContainer
9
+ currentAppModel: -> @model.currentAppModel()
10
+
11
+ activateSubviews: =>
12
+ if @currentAppModel()
13
+ @subviews.index?.deactivate()
14
+ @subviews.app?.activate()
15
+ else
16
+ @subviews.index?.activate()
17
+ @subviews.app?.deactivate()
18
+
19
+ loadedViewName: ->
20
+ @subviews.app?.model.name
21
+
22
+ currentAppModelName: ->
23
+ @model.currentAppModel()?.name
24
+
25
+ renderAbout: =>
26
+ showAbout = @model.get('showAbout')
27
+ if showAbout and not @subviews.help?
28
+ @subviews.help = view = new ELA.Views.Help
29
+ model: @model
30
+ @$el.append(view.render().el)
31
+
32
+ delay =>
33
+ @subviews.help?.setActive(showAbout)
34
+ @subviews.index?.setActive(not showAbout)
35
+
36
+ render: =>
37
+ unless @subviews.index?
38
+ @subviews.index = new ELA.Views.Overview()
39
+ @$el.append(@subviews.index.render().el)
40
+
41
+ if @subviews.app and @loadedViewName() isnt @currentAppModelName()
42
+ @subviews.app.remove()
43
+ delete @subviews.app
44
+
45
+ if @model.currentAppModel() and not @subviews.app?
46
+ AppView = @model.currentNamespace().Views.App
47
+ @subviews.app = view = new AppView
48
+ model: @model.currentAppModel()
49
+ localePrefix: @model.currentAppModel().localePrefix()
50
+ @$el.append(view.render().el)
51
+
52
+ @renderAbout()
53
+
54
+ delay @activateSubviews
55
+
56
+ this
@@ -0,0 +1,274 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.BaseApp extends Backbone.Poised.View
3
+ template: JST['general/app']
4
+
5
+ id: -> @model.name.toDash()
6
+ tagName: 'section'
7
+ className: 'active'
8
+
9
+ # Typically in a subclass we override the list of asides. This may
10
+ # be a list of classes inheriting from ELA.Views.BaseAside or an
11
+ # object with `name` and `klass` attributes.
12
+ asideViews: []
13
+
14
+ legendView: null
15
+
16
+ graphView: null
17
+ graphOverlayView: null
18
+ graphDefaults: {}
19
+
20
+ rangeHandlerView: null
21
+
22
+ # TODO: Rename valueAtRange name pattern to something like selectValue
23
+ # TODO: use correct attribute in every app instead of generic valueAtRange
24
+ valueAtRange: null
25
+ valueAtRangeAxis: 'x'
26
+ valueAtRangeAttribute: 'valueAtRange'
27
+ valueAtRangePrecision: null
28
+
29
+ legendValueAtRange: null
30
+ legendValueAtRangeAxis: null
31
+ legendValueAtRangeAttribute: null
32
+
33
+ useHeadup: false
34
+
35
+ events:
36
+ 'tap header .overview.icon': 'backToOverview'
37
+ 'tap header .help': 'showHelp'
38
+ 'tap header .share-link': 'share'
39
+ 'tap header .share-form input': 'selectShareLink'
40
+ 'tap header .share-form button': 'copyShareLink'
41
+ 'submit header .share-form form': (e) -> e.preventDefault()
42
+ 'tap header *[data-toggle-aside]': 'setCurrentAside'
43
+ 'tap header .poised.subapps.select': 'viewSubappOptions'
44
+ 'tap header .poised.subapps.select .option': 'openSubapp'
45
+ 'tap header .context.icon': 'toggleContextMenu'
46
+ 'tap article.graph:has(~ aside.active)': 'hideAsides'
47
+ 'tap section:has(.subapps.select.view)': 'hideSubappOptions'
48
+ 'tap section:has(.menu.view)': 'hideMenus'
49
+
50
+ hammerjs: true
51
+
52
+ remove: =>
53
+ @$el.afterTransitionForRemovingClass 'active', => super
54
+
55
+ initialize: ->
56
+ @listenTo @model, 'change:currentAside', @toggleAside
57
+ @listenTo @model, 'change:showHelp', @renderHelp
58
+ if @useHeadup
59
+ @on 'controlLiveChangeStart', @liveChangeStart
60
+ @on 'controlLiveChangeEnd', @liveChangeEnd
61
+
62
+ for asideView in @asideViews
63
+ asideView.link ?= 'icon'
64
+
65
+ if @graphView?
66
+ GraphParams = @graphView.toFunction()['Params']
67
+ @model.displayParams = new GraphParams if GraphParams?
68
+
69
+ viewSubappOptions: =>
70
+ @$('.subapps.select').toggleClass('view')
71
+
72
+ hideSubappOptions: =>
73
+ @$('.subapps.select').removeClass('view')
74
+
75
+ toggleContextMenu: =>
76
+ @$('.menu:has(.icon.context)').toggleClass('view')
77
+
78
+ hideMenus: (e) =>
79
+ unless e? and $(e.target).closest(@$shareLink.add(@$shareForm)).length
80
+ @$('.menu').removeClass('view')
81
+ @$shareForm.addClass('hidden')
82
+ @$shareCopyButton.removeClass('success failure').addClass('copy')
83
+ @$shareLink.removeClass('hidden')
84
+
85
+ openSubapp: (e) =>
86
+ $target = $(e.target)
87
+ ELA.router.navigate("app/#{$target.data('path')}", trigger: true)
88
+
89
+ showHelp: =>
90
+ ELA.router.navigate("app/#{@model.path}/help", trigger: true)
91
+
92
+ share: =>
93
+ @$shareUrlInput.val(ELA.app.url())
94
+ @$shareLink.addClass('hidden')
95
+ @$shareForm.removeClass('hidden')
96
+
97
+ selectShareLink: =>
98
+ @$shareUrlInput.select()
99
+
100
+ copyShareLink: =>
101
+ @selectShareLink()
102
+ if document.execCommand('copy')
103
+ @$shareCopyButton.removeClass('copy').addClass('success')
104
+ else
105
+ @$shareCopyButton.removeClass('copy').addClass('failure')
106
+
107
+ setCurrentAside: (e) =>
108
+ asideToToggle = $(e.currentTarget).data('toggle-aside')
109
+ currentAside = @model.get('currentAside')
110
+ if currentAside is asideToToggle
111
+ @model.set currentAside: null
112
+ else
113
+ @model.set currentAside: asideToToggle
114
+
115
+ hideAsides: =>
116
+ @model.set currentAside: null
117
+
118
+ iconAsideNames: ->
119
+ @_iconAsideNames ?= do =>
120
+ _.compact(_.map(@asideViews, (asideView) ->
121
+ asideView.name if asideView.link is 'icon'
122
+ ))
123
+
124
+ contextAsides: ->
125
+ @_contextAsideNames ?= do =>
126
+ _.compact(_.map(@asideViews, (asideView) =>
127
+ if asideView.link is 'contextMenu'
128
+ name: asideView.name
129
+ label: @loadLocale("contextMenu.#{asideView.name}")
130
+ ))
131
+
132
+ backToOverview: =>
133
+ ELA.router.navigate('/', trigger: true)
134
+
135
+ toggleAside: (model, value) =>
136
+ previous = model.previousAttributes().currentAside
137
+ if previous?
138
+ @$("header .#{previous}.aside.icon").toggleClass('active', false)
139
+ @$("aside.#{previous}").toggleClass('active', false)
140
+ if value?
141
+ @$("header .#{value}.aside.icon").toggleClass('active', true)
142
+ @$("aside.#{value}").toggleClass('active', true)
143
+
144
+ liveChangeStart: (slider) =>
145
+ if $(window).width() <= 768
146
+ @$('aside.active').addClass('hidden')
147
+ @subviews.headup.activate(slider)
148
+
149
+ liveChangeEnd: =>
150
+ if $(window).width() <= 768
151
+ @$('aside.active').removeClass('hidden')
152
+ @subviews.headup.deactivate()
153
+
154
+ setActive: (active) =>
155
+ @$el.toggleClass('active', active)
156
+
157
+ activate: =>
158
+ @$el.toggleClass('active', true)
159
+
160
+ deactivate: =>
161
+ @$el.toggleClass('active', false)
162
+
163
+ relatedApps: =>
164
+ @model.parentApp?.subappInfo() or []
165
+
166
+ renderHelp: =>
167
+ showHelp = @model.get('showHelp')
168
+ if showHelp and not @subviews.help?
169
+ @subviews.help = view = new ELA.Views.Help
170
+ model: @model
171
+ @$el.append(view.render().el)
172
+
173
+ delay =>
174
+ @subviews.help?.setActive(showHelp)
175
+ @$app.toggleClass('active', not showHelp)
176
+
177
+ render: =>
178
+ @$el.html @template
179
+ name: @model.name
180
+ path: @model.path
181
+ hasHelpText: @model.hasHelpText
182
+ iconAsideNames: @iconAsideNames()
183
+ contextAsides: @contextAsides()
184
+ legendView: @legendView?
185
+ graphOverlayView: @graphOverlayView?
186
+ graphView: @graphView?
187
+ rangeHandlerView: @rangeHandlerView?
188
+ useHeadup: @useHeadup
189
+ relatedApps: @relatedApps()
190
+ currentPath: @model.path
191
+ @$shareLink = @$('li.share-link')
192
+ @$shareForm = @$('li.share-form')
193
+ @$shareUrlInput = @$shareForm.find('input')
194
+ @$shareCopyButton = @$shareForm.find('button')
195
+
196
+ @$app = @$('section.app')
197
+ for aside in @asideViews
198
+ AsideView = aside.view.toFunction()
199
+ view = @subviews[aside.name] = new AsideView
200
+ model: @model
201
+ parentView: this
202
+ name: aside.name
203
+ localePrefix: @localePrefix
204
+ @$app.append(view.render().el)
205
+
206
+ if @legendView? and not @subviews.legend
207
+ @$legend = @$('article .legend')
208
+ LegendView = @legendView.toFunction()
209
+ @subviews.legend = view = new LegendView
210
+ model: @model
211
+ parentView: this
212
+ el: @$legend
213
+ useValueAtRange: @legendValueAtRange or @valueAtRange or @rangeHandlerView?
214
+ valueAtRangeAxis: @legendValueAtRangeAxis or @valueAtRangeAxis
215
+ valueAtRangeAttribute: @legendValueAtRangeAttribute or @valueAtRangeAttribute
216
+ localePrefix: @localePrefix
217
+ view.render()
218
+
219
+ if @graphOverlayView? and not @subviews.graphOverlayView
220
+ @$graphOverlay = @$('article .graph-overlay')
221
+ GraphOverlayView = @graphOverlayView.toFunction()
222
+ @subviews.graphOverlayView = view = new GraphOverlayView
223
+ model: @model
224
+ parentView: this
225
+ el: @$graphOverlay
226
+ localPrefix: @localePrefix
227
+ view.render()
228
+
229
+ if @rangeHandlerView? and not @subviews.rangeHandler?
230
+ @$rangeHandler = @$('article .range-handler')
231
+ RangeHandlerView = @rangeHandlerView.toFunction()
232
+ @subviews.rangeHandler = view = new RangeHandlerView
233
+ model: @model
234
+ parentView: this
235
+ el: @$rangeHandler
236
+ axis: @valueAtRangeAxis
237
+ attribute: @valueAtRangeAttribute
238
+ precision: @valueAtRangePrecision
239
+ localePrefix: @localePrefix
240
+ view.render()
241
+
242
+ if @useHeadup and not @subviews.headup?
243
+ @$headup = @$('aside.headup')
244
+ @subviews.headup = new ELA.Views.Headup
245
+ el: @$headup
246
+ localePrefix: @localePrefix
247
+
248
+ delay =>
249
+ if @graphView? and not @subviews.graph
250
+ @$graph = @$('article .graph')
251
+ GraphView = @graphView.toFunction()
252
+ @subviews.graph = view = new GraphView
253
+ model: @model
254
+ parentView: this
255
+ params: @model.displayParams
256
+ defaults: _.defaults
257
+ # Taken from ELA.Views.Canvas::readCanvasResolution
258
+ width: @$graph[0].clientWidth
259
+ height: @$graph[0].clientHeight
260
+ valueAtRangeAxis: @valueAtRangeAxis
261
+ valueAtRangeAttribute: @valueAtRangeAttribute
262
+ , @graphDefaults
263
+ localePrefix: @localePrefix
264
+ @$graph.html(view.render().el)
265
+
266
+ # If the legend uses the value at range feature, it's height
267
+ # may change with updated calculators
268
+ if @subviews.legend?.useValueAtRange
269
+ @listenTo(@model, 'change:calculators', view.readCanvasResolution)
270
+
271
+ @renderHelp()
272
+ @toggleAside(@model, @model.get('currentAside'))
273
+
274
+ this
@@ -0,0 +1,9 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.BaseAside extends Backbone.Poised.View
3
+ tagName: 'aside'
4
+ className: ->
5
+ "#{@asideName} right"
6
+
7
+ constructor: (options = {}) ->
8
+ @asideName = options.name
9
+ super
@@ -0,0 +1,477 @@
1
+ ELA.Views ?= {}
2
+ class ELA.Views.BaseGraph extends ELA.Views.Canvas
3
+ class @Params extends Backbone.Model
4
+ serialize: ->
5
+ xScale: @get('xScale')
6
+ yScale: @get('yScale')
7
+ xOriginRatio: @get('xOrigin') / @get('width')
8
+ yOriginRatio: @get('yOrigin') / @get('height')
9
+
10
+ deserialize: (attributes) ->
11
+ @set
12
+ xScale: attributes.xScale
13
+ yScale: attributes.yScale
14
+ xOrigin: @get('width') * attributes.xOriginRatio
15
+ yOrigin: @get('height') * attributes.yOriginRatio
16
+
17
+ # A variable that contains temporary information about the pinch
18
+ # or pan action that is currently performed.
19
+ start: {}
20
+
21
+ # Contains all view specific parameters that do not belong in the model.
22
+ params: null
23
+
24
+ # We need to cache current pixelRatio to reset the canvas scale.
25
+ pixelRatio: null
26
+
27
+ # Defaults for the view params model.
28
+ defaults:
29
+ xScale: 1.1 # display 10% more than the configured xRange
30
+ yScale: 1.1 # display 10% more than the configured yRange
31
+ xOrigin: 30
32
+ yOrigin: 0
33
+ xOriginAnchor: 'left'
34
+ yOriginAnchor: 'bottom'
35
+ xOriginRatio: null
36
+ yOriginRatio: null
37
+ yOffset: 0
38
+ debug: {}
39
+ xLabelPosition: 'top'
40
+ yLabelPosition: 'right'
41
+ xPanLocked: false
42
+ yPanLocked: false
43
+ xPinchLocked: false
44
+ yPinchLocked: false
45
+ scaleLink: false
46
+
47
+ initialize: ->
48
+ super
49
+
50
+ if @defaults.xOriginRatio? and @defaults.xOriginAnchor isnt 'left'
51
+ @defaults.xOriginRatio = 1 - @defaults.xOriginRatio
52
+ @defaults.xOriginAnchor = 'left'
53
+
54
+ if @defaults.yOriginRatio? and @defaults.yOriginAnchor is 'bottom'
55
+ @defaults.yOriginRatio = 1 - @defaults.yOriginRatio
56
+ @defaults.yOriginAnchor = 'top'
57
+
58
+ @resetCanvas()
59
+
60
+ # @calculateRanges changes params.xyRange
61
+ @params.on 'change:xScale', @calculateRangeX
62
+ @params.on 'change:yScale', @calculateRangeY
63
+ # When xyRange change we need to repaint
64
+ @params.on 'change:xOrigin change:yOrigin change:yRange change:xRange change:width change:height', @requestRepaint
65
+
66
+ @calculateRanges()
67
+
68
+ calculateRangeX: =>
69
+ @params.set xRange: @maxRangeX()
70
+
71
+ calculateRangeY: =>
72
+ @params.set yRange: @maxRangeY()
73
+
74
+ calculateRanges: =>
75
+ @calculateRangeX()
76
+ @calculateRangeY()
77
+
78
+ maxRangeX: (func, xScale = @params.get('xScale')) =>
79
+ xScale * 5
80
+
81
+ maxRangeY: (func, yScale = @params.get('yScale')) =>
82
+ yScale * 5
83
+
84
+ events:
85
+ 'pan': 'pan',
86
+ 'panstart': 'panstart'
87
+ 'panend': 'panend'
88
+ 'pinchstart': 'pinchstart'
89
+ 'pinch': 'pinch'
90
+ 'pinchend': 'pinchend'
91
+ 'doubletap': 'resetCanvas'
92
+ 'mousewheel': 'mousewheel'
93
+ 'DOMMouseScroll': 'mousewheel'
94
+
95
+ hammerjs:
96
+ recognizers: [
97
+ [Hammer.Rotate, { enable: false }],
98
+ [Hammer.Pinch, {}, ['rotate']],
99
+ [Hammer.Swipe,{ enable: false }],
100
+ [Hammer.Pan, { direction: Hammer.DIRECTION_ALL, threshold: 1 }, ['swipe']],
101
+ [Hammer.Tap, { threshold: 5 }],
102
+ [Hammer.Tap, { event: 'doubletap', taps: 2, posThreshold: 20, threshold: 5 }, ['tap']],
103
+ [Hammer.Press, { enable: false }]
104
+ ]
105
+
106
+ mousewheel: (e) =>
107
+ e.preventDefault()
108
+ if e.originalEvent.wheelDelta > 0 or e.originalEvent.detail < 0
109
+ factor = 1.05
110
+ else
111
+ factor = 0.95
112
+ if not @params.get('xPinchLocked') and (not window.keys.ALT or window.keys.SHIFT or @params.get('scaleLink'))
113
+ @params.set xScale: @params.get('xScale') * factor
114
+ if not @params.get('yPinchLocked') and (@params.get('scaleLink') or window.keys.ALT or window.keys.SHIFT)
115
+ @params.set yScale: @params.get('yScale') * factor
116
+
117
+ # Set xScale/yScale and xOrigin/yOrigin to their default values.
118
+ resetCanvas: =>
119
+ clearTimeout(@panendTimeout)
120
+
121
+ if @defaults.xOriginRatio?
122
+ xOrigin = @params.get('width') * @defaults.xOriginRatio
123
+ else if @defaults.xOriginAnchor is 'left'
124
+ xOrigin = @defaults.xOrigin
125
+ else
126
+ xOrigin = @params.get('width') - @defaults.xOrigin
127
+
128
+ if @defaults.yOriginRatio?
129
+ yOrigin = @params.get('height') * @defaults.yOriginRatio
130
+ else if @defaults.yOriginAnchor is 'bottom'
131
+ yOrigin = @params.get('height') - @defaults.yOrigin
132
+ else
133
+ yOrigin = @defaults.yOrigin
134
+
135
+ xScale = @defaults.xScale
136
+ yScale = @defaults.yScale
137
+
138
+ if @params.get('scaleLink')
139
+ # axis with less pixels per unit length should define scale
140
+ if @params.get('width') / @maxRangeX(null, 1) < @params.get('height') / @maxRangeY(null, 1)
141
+ yScale = @linkedYScale(xScale)
142
+ else
143
+ xScale = @linkedXScale(yScale)
144
+
145
+ @params.set
146
+ xScale: xScale
147
+ yScale: yScale
148
+ xOrigin: xOrigin
149
+ yOrigin: yOrigin
150
+
151
+ linkedXScale: (yScale) =>
152
+ # calculate xScale to fulfill the following equation:
153
+ # (width / maxRangeX) / xScale = height / maxRangeY
154
+ (@params.get('width') / @maxRangeX(null, 1)) / (@params.get('height') / @maxRangeY(null, yScale))
155
+
156
+ linkedYScale: (xScale) =>
157
+ # calculate yScale to fulfill the following equation:
158
+ # (height / maxRangeY) / yScale = width / maxRangeX
159
+ (@params.get('height') / @maxRangeY(null, 1)) / (@params.get('width') / @maxRangeX(null, xScale))
160
+
161
+ debugCircle: (context, color, x, y, radius = 20) =>
162
+ context.beginPath()
163
+ context.arc(x,y,radius,0,2*Math.PI,false)
164
+ context.fillStyle = color
165
+ context.fill()
166
+ context.closePath()
167
+
168
+ centerBetweenTouches: (t1, t2) ->
169
+ @centerBetweenPoints(t1.clientX, t1.clientY, t2.clientX, t2.clientY)
170
+
171
+ centerBetweenPoints: (x1, y1, x2, y2) ->
172
+ centerX = null
173
+ if x1 <= x2
174
+ centerX = x1 + (x2 - x1) / 2
175
+ else
176
+ centerX = x2 + (x1 - x2) / 2
177
+ centerY = null
178
+ if y1 <= y2
179
+ centerY = y1 + (y2 - y1) / 2
180
+ else
181
+ centerY = y2 + (y1 - y2) / 2
182
+ { x: centerX, y: centerY }
183
+
184
+ pinchstart: (e) =>
185
+ center = @centerBetweenTouches(e.gesture.pointers[0], e.gesture.pointers[1])
186
+ @start.centerX = center.x
187
+ @start.centerY = center.y
188
+ @start.xOrigin = @params.get('xOrigin')
189
+ @start.yOrigin = @params.get('yOrigin')
190
+ @start.touchDistanceX = Math.max(50, Math.abs(e.gesture.pointers[0].clientX - e.gesture.pointers[1].clientX))
191
+ @start.touchDistanceY = Math.max(50, Math.abs(e.gesture.pointers[0].clientY - e.gesture.pointers[1].clientY))
192
+ @start.xScale = @params.get('xScale')
193
+ @start.yScale = @params.get('yScale')
194
+
195
+ pinch: (e) =>
196
+ center = @centerBetweenTouches(e.gesture.pointers[0], e.gesture.pointers[1])
197
+ deltaX = -(@start.centerX - center.x)
198
+ deltaY = -(@start.centerY - center.y)
199
+
200
+ touchDistanceX = Math.max(50, Math.abs(e.gesture.pointers[0].clientX - e.gesture.pointers[1].clientX))
201
+ touchDistanceY = Math.max(50, Math.abs(e.gesture.pointers[0].clientY - e.gesture.pointers[1].clientY))
202
+ xScale = touchDistanceX / @start.touchDistanceX
203
+ yScale = touchDistanceY / @start.touchDistanceY
204
+
205
+ xScale = yScale = (xScale + yScale)/2 if @params.get('scaleLink')
206
+
207
+ unless @params.get('xPinchLocked')
208
+ @params.set 'xScale', @start.xScale / xScale
209
+ unless @params.get('yPinchLocked')
210
+ @params.set 'yScale', @start.yScale / yScale
211
+ unless @params.get('xPanLocked')
212
+ @params.set xOrigin: @start.centerX + (@start.xOrigin - @start.centerX) * xScale + deltaX
213
+ unless @params.get('yPanLocked')
214
+ @params.set yOrigin: @start.centerY + (@start.yOrigin - @start.centerY) * yScale + deltaY
215
+
216
+ pinchend: (e) =>
217
+ # Do not call pan events on transformend
218
+ @hammer.stop()
219
+ # Reset temporary transform variables
220
+ @start = {}
221
+
222
+ panstart: =>
223
+ clearTimeout(@panendTimeout)
224
+ @start.xOrigin = @params.get('xOrigin')
225
+ @start.yOrigin = @params.get('yOrigin')
226
+
227
+ pan: (e) =>
228
+ @start.xOrigin ||= @params.get('xOrigin')
229
+ @start.yOrigin ||= @params.get('yOrigin')
230
+ unless @params.get('xPanLocked')
231
+ @params.set xOrigin: @start.xOrigin + e.gesture.deltaX
232
+ unless @params.get('yPanLocked')
233
+ @params.set yOrigin: @start.yOrigin + e.gesture.deltaY
234
+
235
+ panend: (e) =>
236
+ # Reset temporary transform variables
237
+ @start = {}
238
+ velocityX = e.gesture.velocityX * 10
239
+ velocityY = e.gesture.velocityY * 10
240
+
241
+ slowdown = =>
242
+ if Math.abs(velocityX) > 0 and not @params.get('xPanLocked')
243
+ @params.set xOrigin: @params.get('xOrigin') + velocityX
244
+ velocityX *= 0.9
245
+ if Math.abs(velocityY) > 0 and not @params.get('yPanLocked')
246
+ @params.set yOrigin: @params.get('yOrigin') + velocityY
247
+ velocityY *= 0.9
248
+ if Math.abs(velocityY) > 0.2 or Math.abs(velocityX) > 0.2
249
+ @panendTimeout = setTimeout(slowdown, 8)
250
+
251
+ slowdown()
252
+
253
+ # TODO: Create clever loops to fit with very small grids like
254
+ # (0.00001) and very large grids like (10^10 or alike).
255
+ roundStepSize: (stepSize) ->
256
+ validStepSize = stepSize? and isFinite(stepSize)
257
+ if validStepSize and stepSize > 0.5
258
+ factor = 1
259
+ loop
260
+ for breakpoint in [1, 2, 5]
261
+ roundedStepSize = breakpoint*factor
262
+ return roundedStepSize if roundedStepSize > stepSize
263
+ factor *= 10
264
+ else if validStepSize and 0 < stepSize <= 0.5
265
+ denominator = 10
266
+ lastRoundedStepSize = null
267
+ loop
268
+ for breakpoint in [5, 2, 1]
269
+ roundedStepSize = breakpoint/denominator
270
+ if stepSize > roundedStepSize
271
+ return lastRoundedStepSize or roundedStepSize
272
+ else
273
+ lastRoundedStepSize = roundedStepSize
274
+ denominator *= 10
275
+ else
276
+ stepSize
277
+
278
+ axisLabel: (value, stepSize) ->
279
+ precision = 0
280
+ precision += 1 while stepSize and stepSize*Math.pow(10, precision) < 1
281
+ value.toFixed(precision)
282
+
283
+ setCanvasResolution: (params) ->
284
+ super
285
+
286
+ # Recalculate xOrigin/yOrigin if we're in a width/height change
287
+ # callback. Otherwise, we're initializing and we should skip that.
288
+ if params?
289
+ previous = @params.previousAttributes()
290
+ previousXOrigin = if previous.xOrigin? then previous.xOrigin else @params.get('xOrigin')
291
+ previousYOrigin = if previous.yOrigin? then previous.yOrigin else @params.get('yOrigin')
292
+ @params.set
293
+ xOrigin: previousXOrigin * @params.get('width') / previous.width
294
+ yOrigin: previousYOrigin * @params.get('height') / previous.height
295
+
296
+ # We don't need that during initialisation as well because it's
297
+ # done by resetCanvas
298
+ switch @params.get('scaleLink')
299
+ when 'x'
300
+ @params.set xScale: @linkedXScale()
301
+ when 'y'
302
+ @params.set yScale: @linkedYScale()
303
+
304
+ xAxisValueLabel: (val, stepsize) ->
305
+ @axisLabel(val, stepsize)
306
+
307
+ yAxisValueLabel: (val, stepsize) ->
308
+ @axisLabel(val - @params.get('yOffset'), stepsize)
309
+
310
+ _axisLabel: (label) ->
311
+ if typeof label is 'function'
312
+ label.call(this)
313
+ else if label?
314
+ label
315
+ else
316
+ ''
317
+
318
+ xAxisLabel: -> @_axisLabel(@params.get('xAxisLabel'))
319
+ yAxisLabel: -> @_axisLabel(@params.get('yAxisLabel'))
320
+
321
+ renderCurves: ->
322
+ # stub
323
+
324
+ renderXAxis: ->
325
+ @context.setLineDash []
326
+ @context.font = @defaultFont
327
+ @context.strokeStyle = "#999999"
328
+ @context.fillStyle = "#000000"
329
+ @context.lineWidth = 2
330
+
331
+ @context.beginPath()
332
+ @context.moveTo(0, @yOrigin)
333
+ @context.lineTo(@width, @yOrigin)
334
+
335
+ unless @params.get('xLabelPosition') is 'none'
336
+ labelY = dashY = 0
337
+ if @params.get('xLabelPosition') is 'bottom'
338
+ labelY = @yOrigin + 15
339
+ dashY = @yOrigin + 5
340
+ else
341
+ labelY = @yOrigin - 15
342
+ dashY = @yOrigin - 5
343
+
344
+ @context.textBaseline = 'middle'
345
+ @context.textAlign = 'center'
346
+
347
+ xRange = @maxRangeX() unless xRange?
348
+ xMin = -@xOrigin * xRange / @width
349
+ xMax = (@width - @xOrigin) * xRange / @width
350
+ xStepSize = @roundStepSize(100 * xRange / @width)
351
+ for x in [(xMin - xMin % xStepSize) .. xMax] by xStepSize
352
+ if x <= (0 - xStepSize / 2) or (0 + xStepSize / 2) <= x
353
+ xPos = @xOrigin + x * @width / xRange
354
+ @context.moveTo(xPos, @yOrigin)
355
+ @context.lineTo(xPos, dashY)
356
+ @context.fillText("#{@xAxisValueLabel(x, xStepSize)}", xPos, labelY)
357
+
358
+ @context.save()
359
+ xPos = if @xOrigin <= @width/2
360
+ (@xOrigin + @width)/2
361
+ else
362
+ @xOrigin/2
363
+ xPos = Math.round(xPos) if @context.pixelRatio is 1
364
+ @context.translate(xPos, @yOrigin + 15)
365
+ MarkupText.render(@context, @xAxisLabel(), @defaultFont)
366
+ @context.restore()
367
+
368
+ @context.stroke()
369
+ @context.closePath()
370
+
371
+ renderYAxis: (yRange) ->
372
+ @context.setLineDash []
373
+ @context.font = @defaultFont
374
+ @context.strokeStyle = "#999999"
375
+ @context.fillStyle = "#000000"
376
+ @context.lineWidth = 2
377
+
378
+ @context.beginPath()
379
+ @context.moveTo(@xOrigin, 0)
380
+ @context.lineTo(@xOrigin, @height)
381
+
382
+ unless @params.get('yLabelPosition') is 'none'
383
+ labelX = dashX = 0
384
+ if @params.get('yLabelPosition') is 'right'
385
+ labelX = @xOrigin + 10
386
+ dashX = @xOrigin + 5
387
+ @context.textAlign = 'left'
388
+ else
389
+ labelX = @xOrigin - 10
390
+ dashX = @xOrigin - 5
391
+ @context.textAlign = 'right'
392
+ @context.textBaseline = 'middle'
393
+
394
+ yRange = @maxRangeY() unless yRange?
395
+ yMin = -(@height - @yOrigin) * yRange / @height
396
+ yMax = @yOrigin * yRange / @height
397
+ yStepSize = @roundStepSize(100 * yRange / @height)
398
+ for y in [(yMin - yMin % yStepSize) .. yMax] by yStepSize
399
+ if y <= (0 - yStepSize / 2) or y >= (0 + yStepSize / 2)
400
+ yPos = @yOrigin - y * @height / yRange
401
+ @context.moveTo(@xOrigin, yPos)
402
+ @context.lineTo(dashX, yPos)
403
+ @context.fillText(@yAxisValueLabel(y, yStepSize), labelX, yPos)
404
+
405
+ @context.save();
406
+ yPos = if @yOrigin < @height/2
407
+ (@yOrigin + @height)/2
408
+ else
409
+ @yOrigin/2
410
+ yPos = Math.round(yPos) if @context.pixelRatio is 1
411
+ @context.translate(@xOrigin - 15, yPos);
412
+ @context.rotate(-Math.PI / 2);
413
+ MarkupText.render(@context, @yAxisLabel(), @defaultFont)
414
+ @context.restore()
415
+
416
+ @context.stroke()
417
+ @context.closePath()
418
+
419
+ renderGrid: ->
420
+ @context.strokeStyle = '#eeeeee'
421
+ @context.lineWidth = 1
422
+ @context.beginPath()
423
+
424
+ unless @params.get('xLabelPosition') is 'none'
425
+ xRange = @maxRangeX() unless xRange?
426
+ xMin = -@xOrigin * xRange / @width
427
+ xMax = (@width - @xOrigin) * xRange / @width
428
+ xStepSize = @roundStepSize(100 * xRange / @width)
429
+ for x in [(xMin - xMin % xStepSize) .. xMax] by xStepSize
430
+ xPos = @xOrigin + x * @width / xRange
431
+ @context.moveTo(xPos, 0)
432
+ @context.lineTo(xPos, @height)
433
+
434
+ unless @params.get('yLabelPosition') is 'none'
435
+ yRange = @maxRangeY() unless yRange?
436
+ yMin = -(@height - @yOrigin) * yRange / @height
437
+ yMax = @yOrigin * yRange / @height
438
+ yStepSize = @roundStepSize(100 * yRange / @height)
439
+ for y in [(yMin - yMin % yStepSize) .. yMax] by yStepSize
440
+ yPos = @yOrigin - y * @height / yRange
441
+ @context.moveTo(0, yPos)
442
+ @context.lineTo(@width, yPos)
443
+
444
+ @context.stroke()
445
+ @context.closePath()
446
+
447
+ beforeRender: ->
448
+ # Stub to execute code before rendering...
449
+
450
+ render: =>
451
+ @width = @params.get('width')
452
+ @height = @params.get('height')
453
+ @xOrigin = @params.get('xOrigin')
454
+ @yOrigin = @params.get('yOrigin')
455
+ @yOffset = @params.get('yOffset')
456
+ @xRange = @params.get('xRange')
457
+ @yRange = @params.get('yRange')
458
+
459
+ @xMin = -@xOrigin * @xRange / @width
460
+ @xMax = (@width - @xOrigin) * @xRange / @width
461
+
462
+ @yMin = -(@height - @yOrigin) * @yRange / @height
463
+ @yMax = @yOrigin * @yRange / @height
464
+
465
+ return this if @width == null and @height == null
466
+
467
+ @context ||= @el.getContext('2d')
468
+ @context.clearRect(0, 0, @width, @height)
469
+
470
+ @beforeRender()
471
+
472
+ @renderGrid()
473
+ @renderXAxis()
474
+ @renderYAxis()
475
+ @renderCurves()
476
+
477
+ this