ela 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.gitlab-ci.yml +23 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +139 -0
- data/Guardfile +25 -0
- data/LICENSE.txt +205 -0
- data/README.de.md +195 -0
- data/README.md +66 -0
- data/Rakefile +96 -0
- data/app/css/screen.styl +425 -0
- data/app/css/vendor/stackedit.styl +140 -0
- data/app/fonts/Roboto-Italic-webfont.eot +0 -0
- data/app/fonts/Roboto-Italic-webfont.svg +642 -0
- data/app/fonts/Roboto-Italic-webfont.ttf +0 -0
- data/app/fonts/Roboto-Italic-webfont.woff +0 -0
- data/app/fonts/Roboto-Light-webfont.eot +0 -0
- data/app/fonts/Roboto-Light-webfont.svg +641 -0
- data/app/fonts/Roboto-Light-webfont.ttf +0 -0
- data/app/fonts/Roboto-Light-webfont.woff +0 -0
- data/app/fonts/Roboto-LightItalic-webfont.eot +0 -0
- data/app/fonts/Roboto-LightItalic-webfont.svg +641 -0
- data/app/fonts/Roboto-LightItalic-webfont.ttf +0 -0
- data/app/fonts/Roboto-LightItalic-webfont.woff +0 -0
- data/app/fonts/Roboto-Medium-webfont.eot +0 -0
- data/app/fonts/Roboto-Medium-webfont.svg +593 -0
- data/app/fonts/Roboto-Medium-webfont.ttf +0 -0
- data/app/fonts/Roboto-Medium-webfont.woff +0 -0
- data/app/fonts/Roboto-MediumItalic-webfont.eot +0 -0
- data/app/fonts/Roboto-MediumItalic-webfont.svg +642 -0
- data/app/fonts/Roboto-MediumItalic-webfont.ttf +0 -0
- data/app/fonts/Roboto-MediumItalic-webfont.woff +0 -0
- data/app/fonts/Roboto-Regular-webfont.eot +0 -0
- data/app/fonts/Roboto-Regular-webfont.svg +621 -0
- data/app/fonts/Roboto-Regular-webfont.ttf +0 -0
- data/app/fonts/Roboto-Regular-webfont.woff +0 -0
- data/app/fonts/Roboto-Thin-webfont.eot +0 -0
- data/app/fonts/Roboto-Thin-webfont.svg +631 -0
- data/app/fonts/Roboto-Thin-webfont.ttf +0 -0
- data/app/fonts/Roboto-Thin-webfont.woff +0 -0
- data/app/fonts/Roboto-ThinItalic-webfont.eot +0 -0
- data/app/fonts/Roboto-ThinItalic-webfont.svg +631 -0
- data/app/fonts/Roboto-ThinItalic-webfont.ttf +0 -0
- data/app/fonts/Roboto-ThinItalic-webfont.woff +0 -0
- data/app/fonts/droid_sans_regular.typeface.svg +1 -0
- data/app/fonts/fontawesome-webfont.eot +0 -0
- data/app/fonts/fontawesome-webfont.svg +2671 -0
- data/app/fonts/fontawesome-webfont.ttf +0 -0
- data/app/fonts/fontawesome-webfont.woff +0 -0
- data/app/fonts/fontawesome-webfont.woff2 +0 -0
- data/app/js/lib/application.coffee +83 -0
- data/app/js/lib/bootstrap_data.coffee +70 -0
- data/app/js/lib/collections/00_limited_collection.coffee +85 -0
- data/app/js/lib/collections/curves.coffee +3 -0
- data/app/js/lib/collections/named_object_collection.coffee +7 -0
- data/app/js/lib/mathjaxConfig.coffee +241 -0
- data/app/js/lib/models/app.coffee +58 -0
- data/app/js/lib/models/base_app.coffee +62 -0
- data/app/js/lib/models/base_app_model.coffee +61 -0
- data/app/js/lib/models/base_calculator.coffee +212 -0
- data/app/js/lib/models/base_subapp_container.coffee +35 -0
- data/app/js/lib/models/curve.coffee +179 -0
- data/app/js/lib/router.coffee +26 -0
- data/app/js/lib/views/app.coffee +56 -0
- data/app/js/lib/views/base_app.coffee +274 -0
- data/app/js/lib/views/base_aside.coffee +9 -0
- data/app/js/lib/views/base_graph.coffee +477 -0
- data/app/js/lib/views/base_subapp_container.coffee +44 -0
- data/app/js/lib/views/canvas.coffee +73 -0
- data/app/js/lib/views/curve_graph.coffee +163 -0
- data/app/js/lib/views/curves_aside.coffee +21 -0
- data/app/js/lib/views/curves_list_item.coffee +8 -0
- data/app/js/lib/views/grouped_parameters_aside.coffee +14 -0
- data/app/js/lib/views/headup.coffee +15 -0
- data/app/js/lib/views/help.coffee +86 -0
- data/app/js/lib/views/interpolated_graph.coffee +281 -0
- data/app/js/lib/views/legend.coffee +138 -0
- data/app/js/lib/views/legend_handler.coffee +51 -0
- data/app/js/lib/views/overview.coffee +85 -0
- data/app/js/lib/views/overview_tile.coffee +18 -0
- data/app/js/lib/views/parameters_aside.coffee +12 -0
- data/app/js/lib/views/three_graph.coffee +92 -0
- data/app/js/vendor/Markdown.Converter.js +1519 -0
- data/app/js/vendor/Markdown.Extra.js +874 -0
- data/app/js/vendor/Markdown.Toc.coffee +79 -0
- data/app/js/vendor/backbone-1.3.3.min.js +2 -0
- data/app/js/vendor/backbone-validation-0.11.5.js +8 -0
- data/app/js/vendor/backbone.poised/form.coffee +156 -0
- data/app/js/vendor/backbone.poised/form/anchor.coffee +26 -0
- data/app/js/vendor/backbone.poised/form/base_control.coffee +42 -0
- data/app/js/vendor/backbone.poised/form/linked_control.coffee +79 -0
- data/app/js/vendor/backbone.poised/form/linked_number_control.coffee +27 -0
- data/app/js/vendor/backbone.poised/form/linked_range_control.coffee +53 -0
- data/app/js/vendor/backbone.poised/form/linked_select_control.coffee +18 -0
- data/app/js/vendor/backbone.poised/form/linked_string_control.coffee +27 -0
- data/app/js/vendor/backbone.poised/form/number_control.coffee +25 -0
- data/app/js/vendor/backbone.poised/form/range_control.coffee +48 -0
- data/app/js/vendor/backbone.poised/form/select_control.coffee +16 -0
- data/app/js/vendor/backbone.poised/form/selectbox.coffee +78 -0
- data/app/js/vendor/backbone.poised/form/slider.coffee +109 -0
- data/app/js/vendor/backbone.poised/form/string_control.coffee +23 -0
- data/app/js/vendor/backbone.poised/form/submit_control.coffee +39 -0
- data/app/js/vendor/backbone.poised/form/textarea.coffee +36 -0
- data/app/js/vendor/backbone.poised/form/textfield.coffee +86 -0
- data/app/js/vendor/backbone.poised/form/value.coffee +33 -0
- data/app/js/vendor/backbone.poised/form/value_control.coffee +15 -0
- data/app/js/vendor/backbone.poised/linked_form.coffee +43 -0
- data/app/js/vendor/backbone.poised/list.coffee +97 -0
- data/app/js/vendor/backbone.poised/list/add_button.coffee +16 -0
- data/app/js/vendor/backbone.poised/list/anchor.coffee +32 -0
- data/app/js/vendor/backbone.poised/list/item.coffee +68 -0
- data/app/js/vendor/backbone.poised/list/searchfield.coffee +26 -0
- data/app/js/vendor/backbone.poised/list/selectable_item.coffee +65 -0
- data/app/js/vendor/backbone.poised/patches.coffee +6 -0
- data/app/js/vendor/backbone.poised/string_mixin.coffee +23 -0
- data/app/js/vendor/backbone.poised/underscore_ext.coffee +2 -0
- data/app/js/vendor/backbone.poised/view.coffee +59 -0
- data/app/js/vendor/gaussianElimination.coffee +40 -0
- data/app/js/vendor/hammer-2.0.8.min.js +7 -0
- data/app/js/vendor/jquery-3.1.1.min.js +4 -0
- data/app/js/vendor/jquery.after-transition.coffee +20 -0
- data/app/js/vendor/jquery.backbone-hammer.coffee +28 -0
- data/app/js/vendor/jquery.keyboard-modifiers.coffee +22 -0
- data/app/js/vendor/jquery.mark-5.2.3.min.js +7 -0
- data/app/js/vendor/jquery.scrollTo-2.1.2.min.js +7 -0
- data/app/js/vendor/js-yaml-3.4.3.min.js +3 -0
- data/app/js/vendor/markup_text.coffee +95 -0
- data/app/js/vendor/mathjax/MathJax.js +19 -0
- data/app/js/vendor/mathjax/extensions/MathEvents.js +19 -0
- data/app/js/vendor/mathjax/extensions/tex2jax.js +19 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Math-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/eot/MathJax_WinIE6-Regular.eot +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Math-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinChrome-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/otf/MathJax_WinIE6-Regular.otf +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_AMS-Regular.svg +765 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Bold.svg +136 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Caligraphic-Regular.svg +134 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Bold.svg +319 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Fraktur-Regular.svg +309 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Bold.svg +656 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Italic.svg +374 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Main-Regular.svg +659 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-BoldItalic.svg +331 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Italic.svg +331 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Math-Regular.svg +330 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Bold.svg +280 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Italic.svg +245 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_SansSerif-Regular.svg +211 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Script-Regular.svg +160 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size1-Regular.svg +110 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size2-Regular.svg +109 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size3-Regular.svg +49 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Size4-Regular.svg +102 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_Typewriter-Regular.svg +322 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/svg/MathJax_WinChrome-Regular.svg +39 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Math-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff +0 -0
- data/app/js/vendor/mathjax/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff +0 -0
- data/app/js/vendor/mathjax/jax/element/mml/jax.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/Arrows.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/BasicLatin.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiacritMarks.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/CombDiactForSymbols.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/Dingbats.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/GeneralPunctuation.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/GeometricShapes.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/GreekAndCoptic.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/Latin1Supplement.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/LetterlikeSymbols.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/MathOperators.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsA.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/MiscMathSymbolsB.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/MiscSymbolsAndArrows.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/MiscTechnical.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/SpacingModLetters.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/SuppMathOperators.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsA.js +19 -0
- data/app/js/vendor/mathjax/jax/element/mml/optable/SupplementalArrowsB.js +19 -0
- data/app/js/vendor/mathjax/jax/input/TeX/config.js +19 -0
- data/app/js/vendor/mathjax/jax/input/TeX/jax.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/annotation-xml.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/maction.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/menclose.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mglyph.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mmultiscripts.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/ms.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/mtable.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/autoload/multiline.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/config.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/AMS-Regular.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Caligraphic-Bold.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Bold.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Fraktur-Regular.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Main-Bold.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Math-BoldItalic.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Bold.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Italic.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/SansSerif-Regular.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Script-Regular.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/Typewriter-Regular.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata-extra.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/fonts/TeX/fontdata.js +19 -0
- data/app/js/vendor/mathjax/jax/output/CommonHTML/jax.js +19 -0
- data/app/js/vendor/modernizr-custom-3.3.1.min.js +3 -0
- data/app/js/vendor/persistjs-git.js +1136 -0
- data/app/js/vendor/poised/poised.general.coffee +21 -0
- data/app/js/vendor/poised/poised.tabs.coffee +31 -0
- data/app/js/vendor/poised/utils.coffee +11 -0
- data/app/js/vendor/request_animation_frame.coffee +19 -0
- data/app/js/vendor/three-82.min.js +15 -0
- data/app/js/vendor/three-CanvasRenderer-82.js +1118 -0
- data/app/js/vendor/three-Projector-82.js +929 -0
- data/app/js/vendor/underscore-1.8.3.min.js +6 -0
- data/app/js/vendor/webfontloader-1.6.26.min.js +33 -0
- data/app/views/aliasing/legend.jst.hamlc +6 -0
- data/app/views/composites/composites_list_item_label.jst.hamlc +3 -0
- data/app/views/composites/import_composites_aside.jst.hamlc +6 -0
- data/app/views/composites/mix_preset_list_item_label.jst.hamlc +8 -0
- data/app/views/composites/share_aside.jst.hamlc +7 -0
- data/app/views/doc/airplanes_list_item_label.jst.hamlc +3 -0
- data/app/views/doc/import_airplanes_aside.jst.hamlc +6 -0
- data/app/views/doc/share_aside.jst.hamlc +7 -0
- data/app/views/general/app.jst.hamlc +42 -0
- data/app/views/general/curves_list_item_label.jst.hamlc +5 -0
- data/app/views/general/help.jst.hamlc +7 -0
- data/app/views/general/tabs.jst.hamlc +6 -0
- data/app/views/index.haml +24 -0
- data/app/views/overview/app.jst.hamlc +7 -0
- data/app/views/overview/tile.jst.hamlc +4 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ela.gemspec +50 -0
- data/exe/ela +59 -0
- data/lib/ela.rb +8 -0
- data/lib/ela/jasmine.rb +87 -0
- data/lib/ela/server.rb +136 -0
- data/lib/ela/utils.rb +131 -0
- data/lib/ela/version.rb +3 -0
- data/package-lock.json +899 -0
- data/package.json +11 -0
- data/support/project/Guardfile +64 -0
- data/support/project/jasmine.yml +3 -0
- data/support/server.ru +5 -0
- metadata +4365 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.BaseSubappContainer extends Backbone.Poised.View
|
3
|
+
id: -> @model.name.toDash()
|
4
|
+
tagName: 'section'
|
5
|
+
className: 'subapp-container'
|
6
|
+
subappViews: []
|
7
|
+
|
8
|
+
events:
|
9
|
+
'tap header h2': 'switchSubapp'
|
10
|
+
|
11
|
+
initialize: ->
|
12
|
+
super
|
13
|
+
@listenTo @model, 'change:path', @toggleActivation
|
14
|
+
|
15
|
+
remove: =>
|
16
|
+
@$el.afterTransitionForRemovingClass 'active', => super
|
17
|
+
|
18
|
+
setActive: (active) =>
|
19
|
+
@$el.toggleClass('active', active)
|
20
|
+
|
21
|
+
activate: =>
|
22
|
+
@$el.toggleClass('active', true)
|
23
|
+
|
24
|
+
deactivate: =>
|
25
|
+
@$el.toggleClass('active', false)
|
26
|
+
|
27
|
+
toggleActivation: =>
|
28
|
+
subapp = @model.get('path')[0]
|
29
|
+
for name, app of @model.subapps
|
30
|
+
@subviews[name].setActive(name is subapp)
|
31
|
+
|
32
|
+
render: =>
|
33
|
+
@$el.empty()
|
34
|
+
|
35
|
+
for name, app of @model.subapps
|
36
|
+
SubappView = app.view.toFunction()
|
37
|
+
@subviews[name] = view = new SubappView
|
38
|
+
model: @model.subappInstances[name]
|
39
|
+
localePrefix: "#{@localePrefix}.#{name}"
|
40
|
+
@$el.append(view.render().el)
|
41
|
+
|
42
|
+
@toggleActivation()
|
43
|
+
|
44
|
+
this
|
@@ -0,0 +1,73 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.Canvas extends Backbone.Poised.View
|
3
|
+
tagName: 'canvas'
|
4
|
+
|
5
|
+
class @Params extends Backbone.Model
|
6
|
+
serialize: -> {}
|
7
|
+
deserialize: ->
|
8
|
+
|
9
|
+
# True if an animation frame request is currently pending
|
10
|
+
animationFrameRequested: false
|
11
|
+
|
12
|
+
constructor: ->
|
13
|
+
super
|
14
|
+
fontWeight = if window.devicePixelRatio > 1 then 300 else 400
|
15
|
+
@defaultFont = "#{fontWeight} 12px Roboto"
|
16
|
+
|
17
|
+
initialize: (options = {}) ->
|
18
|
+
# Make sure we got the parameters model for holding view specific information
|
19
|
+
@defaults = _.defaults(options.defaults, @defaults) if options.defaults?
|
20
|
+
if options.params?
|
21
|
+
@params = options.params
|
22
|
+
@params.set(@defaults)
|
23
|
+
else
|
24
|
+
@params = new @constructor.Params(@defaults)
|
25
|
+
|
26
|
+
@setCanvasResolution()
|
27
|
+
|
28
|
+
$(window).resize(@readCanvasResolution)
|
29
|
+
@listenTo(@params, 'change:width change:height', @setCanvasResolution)
|
30
|
+
|
31
|
+
remove: ->
|
32
|
+
super
|
33
|
+
$(window).off('resize', @readCanvasResolution)
|
34
|
+
|
35
|
+
readCanvasResolution: =>
|
36
|
+
$parent = @$el.parent()
|
37
|
+
# Do not take scale into account here, otherwise
|
38
|
+
# non-active subapps will get initialized with wrong size
|
39
|
+
# because they have a css scale of 0.75
|
40
|
+
@params.set
|
41
|
+
width: $parent[0].clientWidth
|
42
|
+
height: $parent[0].clientHeight
|
43
|
+
|
44
|
+
setCanvasResolution: ->
|
45
|
+
width = @params.get('width')
|
46
|
+
height = @params.get('height')
|
47
|
+
|
48
|
+
context = @el.getContext('2d')
|
49
|
+
|
50
|
+
# Ratio between software dpi and device ppi.
|
51
|
+
devicePixelRatio = window.devicePixelRatio || 1
|
52
|
+
|
53
|
+
# On desktop computers the browser scales automatically.
|
54
|
+
# This is deactivated on mobile devices due to memory.
|
55
|
+
backingStoreRatio = context.webkitBackingStorePixelRatio ||
|
56
|
+
context.mozBackingStorePixelRatio ||
|
57
|
+
context.msBackingStorePixelRatio ||
|
58
|
+
context.oBackingStorePixelRatio ||
|
59
|
+
context.backingStorePixelRatio || 1
|
60
|
+
|
61
|
+
context.pixelRatio = @pixelRatio = devicePixelRatio/backingStoreRatio
|
62
|
+
|
63
|
+
@$el.css width: width, height: height
|
64
|
+
@$el.attr width: width * @pixelRatio, height: height * @pixelRatio
|
65
|
+
|
66
|
+
context.scale(@pixelRatio, @pixelRatio)
|
67
|
+
|
68
|
+
requestRepaint: =>
|
69
|
+
unless @animationFrameRequested
|
70
|
+
@animationFrameRequested = true
|
71
|
+
requestAnimationFrame =>
|
72
|
+
@animationFrameRequested = false
|
73
|
+
@render()
|
@@ -0,0 +1,163 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.CurveGraph extends ELA.Views.BaseGraph
|
3
|
+
initialize: (options = {}) ->
|
4
|
+
super
|
5
|
+
|
6
|
+
@bindCalculatorEvents()
|
7
|
+
|
8
|
+
@model.curves.on 'change:selected', =>
|
9
|
+
@bindCalculatorEvents()
|
10
|
+
@requestRepaint()
|
11
|
+
|
12
|
+
@model.on 'change:calculators', =>
|
13
|
+
@calculateRanges()
|
14
|
+
@bindCalculatorEvents()
|
15
|
+
@requestRepaint()
|
16
|
+
|
17
|
+
@model.on 'change:valueAtRange', @requestRepaint
|
18
|
+
@model.on 'change:axisLabelingForCurve', @requestRepaint
|
19
|
+
|
20
|
+
bindCalculatorEvents: ->
|
21
|
+
# Remove current callbacks, add new ones for each curve
|
22
|
+
@stopListening(@model.previous('calculators'))
|
23
|
+
|
24
|
+
for calc in @model.get('calculators')
|
25
|
+
for curve in @model.curves.history
|
26
|
+
@listenTo calc, "change:#{curve.get('function')}", @requestRepaint
|
27
|
+
|
28
|
+
@listenTo calc, 'change:maxX change:maxY', @calculateRanges
|
29
|
+
# TODO: Add dynamic dependencies to calculator, so that we can
|
30
|
+
# actually only listen to maxY changes and recalculate ranges.
|
31
|
+
oldestCurve = @model.curves.history[0]
|
32
|
+
if oldestCurve?
|
33
|
+
@listenTo calc, "change:#{oldestCurve.get('function')}", @calculateRanges
|
34
|
+
|
35
|
+
calculateRanges: =>
|
36
|
+
@params.set xRange: @maxRangeX()
|
37
|
+
|
38
|
+
maxRangeX: =>
|
39
|
+
max = _.chain(@model.get('calculators'))
|
40
|
+
.map (c) -> c.maxX()
|
41
|
+
.max()
|
42
|
+
.value()
|
43
|
+
min = _.chain(@model.get('calculators'))
|
44
|
+
.map (c) -> c.minX()
|
45
|
+
.min()
|
46
|
+
.value()
|
47
|
+
range = 0
|
48
|
+
range += max if max > 0
|
49
|
+
range -= min if min < 0
|
50
|
+
(Math.abs(range) or 10000) * @params.get('xScale') * 1.1
|
51
|
+
|
52
|
+
maxRangeY: (func) =>
|
53
|
+
unless func?
|
54
|
+
func = @model.get('axisLabelingForCurve')?.get('function')
|
55
|
+
max = _.chain(@model.get('calculators'))
|
56
|
+
.map (c) -> c.maxY(func, c.minX(), c.maxX(), 30)
|
57
|
+
.max()
|
58
|
+
.value()
|
59
|
+
min = _.chain(@model.get('calculators'))
|
60
|
+
.map (c) -> c.minY(func, c.minX(), c.maxX(), 30)
|
61
|
+
.min()
|
62
|
+
.value()
|
63
|
+
range = 0
|
64
|
+
range += max if max > 0
|
65
|
+
range -= min if min < 0
|
66
|
+
Math.abs(range) * @params.get('yScale') * 1.1
|
67
|
+
|
68
|
+
xAxisValueLabel: (val, stepsize) ->
|
69
|
+
@axisLabel(val, stepsize)
|
70
|
+
|
71
|
+
yAxisValueLabel: (val, stepsize) ->
|
72
|
+
curve = @model.get('axisLabelingForCurve')
|
73
|
+
val = @Present(curve).unitValue(val) if curve?
|
74
|
+
@axisLabel(val, stepsize)
|
75
|
+
|
76
|
+
yAxisLabel: ->
|
77
|
+
curve = @model.get('axisLabelingForCurve')
|
78
|
+
@Present(curve).fullYAxisLabel()
|
79
|
+
|
80
|
+
renderCurves: ->
|
81
|
+
for calc, i in @model.get('calculators')
|
82
|
+
for curve, j in @model.curves.history
|
83
|
+
func = curve.get('function')
|
84
|
+
|
85
|
+
@context.strokeStyle = curve.strokeStyle()
|
86
|
+
@context.lineWidth = 3
|
87
|
+
if i == 1
|
88
|
+
@context.setLineDash [4,5]
|
89
|
+
else
|
90
|
+
@context.setLineDash []
|
91
|
+
xPos = 0
|
92
|
+
brokenLine = 1
|
93
|
+
plotted = 0
|
94
|
+
@context.beginPath()
|
95
|
+
xPos = 0
|
96
|
+
yRange = @maxRangeY(func)
|
97
|
+
yMin = -(@height - @yOrigin) * yRange / @height
|
98
|
+
yMax = @yOrigin * yRange / @height
|
99
|
+
for xPos in [-2 .. (@width + 3)]
|
100
|
+
x = @xMin + xPos * @xRange / @width
|
101
|
+
val = calc[func](x)
|
102
|
+
y = val
|
103
|
+
if y?
|
104
|
+
yPos = (yMax - y) * @height / yRange
|
105
|
+
if brokenLine > 0
|
106
|
+
@context.moveTo(xPos, yPos) if brokenLine == 1
|
107
|
+
brokenLine -= 1
|
108
|
+
else
|
109
|
+
@context.lineTo(xPos, yPos)
|
110
|
+
plotted += 1
|
111
|
+
|
112
|
+
@context.stroke()
|
113
|
+
@context.closePath()
|
114
|
+
|
115
|
+
renderRangeIndicator: ->
|
116
|
+
@context.setLineDash []
|
117
|
+
@context.beginPath()
|
118
|
+
@context.strokeStyle = '#999999'
|
119
|
+
@context.lineWidth = 2
|
120
|
+
@context.moveTo(0, 0)
|
121
|
+
@context.lineTo(@width, 0)
|
122
|
+
@context.stroke()
|
123
|
+
|
124
|
+
@context.beginPath()
|
125
|
+
@context.strokeStyle = '#999999'
|
126
|
+
@context.lineWidth = 2
|
127
|
+
@context.moveTo(0, @height)
|
128
|
+
@context.lineTo(@width, @height)
|
129
|
+
@context.stroke()
|
130
|
+
|
131
|
+
if @model.get('valueAtRange')?
|
132
|
+
valueAtPoint = @model.get('valueAtRange')
|
133
|
+
|
134
|
+
@context.beginPath()
|
135
|
+
@context.strokeStyle = '#999999'
|
136
|
+
@context.lineWidth = 2
|
137
|
+
xPos = @xOrigin + valueAtPoint * @width / @xRange
|
138
|
+
@context.moveTo(xPos, 0)
|
139
|
+
@context.lineTo(xPos, @height)
|
140
|
+
@context.stroke()
|
141
|
+
@context.closePath()
|
142
|
+
|
143
|
+
@context.beginPath()
|
144
|
+
@context.lineWidth = 1
|
145
|
+
|
146
|
+
# The fillStyle of the triangle should match the color of the
|
147
|
+
# legend background set in screen.styl:
|
148
|
+
@context.fillStyle = "#f2f2f2"
|
149
|
+
|
150
|
+
@context.moveTo(xPos + 8, 0)
|
151
|
+
@context.lineTo(xPos, 8)
|
152
|
+
@context.lineTo(xPos - 8, 0)
|
153
|
+
@context.moveTo(xPos - 8, @height)
|
154
|
+
@context.lineTo(xPos, @height - 8)
|
155
|
+
@context.lineTo(xPos + 8, @height)
|
156
|
+
@context.stroke()
|
157
|
+
@context.fill()
|
158
|
+
@context.closePath()
|
159
|
+
|
160
|
+
render: =>
|
161
|
+
super
|
162
|
+
@renderRangeIndicator()
|
163
|
+
this
|
@@ -0,0 +1,21 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.CurvesAside extends ELA.Views.BaseAside
|
3
|
+
initialize: ->
|
4
|
+
unless @model.curves?
|
5
|
+
throw new Error('Missing curves collection in model for CurvesAside')
|
6
|
+
|
7
|
+
render: =>
|
8
|
+
@$el.toggleClass('scroll-y', true)
|
9
|
+
@subviews.curvesList = new Backbone.Poised.List
|
10
|
+
collection: @model.curves
|
11
|
+
filterAttributes: ['label']
|
12
|
+
itemLabel: JST['general/curves_list_item_label']
|
13
|
+
itemClass: ELA.Views.CurvesListItem
|
14
|
+
singleSelect: true
|
15
|
+
localePrefix: @model.localePrefix()
|
16
|
+
group:
|
17
|
+
by: 'group'
|
18
|
+
|
19
|
+
@$el.html(@subviews.curvesList.render().el)
|
20
|
+
@$el.append($('<div>', class: 'hint').text(t('curvesAside.hint')))
|
21
|
+
this
|
@@ -0,0 +1,14 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.GroupedParametersAside extends ELA.Views.BaseAside
|
3
|
+
render: =>
|
4
|
+
@$el.addClass('scroll-y')
|
5
|
+
subview = @subviews.form = new Backbone.Poised.Form
|
6
|
+
model: @model
|
7
|
+
liveForm: true
|
8
|
+
parentView: this
|
9
|
+
group:
|
10
|
+
by: 'group'
|
11
|
+
localePrefix: @model.localePrefix()
|
12
|
+
@$el.html(subview.render().el)
|
13
|
+
|
14
|
+
this
|
@@ -0,0 +1,15 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.Headup extends Backbone.Poised.View
|
3
|
+
activate: (control) =>
|
4
|
+
# Clone the control view to add a new DOM element showing the same values
|
5
|
+
@subviews.control = control.clone()
|
6
|
+
@$el.addClass('active')
|
7
|
+
@render()
|
8
|
+
|
9
|
+
deactivate: =>
|
10
|
+
@$el.removeClass('active')
|
11
|
+
@subviews.control.remove()
|
12
|
+
|
13
|
+
render: =>
|
14
|
+
@$el.html(@subviews.control.render().el)
|
15
|
+
this
|
@@ -0,0 +1,86 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.Help extends Backbone.View
|
3
|
+
id: 'help'
|
4
|
+
tagName: 'section'
|
5
|
+
|
6
|
+
template: JST['general/help']
|
7
|
+
typeset: false
|
8
|
+
scrollTarget: null
|
9
|
+
|
10
|
+
events:
|
11
|
+
'tap header .back.icon': 'goBack'
|
12
|
+
'tap header h2': 'scrollToToc'
|
13
|
+
'click a': 'scrollToAnchor'
|
14
|
+
|
15
|
+
hammerjs: true
|
16
|
+
|
17
|
+
goBack: (e) =>
|
18
|
+
if @model.path?
|
19
|
+
ELA.router.navigate("app/#{@model.path}", trigger: true)
|
20
|
+
else
|
21
|
+
ELA.router.navigate('/', trigger: true)
|
22
|
+
|
23
|
+
scrollToAnchor: (e) =>
|
24
|
+
href = $(e.currentTarget).attr('href')
|
25
|
+
if href.match /^#(.*)$/
|
26
|
+
$target = @$article.find(href)
|
27
|
+
if $target.length > 0
|
28
|
+
e.preventDefault()
|
29
|
+
@scrollTo href
|
30
|
+
@scrollTarget = href
|
31
|
+
|
32
|
+
remove: =>
|
33
|
+
@$el.afterTransitionForRemovingClass 'active', =>
|
34
|
+
super
|
35
|
+
|
36
|
+
scrollToToc: (e) =>
|
37
|
+
@scrollTo '.toc'
|
38
|
+
e.stopPropagation()
|
39
|
+
|
40
|
+
setActive: (val) ->
|
41
|
+
@$el.toggleClass('active', val)
|
42
|
+
|
43
|
+
activate: ->
|
44
|
+
@$el.toggleClass('active', true)
|
45
|
+
|
46
|
+
deactivate: ->
|
47
|
+
@$el.toggleClass('active', false)
|
48
|
+
|
49
|
+
scrollTo: (target) =>
|
50
|
+
@$article.scrollTo target, 600,
|
51
|
+
axis: 'y'
|
52
|
+
offset: -5
|
53
|
+
|
54
|
+
renderMath: =>
|
55
|
+
# MathJax may not have been loaded yet
|
56
|
+
typesetCallback = =>
|
57
|
+
@$el.find('.toast').addClass('hidden')
|
58
|
+
@scrollTo @scrollTarget if @scrollTarget?
|
59
|
+
performTypeset = =>
|
60
|
+
if window.MathJax.isReady
|
61
|
+
MathJax.Hub.Queue(["Typeset", MathJax.Hub, @$article[0], typesetCallback]);
|
62
|
+
else
|
63
|
+
setTimeout performTypeset, 100
|
64
|
+
performTypeset()
|
65
|
+
|
66
|
+
renderArticle: (text) =>
|
67
|
+
unless ELA.converter
|
68
|
+
ELA.converter = new Markdown.Converter()
|
69
|
+
Markdown.Extra.init(ELA.converter)
|
70
|
+
@$article.html(ELA.converter.makeHtml(text))
|
71
|
+
Markdown.Toc.apply(@$article)
|
72
|
+
@renderMath()
|
73
|
+
|
74
|
+
render: =>
|
75
|
+
@$el.html(@template())
|
76
|
+
@$article = @$el.find('article')
|
77
|
+
unless @loadingOrLoadedSuccessfully
|
78
|
+
@loadingOrLoadedSuccessfully = true
|
79
|
+
fileName = @model.helpTextName?() or 'about'
|
80
|
+
$.ajax "help/#{fileName}.md",
|
81
|
+
success: @renderArticle
|
82
|
+
error: =>
|
83
|
+
@loadingOrLoadedSuccessfully = false
|
84
|
+
@$el.find('.toast').addClass('hidden')
|
85
|
+
@$article.html(t('help.messages.missing_help_text'))
|
86
|
+
this
|
@@ -0,0 +1,281 @@
|
|
1
|
+
ELA.Views ?= {}
|
2
|
+
class ELA.Views.InterpolatedGraph extends ELA.Views.BaseGraph
|
3
|
+
initialize: (options = {}) ->
|
4
|
+
super
|
5
|
+
|
6
|
+
@bindCalculatorEvents()
|
7
|
+
|
8
|
+
@model.curves.on 'change:selected', =>
|
9
|
+
@bindCalculatorEvents()
|
10
|
+
@requestRepaint()
|
11
|
+
|
12
|
+
@model.on 'change:calculators', =>
|
13
|
+
@calculateRanges()
|
14
|
+
@bindCalculatorEvents()
|
15
|
+
@requestRepaint()
|
16
|
+
|
17
|
+
if attr = @params.get('valueAtRangeAttribute')
|
18
|
+
@model.on "change:#{attr}", @requestRepaint
|
19
|
+
@model.on 'change:axisLabelingForCurve', @requestRepaint
|
20
|
+
|
21
|
+
bindCalculatorEvents: ->
|
22
|
+
# Remove current callbacks, add new ones for each curve
|
23
|
+
@stopListening(@model.previous('calculators'))
|
24
|
+
|
25
|
+
for calc in @model.get('calculators')
|
26
|
+
for curve in @model.curves.history
|
27
|
+
@listenTo calc, "change:#{curve.get('function')}", @requestRepaint
|
28
|
+
|
29
|
+
@listenTo calc, 'change:maxX change:xRange', @calculateRangeX
|
30
|
+
@listenTo calc, 'change:maxY change:yRange', @calculateRangeY
|
31
|
+
# TODO: Add dynamic dependencies to calculator, so that we can
|
32
|
+
# actually only listen to maxY changes and recalculate ranges.
|
33
|
+
oldestCurve = @model.curves.history[0]
|
34
|
+
if oldestCurve?
|
35
|
+
@listenTo calc, "change:#{oldestCurve.get('function')}", @calculateRanges
|
36
|
+
|
37
|
+
maxRangeX: (func, xScale = @params.get('xScale')) =>
|
38
|
+
func = @model.get('axisLabelingForCurve')?.get('function') unless func?
|
39
|
+
ranges = (calc.xRange(func) for calc in @model.get('calculators'))
|
40
|
+
Math.max.apply(Math, _.compact(ranges)) * xScale
|
41
|
+
|
42
|
+
maxRangeY: (func, yScale = @params.get('yScale')) =>
|
43
|
+
func = @model.get('axisLabelingForCurve')?.get('function') unless func?
|
44
|
+
ranges = (calc.yRange(func) for calc in @model.get('calculators'))
|
45
|
+
Math.max.apply(Math, _.compact(ranges)) * yScale
|
46
|
+
|
47
|
+
xAxisValueLabel: (val, stepsize) ->
|
48
|
+
@axisLabel(val, stepsize)
|
49
|
+
|
50
|
+
yAxisValueLabel: (val, stepsize) ->
|
51
|
+
curve = @model.get('axisLabelingForCurve')
|
52
|
+
if curve?
|
53
|
+
curvePresenter = @Present(curve)
|
54
|
+
val = curvePresenter.unitValue(val)
|
55
|
+
stepsize = curvePresenter.unitValue(stepsize)
|
56
|
+
@axisLabel(val - @params.get('yOffset'), stepsize)
|
57
|
+
|
58
|
+
genericAxisLabel: (axis) ->
|
59
|
+
axisLabel = @params.get("#{axis}AxisLabel")
|
60
|
+
return axisLabel.call(this) if axisLabel? and _.isFunction(axisLabel)
|
61
|
+
return axisLabel if axisLabel?
|
62
|
+
|
63
|
+
axisLabelLocale = @params.get("#{axis}AxisLabelLocale")
|
64
|
+
return @loadLocale(axisLabelLocale) if axisLabelLocale?
|
65
|
+
|
66
|
+
curve = @model.get('axisLabelingForCurve')
|
67
|
+
if curve?
|
68
|
+
return @Present(curve).fullXAxisLabel() if axis is 'x'
|
69
|
+
return @Present(curve).fullYAxisLabel() if axis is 'y'
|
70
|
+
|
71
|
+
@loadLocale("graph.#{axis}AxisLabel", defaultValue: '')
|
72
|
+
|
73
|
+
xAxisLabel: -> @genericAxisLabel('x')
|
74
|
+
yAxisLabel: -> @genericAxisLabel('y')
|
75
|
+
|
76
|
+
getControlPoints: (x0, y0, x1, y1, x2, y2, tension) ->
|
77
|
+
d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2))
|
78
|
+
d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
79
|
+
fa = tension * d01 / (d01 + d12)
|
80
|
+
fb = tension - fa
|
81
|
+
p1x = x1 + fa * (x0 - x2)
|
82
|
+
p1y = y1 + fa * (y0 - y2)
|
83
|
+
p2x = x1 - fb * (x0 - x2)
|
84
|
+
p2y = y1 - fb * (y0 - y2)
|
85
|
+
[p1x, p1y, p2x, p2y]
|
86
|
+
|
87
|
+
drawSpline: (points, t, closed, xPos = ((x) -> x), yPos = ((y) -> y)) ->
|
88
|
+
if points.length <= 4
|
89
|
+
@context.moveTo(xPos(points[0]), yPos(points[1]))
|
90
|
+
@context.lineTo(xPos(points[2]), yPos(points[3]))
|
91
|
+
else
|
92
|
+
cp = []
|
93
|
+
n = points.length
|
94
|
+
points = _.clone(points)
|
95
|
+
if closed
|
96
|
+
points.push points[0], points[1], points[2], points[3]
|
97
|
+
points.unshift points[n - 1]
|
98
|
+
points.unshift points[n - 1]
|
99
|
+
for i in [0..n] by 2
|
100
|
+
cp = cp.concat(@getControlPoints(points[i], points[i+1], points[i+2], points[i+3], points[i+4], points[i+5], t))
|
101
|
+
cp = cp.concat(cp[0], cp[1])
|
102
|
+
for i in [0..n] by 2
|
103
|
+
@context.moveTo(xPos(points[i]), yPos(points[i+1]))
|
104
|
+
@context.bezierCurveTo(xPos(cp[2*i-2]), yPos(cp[2*i-1]), xPos(cp[2*i]), yPos(cp[2*i+1]), xPos(points[i+2]), yPos(points[i+3]))
|
105
|
+
else
|
106
|
+
for i in [0..(n-4)] by 2
|
107
|
+
cp = cp.concat(@getControlPoints(points[i], points[i+1], points[i+2], points[i+3], points[i+4], points[i+5], t))
|
108
|
+
|
109
|
+
@context.moveTo(xPos(points[0]), yPos(points[1]))
|
110
|
+
@context.quadraticCurveTo(xPos(cp[0]), yPos(cp[1]), xPos(points[2]), yPos(points[3]))
|
111
|
+
for i in [2..(n-3)] by 2
|
112
|
+
@context.moveTo(xPos(points[i]), yPos(points[i+1]))
|
113
|
+
@context.bezierCurveTo(xPos(cp[2*i-2]), yPos(cp[2*i-1]), xPos(cp[2*i]), yPos(cp[2*i+1]), xPos(points[i+2]), yPos(points[i+3]))
|
114
|
+
@context.moveTo(xPos(points[n-2]), yPos(points[n-1]))
|
115
|
+
@context.quadraticCurveTo(xPos(cp[2*n-10]), yPos(cp[2*n-9]), xPos(points[n-4]), yPos(points[n-3]))
|
116
|
+
|
117
|
+
drawCurve: (points, tension = 0, closed = false, xPos = ((x) -> x), yPos = ((y) -> y)) ->
|
118
|
+
if tension is 0
|
119
|
+
beginning = true
|
120
|
+
if points.length >= 2
|
121
|
+
@context.moveTo(xPos(points[0]), yPos(points[1]))
|
122
|
+
for i in [2...points.length] by 2
|
123
|
+
@context.lineTo(xPos(points[i]), yPos(points[i+1]))
|
124
|
+
else
|
125
|
+
@drawSpline(points, tension, closed, xPos, yPos)
|
126
|
+
|
127
|
+
_sortedCurves: ->
|
128
|
+
_.sortBy @model.curves.history, (c) ->
|
129
|
+
c.attributes.zIndex
|
130
|
+
|
131
|
+
beforeRenderCurves: (resultCurves) ->
|
132
|
+
afterRenderCurves: (resultCurves) ->
|
133
|
+
|
134
|
+
renderCurves: ->
|
135
|
+
resultCurves = []
|
136
|
+
for calc, i in @model.get('calculators')
|
137
|
+
for curve, j in @_sortedCurves()
|
138
|
+
|
139
|
+
func = curve.get('function')
|
140
|
+
resultCurves.push
|
141
|
+
curve: curve
|
142
|
+
result: calc[func](@xMin, @xMax)
|
143
|
+
yRange: @maxRangeY(func)
|
144
|
+
xRange: @maxRangeX(func)
|
145
|
+
calculatorIdx: i
|
146
|
+
|
147
|
+
@beforeRenderCurves(resultCurves)
|
148
|
+
|
149
|
+
for resultCurve in resultCurves
|
150
|
+
curve = resultCurve.curve
|
151
|
+
result = resultCurve.result
|
152
|
+
yRange = resultCurve.yRange
|
153
|
+
xRange = resultCurve.xRange
|
154
|
+
if _.isObject(result)
|
155
|
+
xPos = (x) => @xOrigin + x * @width / xRange
|
156
|
+
yPos = (y) => @yOrigin - (y + @yOffset) * @height / yRange
|
157
|
+
|
158
|
+
if curve.hasSubcurves()
|
159
|
+
for name, subcurve of curve.subcurves()
|
160
|
+
if result[name].points?
|
161
|
+
@renderCurve(subcurve, result[name], xPos, yPos, resultCurve.calculatorIdx)
|
162
|
+
else if result[name].radius?
|
163
|
+
@renderCircle(subcurve, result[name], xPos, yPos, resultCurve.calculatorIdx)
|
164
|
+
else
|
165
|
+
if result.points?
|
166
|
+
@renderCurve(curve, result, xPos, yPos, resultCurve.calculatorIdx)
|
167
|
+
else if result.radius?
|
168
|
+
@renderCircle(curve, result, xPos, yPos, resultCurve.calculatorIdx)
|
169
|
+
|
170
|
+
@afterRenderCurves(resultCurves)
|
171
|
+
|
172
|
+
renderCircle: (curve, result, xPos, yPos, calculatorIdx) ->
|
173
|
+
func = curve.get('function')
|
174
|
+
yRange = @maxRangeY(func)
|
175
|
+
@context.beginPath()
|
176
|
+
width = Math.abs(xPos(2*result.radius) - @xOrigin)
|
177
|
+
height = Math.abs(yPos(2*result.radius) - @yOrigin)
|
178
|
+
centerX = xPos(result.center[0])
|
179
|
+
centerY = yPos(result.center[1])
|
180
|
+
|
181
|
+
aX = centerX - width/2
|
182
|
+
aY = centerY - height/2
|
183
|
+
hB = (width / 2) * .5522848
|
184
|
+
vB = (height / 2) * .5522848
|
185
|
+
eX = aX + width
|
186
|
+
eY = aY + height
|
187
|
+
mX = aX + width / 2
|
188
|
+
mY = aY + height / 2
|
189
|
+
@context.moveTo(aX, mY);
|
190
|
+
@context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY);
|
191
|
+
@context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY);
|
192
|
+
@context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);
|
193
|
+
@context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY);
|
194
|
+
|
195
|
+
@context.setLineDash(curve.lineDash(calculatorIdx))
|
196
|
+
if curve.strokeStyle()
|
197
|
+
@context.lineWidth = curve.get('lineWidth')
|
198
|
+
@context.strokeStyle = curve.strokeStyle()
|
199
|
+
@context.stroke()
|
200
|
+
if fillStyle = curve.get('fillStyle')
|
201
|
+
@context.fillStyle = fillStyle
|
202
|
+
@context.fill()
|
203
|
+
@context.closePath()
|
204
|
+
|
205
|
+
renderCurve: (curve, result, xPos, yPos, calculatorIdx) ->
|
206
|
+
@context.beginPath()
|
207
|
+
@context.setLineDash(curve.lineDash(calculatorIdx))
|
208
|
+
if result.multiplePaths
|
209
|
+
for setOfPoints, i in result.points
|
210
|
+
@drawCurve(setOfPoints, result.tension, false, xPos, yPos)
|
211
|
+
else
|
212
|
+
@drawCurve(result.points, result.tension, false, xPos, yPos)
|
213
|
+
if curve.strokeStyle()
|
214
|
+
@context.lineWidth = curve.get('lineWidth')
|
215
|
+
@context.strokeStyle = curve.strokeStyle()
|
216
|
+
@context.stroke()
|
217
|
+
if fillStyle = curve.get('fillStyle')
|
218
|
+
@context.fillStyle = fillStyle
|
219
|
+
@context.fill()
|
220
|
+
@context.closePath()
|
221
|
+
|
222
|
+
renderRangeIndicator: ->
|
223
|
+
if @params.get('valueAtRangeAttribute') and (valueAtPoint = @model.get(@params.get('valueAtRangeAttribute')))?
|
224
|
+
@context.beginPath()
|
225
|
+
@context.setLineDash []
|
226
|
+
@context.strokeStyle = '#999999'
|
227
|
+
@context.lineWidth = 2
|
228
|
+
|
229
|
+
# Border below legend
|
230
|
+
@context.moveTo(@width, 0)
|
231
|
+
@context.lineTo(0, 0)
|
232
|
+
|
233
|
+
if (axis = @params.get('valueAtRangeAxis')) is 'x'
|
234
|
+
# Border next to range handler
|
235
|
+
@context.moveTo(0, @height)
|
236
|
+
@context.lineTo(@width, @height)
|
237
|
+
@context.lineTo(@width, @height-10)
|
238
|
+
|
239
|
+
# Range handler line
|
240
|
+
xPos = @xOrigin + valueAtPoint * @width / @xRange
|
241
|
+
@context.moveTo(xPos, 0)
|
242
|
+
@context.lineTo(xPos, @height)
|
243
|
+
else
|
244
|
+
# Border next to range handler
|
245
|
+
@context.lineTo(0, @height)
|
246
|
+
|
247
|
+
# Range handler line
|
248
|
+
yPos = - valueAtPoint * @height / @yRange + @yOrigin
|
249
|
+
@context.moveTo(0, yPos)
|
250
|
+
@context.lineTo(@width, yPos)
|
251
|
+
@context.stroke()
|
252
|
+
@context.closePath()
|
253
|
+
|
254
|
+
@context.beginPath()
|
255
|
+
# The fillStyle of the triangle should match the color of the
|
256
|
+
# background set for the legend and range handler in screen.styl:
|
257
|
+
@context.fillStyle = "#f2f2f2"
|
258
|
+
@context.lineWidth = 1
|
259
|
+
|
260
|
+
if axis is 'x'
|
261
|
+
@context.moveTo(xPos + 8, 0)
|
262
|
+
@context.lineTo(xPos, 8)
|
263
|
+
@context.lineTo(xPos - 8, 0)
|
264
|
+
@context.moveTo(xPos - 8, @height)
|
265
|
+
@context.lineTo(xPos, @height - 8)
|
266
|
+
@context.lineTo(xPos + 8, @height)
|
267
|
+
else
|
268
|
+
@context.moveTo(0, yPos - 8)
|
269
|
+
@context.lineTo(8, yPos)
|
270
|
+
@context.lineTo(0, yPos + 8)
|
271
|
+
@context.moveTo(@width, yPos - 8)
|
272
|
+
@context.lineTo(@width - 8, yPos)
|
273
|
+
@context.lineTo(@width, yPos + 8)
|
274
|
+
@context.stroke()
|
275
|
+
@context.fill()
|
276
|
+
@context.closePath()
|
277
|
+
|
278
|
+
render: =>
|
279
|
+
super
|
280
|
+
@renderRangeIndicator()
|
281
|
+
this
|