flammarion 0.0.1

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 (78) hide show
  1. data/LICENSE +19 -0
  2. data/Readme.md +74 -0
  3. data/lib/flammarion.rb +155 -0
  4. data/lib/flammarion/pane.rb +12 -0
  5. data/lib/flammarion/server.rb +103 -0
  6. data/lib/flammarion/version.rb +3 -0
  7. data/lib/flammarion/writeable.rb +202 -0
  8. data/lib/html/Gemfile +19 -0
  9. data/lib/html/Gemfile.lock +151 -0
  10. data/lib/html/build/images/layers-2x.png +0 -0
  11. data/lib/html/build/images/layers.png +0 -0
  12. data/lib/html/build/images/marker-icon-2x.png +0 -0
  13. data/lib/html/build/images/marker-icon.png +0 -0
  14. data/lib/html/build/images/marker-shadow.png +0 -0
  15. data/lib/html/build/index.html +1 -0
  16. data/lib/html/build/javascripts/actions.js +415 -0
  17. data/lib/html/build/javascripts/all.js +7401 -0
  18. data/lib/html/build/javascripts/map.js +222 -0
  19. data/lib/html/build/javascripts/plot.js +288 -0
  20. data/lib/html/build/javascripts/querystring.js +39 -0
  21. data/lib/html/build/javascripts/status.js +37 -0
  22. data/lib/html/build/javascripts/vendor/ansi_up.js +327 -0
  23. data/lib/html/build/javascripts/vendor/highlight.pack.js +1 -0
  24. data/lib/html/build/javascripts/vendor/jquery.js +5 -0
  25. data/lib/html/build/javascripts/vendor/jquery.transit.min.js +1 -0
  26. data/lib/html/build/javascripts/vendor/l.control.geosearch.js +253 -0
  27. data/lib/html/build/javascripts/vendor/l.geosearch.provider.openstreetmap.js +297 -0
  28. data/lib/html/build/javascripts/vendor/leaflet.js +10 -0
  29. data/lib/html/build/javascripts/vendor/term.js +5974 -0
  30. data/lib/html/build/javascripts/websocket.js +166 -0
  31. data/lib/html/build/spectrum_test.html +12 -0
  32. data/lib/html/build/stylesheets/all.css +992 -0
  33. data/lib/html/build/stylesheets/buttons.css +179 -0
  34. data/lib/html/build/stylesheets/colors.css +0 -0
  35. data/lib/html/build/stylesheets/frontend.css +112 -0
  36. data/lib/html/build/stylesheets/leaflet.css +479 -0
  37. data/lib/html/build/stylesheets/map.css +0 -0
  38. data/lib/html/build/stylesheets/normalize.bak +375 -0
  39. data/lib/html/build/stylesheets/railscasts.css +185 -0
  40. data/lib/html/build/stylesheets/scrollbar.css +14 -0
  41. data/lib/html/build/stylesheets/table.css +21 -0
  42. data/lib/html/build/term_test.html +28 -0
  43. data/lib/html/config.rb +72 -0
  44. data/lib/html/source/images/layers-2x.png +0 -0
  45. data/lib/html/source/images/layers.png +0 -0
  46. data/lib/html/source/images/marker-icon-2x.png +0 -0
  47. data/lib/html/source/images/marker-icon.png +0 -0
  48. data/lib/html/source/images/marker-shadow.png +0 -0
  49. data/lib/html/source/index.html.slim +31 -0
  50. data/lib/html/source/javascripts/actions.coffee +192 -0
  51. data/lib/html/source/javascripts/all.js +3 -0
  52. data/lib/html/source/javascripts/map.coffee +43 -0
  53. data/lib/html/source/javascripts/plot.coffee +233 -0
  54. data/lib/html/source/javascripts/querystring.coffee +12 -0
  55. data/lib/html/source/javascripts/status.coffee +17 -0
  56. data/lib/html/source/javascripts/vendor/ansi_up.js +348 -0
  57. data/lib/html/source/javascripts/vendor/highlight.pack.js +1 -0
  58. data/lib/html/source/javascripts/vendor/jquery.js +4 -0
  59. data/lib/html/source/javascripts/vendor/jquery.transit.min.js +1 -0
  60. data/lib/html/source/javascripts/vendor/l.control.geosearch.js +242 -0
  61. data/lib/html/source/javascripts/vendor/l.geosearch.provider.openstreetmap.js +43 -0
  62. data/lib/html/source/javascripts/vendor/leaflet.js +9 -0
  63. data/lib/html/source/javascripts/vendor/term.js +5973 -0
  64. data/lib/html/source/javascripts/websocket.coffee +83 -0
  65. data/lib/html/source/layouts/layout.erb +0 -0
  66. data/lib/html/source/spectrum_test.html.slim +39 -0
  67. data/lib/html/source/stylesheets/all.css +2 -0
  68. data/lib/html/source/stylesheets/buttons.styl +115 -0
  69. data/lib/html/source/stylesheets/colors.styl +18 -0
  70. data/lib/html/source/stylesheets/frontend.styl +109 -0
  71. data/lib/html/source/stylesheets/leaflet.css +478 -0
  72. data/lib/html/source/stylesheets/map.styl +0 -0
  73. data/lib/html/source/stylesheets/normalize.bak +375 -0
  74. data/lib/html/source/stylesheets/railscasts.css +184 -0
  75. data/lib/html/source/stylesheets/scrollbar.styl +18 -0
  76. data/lib/html/source/stylesheets/table.styl +28 -0
  77. data/lib/html/source/term_test.html.slim +50 -0
  78. metadata +250 -0
@@ -0,0 +1,14 @@
1
+ ::-webkit-scrollbar {
2
+ width: 0.5em;
3
+ height: 0.5em;
4
+ }
5
+ body:hover::-webkit-scrollbar {
6
+ width: 1.5em;
7
+ height: 1.5em;
8
+ }
9
+ ::-webkit-scrollbar-thumb {
10
+ background: #81638a;
11
+ }
12
+ ::-webkit-scrollbar-track {
13
+ background: #433049;
14
+ }
@@ -0,0 +1,21 @@
1
+ table {
2
+ border-collapse: collapse;
3
+ }
4
+ td {
5
+ border: none;
6
+ padding: 0.4em;
7
+ box-sizing: padding-box;
8
+ }
9
+ td.hover {
10
+ background: #240030;
11
+ }
12
+ tr {
13
+ padding: 0;
14
+ }
15
+ tr:hover {
16
+ background: #240030;
17
+ }
18
+ tr:hover td.hover {
19
+ outline: 1px solid #333;
20
+ background: #120018;
21
+ }
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html><html><head><meta content="text/html; charset=UTF-8" http-equiv="content-type" /><meta charset="utf-8" /><meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" /><meta content="width=device-width, initial-scale=1.0" name="viewport" /><link href="stylesheets/railscasts.css" rel="stylesheet" type="text/css" /><link href="stylesheets/all.css" rel="stylesheet" type="text/css" /><link href="stylesheets/scrollbar.css" rel="stylesheet" type="text/css" /><script src="javascripts/all.js" type="text/javascript"></script><script>hljs.initHighlightingOnLoad();</script><script>(function() {
2
+ $(document).ready(function() {
3
+ var term;
4
+ term = new Terminal({
5
+ cols: 80,
6
+ rows: 24,
7
+ screenKeys: true
8
+ });
9
+ term.on('data', function(data) {
10
+ return console.log(data);
11
+ });
12
+ term.on('title', function(title) {
13
+ return document.title = title;
14
+ });
15
+ term.open($('#console-default')[0]);
16
+ return term.write('HEllo World');
17
+ });
18
+
19
+ }).call(this);
20
+ </script><script>(function() {
21
+ $.extend(WSClient.prototype.actions, {
22
+ term: function(data) {
23
+ return term.write(data.data);
24
+ }
25
+ });
26
+
27
+ }).call(this);
28
+ </script></head><body><div class="hidden" id="toolbar"><a class="tool-button" href="#">Open</a><a class="tool-button" href="#">Save</a></div><div id="panes"><pre class="pane" id="console-default" style="height:100%"></pre></div><div class="hidden" id="dialog"><pre id="message">Hi World</pre><a class="full-button" href="#">Ok</a></div><div id="status"><div class="left"></div><div class="center"></div><div class="right"></div></div></body></html>
@@ -0,0 +1,72 @@
1
+ ###
2
+ # Compass
3
+ ###
4
+
5
+ # Change Compass configuration
6
+ # compass_config do |config|
7
+ # config.output_style = :compact
8
+ # end
9
+
10
+ ###
11
+ # Page options, layouts, aliases and proxies
12
+ ###
13
+
14
+ # Per-page layout changes:
15
+ #
16
+ # With no layout
17
+ # page "/path/to/file.html", :layout => false
18
+ #
19
+ # With alternative layout
20
+ # page "/path/to/file.html", :layout => :otherlayout
21
+ #
22
+ # A path which all have the same layout
23
+ # with_layout :admin do
24
+ # page "/admin/*"
25
+ # end
26
+
27
+ # Proxy pages (https://middlemanapp.com/advanced/dynamic_pages/)
28
+ # proxy "/this-page-has-no-template.html", "/template-file.html", :locals => {
29
+ # :which_fake_page => "Rendering a fake page with a local variable" }
30
+
31
+ ###
32
+ # Helpers
33
+ ###
34
+
35
+ # Automatic image dimensions on image_tag helper
36
+ # activate :automatic_image_sizes
37
+
38
+ # Reload the browser automatically whenever files change
39
+ configure :development do
40
+ activate :livereload
41
+ end
42
+
43
+ # Methods defined in the helpers block are available in templates
44
+ # helpers do
45
+ # def some_helper
46
+ # "Helping"
47
+ # end
48
+ # end
49
+
50
+ set :css_dir, 'stylesheets'
51
+
52
+ set :js_dir, 'javascripts'
53
+
54
+ set :images_dir, 'images'
55
+
56
+ # Build-specific configuration
57
+ configure :build do
58
+ # For example, change the Compass output style for deployment
59
+ # activate :minify_css
60
+
61
+ # Minify Javascript on build
62
+ # activate :minify_javascript
63
+
64
+ # Enable cache buster
65
+ # activate :asset_hash
66
+
67
+ # Use relative URLs
68
+ activate :relative_assets
69
+
70
+ # Or use a different image path
71
+ # set :http_prefix, "/Content/images/"
72
+ end
Binary file
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Welcome to Middleman
3
+ layout: false
4
+ ---
5
+
6
+ doctype html
7
+ html
8
+ head
9
+ meta[http-equiv="content-type" content="text/html; charset=UTF-8"]
10
+ meta charset="utf-8"
11
+ meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"
12
+ meta[name="viewport" content="width=device-width, initial-scale=1.0"]
13
+ title Flammarion
14
+ = stylesheet_link_tag("all")
15
+ = javascript_include_tag("all")
16
+ javascript:
17
+ hljs.initHighlightingOnLoad();
18
+ body
19
+ #toolbar.hidden
20
+ a.tool-button[href="#"] Open
21
+ a.tool-button[href="#"] Save
22
+ #panes
23
+ pre#console-default.pane[style="height:100%"]
24
+ #dialog.hidden
25
+ pre#message Hi World
26
+ a.full-button[href="#"] Ok
27
+ #status
28
+ .left
29
+ .center
30
+ .right
31
+
@@ -0,0 +1,192 @@
1
+ #= require websocket.coffee
2
+ $.extend WSClient.prototype.actions,
3
+ append: (data) ->
4
+ @__parent.check_target(data)
5
+ element = $("#console-#{data.target}")
6
+ marginSize = 16
7
+ atBottom = element.scrollTop() >= element[0].scrollHeight - element.height() - marginSize - 2 or element[0].scrollHeight - marginSize < element.height()
8
+ console.log "top: #{element.scrollTop()} height: #{element[0].scrollHeight - element.height() - marginSize} marginSize: #{marginSize} atBottom: #{atBottom}"
9
+ element.append(@__parent.escape(data.text, data))
10
+ element.scrollTop(element[0].scrollHeight - element.height() - marginSize) if atBottom
11
+
12
+ replace: (data) ->
13
+ @__parent.check_target(data)
14
+ $("#console-#{data.target}").html(@__parent.escape(data.text, data))
15
+
16
+ clear: (data) ->
17
+ @__parent.check_target(data)
18
+ $("#console-#{data.target}").html("") # empty() is really slow for some reason
19
+
20
+ addpane: (data) ->
21
+ if data.target
22
+ target = @__parent.check_target(data)
23
+ else
24
+ target = $('#panes')
25
+
26
+ target.append("<pre class='pane' id='console-#{data.name}'><pre>") if target.find("#console-#{data.name}").size() is 0
27
+ @__parent.resize_panes(data)
28
+
29
+ closepane: (data) ->
30
+ target = $("#console-#{data.target}")
31
+ unless target.size() is 0
32
+ target.remove()
33
+ @__parent.resize_panes(data)
34
+
35
+ hidepane: (data) ->
36
+ target = @__parent.check_target(data)
37
+ target.addClass("hidden")
38
+ target.removeClass("pane")
39
+ @__parent.resize_panes({target_element:target.parent()})
40
+
41
+ showpane: (data) ->
42
+ target = @__parent.check_target(data)
43
+ target.addClass("pane")
44
+ target.removeClass("hidden")
45
+ @__parent.resize_panes(data)
46
+
47
+ reorient: (data) ->
48
+ if data.target
49
+ target = @__parent.check_target(data)
50
+ else
51
+ target = $('#panes')
52
+
53
+ if data.orientation is "horizontal"
54
+ target.addClass("horizontal")
55
+ else
56
+ target.removeClass("horizontal")
57
+
58
+ @__parent.resize_panes(data)
59
+
60
+ # plot: (data) ->
61
+ # @__parent.check_target(data)
62
+ # drawPlot("#console-#{data.target}", data.data, $.extend({orientation:@__parent.orientation}, data))
63
+
64
+ highlight: (data) ->
65
+ target = @__parent.check_target(data)
66
+ code = $("<code>#{ansi_up.escape_for_html(data.text)}</code>")
67
+ code.addClass data.language if data.language
68
+ @__parent.add(code, target, data)
69
+ hljs.highlightBlock(code[0])
70
+
71
+ button: (data) ->
72
+ target = @__parent.check_target(data)
73
+ class_name = if data.inline then 'inline-button' else 'full-button'
74
+ element = $("<a href='#' class='#{class_name}'>#{@__parent.escape(data.label, data)}</a>")
75
+ element.click =>
76
+ @__parent.send({
77
+ id:data.id
78
+ action:'callback'
79
+ source:'button'
80
+ original_msg:data
81
+ })
82
+ target.append element
83
+
84
+ buttonbox: (data) ->
85
+ target = @__parent.check_target(data)
86
+
87
+ element = target.find("#console-#{data.name}")
88
+ if element.size() is 0
89
+ target.prepend("<pre class='button-box' id='console-#{data.name}'></pre>")
90
+ else
91
+ element.addClass('button-box')
92
+
93
+ break: (data) ->
94
+ target = @__parent.check_target(data)
95
+ code = $("<hr>")
96
+ @__parent.add(code, target, data)
97
+
98
+ subpane: (data) ->
99
+ target = @__parent.check_target(data)
100
+ element = target.find("#console-#{data.name}")
101
+ if element.size() is 0
102
+ target.append("<pre id='console-#{data.name}' class='pane'></pre>")
103
+
104
+ input: (data) ->
105
+ target = @__parent.check_target(data)
106
+ if data.multiline
107
+ element = $("<textarea placeholder='#{data.label}' class='inline-text-input'></textarea>")
108
+ else
109
+ element = $("<input type='text' placeholder='#{data.label}' class='inline-text-input'>")
110
+ if data.value
111
+ element[0].value = data.value
112
+
113
+ element.change =>
114
+ unless element.hasClass("unclicked")
115
+ @__parent.send({
116
+ id:data.id
117
+ action:'callback'
118
+ source:'input'
119
+ text: element[0].value
120
+ original_msg:data
121
+ })
122
+ if data.once
123
+ replaceText = @__parent.escape("#{element[0].value}\n")
124
+ replaceText = "#{data.label}#{replaceText}" if data.keep_label
125
+ element.replaceWith(replaceText)
126
+
127
+ target.append(element)
128
+
129
+ if data.focus
130
+ element.focus()
131
+
132
+ checkbox: (data) ->
133
+ target = @__parent.check_target(data)
134
+ element = $("<label class='inline-checkbox'><input type='checkbox'><span>#{@__parent.escape(data.label,data)}</span></label>'")
135
+ if data.value
136
+ element.find('input').attr "checked", true
137
+ element.addClass "checked"
138
+ element.change (e) =>
139
+ element.toggleClass("checked", element.find('input').prop('checked'))
140
+ @__parent.send({
141
+ id:data.id
142
+ action:'callback'
143
+ source:'input'
144
+ checked: element.find('input').prop('checked')
145
+ original_msg:data
146
+ })
147
+ element.click (e) =>
148
+ if e.shiftKey and @__lastChecked
149
+ all_boxes = $('.inline-checkbox')
150
+ start = all_boxes.index(@__lastChecked)
151
+ stop = all_boxes.index(element)
152
+ console.log start, stop
153
+
154
+ all_boxes.slice(Math.min(start, stop), Math.max(start, stop) + 1).find('input').prop("checked", @__lastChecked.find('input').prop("checked"))
155
+ all_boxes.change()
156
+ else
157
+ @__lastChecked = element
158
+ target.append(element)
159
+
160
+ alert: (data) ->
161
+ alert(data.text)
162
+
163
+ title: (data) ->
164
+ document.title = data.title
165
+
166
+ status: (data) ->
167
+ @__parent.status.show_status(data)
168
+
169
+ layout: (data) ->
170
+ $("body").html(data.data)
171
+
172
+ script: (data) ->
173
+ eval(data.data)
174
+
175
+ table: (data) ->
176
+ target = @__parent.check_target(data)
177
+ html = "<table>"
178
+ if data.headers
179
+ html += "<tr>"
180
+ html += "<th>#{@__parent.escape(header, data)}</th>" for header in data.headers
181
+ html += "<tr>"
182
+ for row in data.rows
183
+ html += "<tr>"
184
+ html += "<td>#{@__parent.escape(cell, data)}</td>" for cell in row
185
+ html += "</tr>"
186
+ html += "</table>"
187
+ html = $(html)
188
+ unless data.interactive is false
189
+ html.delegate 'td', 'mouseover mouseout', ->
190
+ pos = $(this).index()
191
+ html.find("td:nth-child(#{(pos+1)})").toggleClass("hover")
192
+ @__parent.add(html, target, data)
@@ -0,0 +1,3 @@
1
+ //= require vendor/jquery.js
2
+ //= require_tree ./vendor
3
+ //= require_tree .
@@ -0,0 +1,43 @@
1
+ #= require websocket.coffee
2
+ __geosearch = null
3
+ $.extend WSClient.prototype.actions,
4
+ map: (data) ->
5
+ default_options =
6
+ latitude: 51.505
7
+ longitude: -0.09
8
+ zoom: 13
9
+ marker: true
10
+ replace: true
11
+
12
+ options = $.extend default_options, data
13
+
14
+ if options.address
15
+ __geosearch ||= new L.GeoSearch.Provider.OpenStreetMap()
16
+ url = __geosearch.GetServiceUrl(options.address)
17
+ $.getJSON url, (json) =>
18
+ console.log(json)
19
+ options.latitude = json[0].lat
20
+ options.longitude = json[0].lon
21
+ options.address = null
22
+ @map(options)
23
+ return
24
+
25
+ target = @__parent.check_target(data)
26
+ mapDiv = $('<div id="map" class="map"></div>')
27
+ @__parent.add(mapDiv, target, data)
28
+ mapDiv.height target.height()
29
+ $(window).resize ->
30
+ mapDiv.height target.height()
31
+
32
+ latitude = options.latitude
33
+ longitude = options.longitude
34
+
35
+ map = L.map('map', {center: [latitude, longitude], zoom: options.zoom})
36
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
37
+ attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
38
+ maxZoom: 19,
39
+ subdomans: ["a.tile", "b.tile", "c.tile"]
40
+ }).addTo(map);
41
+
42
+ L.Icon.Default.imagePath = "/images"
43
+ L.marker([latitude, longitude]).addTo(map) if options.marker
@@ -0,0 +1,233 @@
1
+ $.event.special.removed =
2
+ remove: (o) ->
3
+ o.handler() if o.handler
4
+
5
+ $.extend WSClient.prototype.actions,
6
+ plot: (data) ->
7
+ target = @__parent.check_target(data)
8
+ @__plots ||= {}
9
+ if @__plots[data.id]
10
+ @__plots[data.id].update(data)
11
+ else
12
+ @__plots[data.id] = new Plot(target, @__parent, data)
13
+
14
+ class Plot
15
+ default_options:
16
+ color: "#fff"
17
+ replace: true
18
+ size: 1.0
19
+ orientation: 'vertical'
20
+ xscale: 1.0
21
+ yscale: 1.0
22
+ tick_height: 15
23
+ number_of_ticks: 10
24
+ tick_color: "rgba(255,255,255,0.5)"
25
+ tick_precision: 2
26
+ id: "spec0"
27
+ draw_zero: true
28
+ fill_color: null
29
+ draw_line: true
30
+ draw_marker: false
31
+ marker_color: '#88F'
32
+
33
+ parse_property: (prop) ->
34
+ parseInt(prop.slice(0, -1))
35
+
36
+ move_zoom: (event) =>
37
+ @zoom_box.width = event.pageX - @zoom_box.left
38
+ @zoom_box.height = event.pageY - @zoom_box.top
39
+ @zoom_element.css "width", "#{Math.abs(@zoom_box.width)}"
40
+ @zoom_element.css "height", "#{Math.abs(@zoom_box.height)}"
41
+
42
+ @zoom_element.css "left", event.pageX if @zoom_box.width < 0
43
+ @zoom_element.css "top", event.pageY if @zoom_box.height < 0
44
+
45
+ mousemove: (event) =>
46
+ @mouse_element.removeClass "hidden"
47
+ @canvas.focus()
48
+ relative_x_pos = (event.pageX - @canvas.offset().left) / @plot_width
49
+ relative_y_pos = 1.0 - ((event.pageY - @canvas.offset().top) / @plot_height)
50
+
51
+ @mouse_element.css "left", "#{event.pageX + 15}px"
52
+ @mouse_element.css "top", "#{event.pageY + 15}px"
53
+
54
+ mouse_x_value = relative_x_pos * @xscaled_end_value + (1.0 - relative_x_pos) * @xscaled_start_value
55
+ mouse_x_value = mouse_x_value * @xvalue_scale
56
+ mouse_y_value = relative_y_pos * @yscaled_end_value + (1.0 - relative_y_pos) * @yscaled_start_value
57
+ @mouse_element.text "#{mouse_x_value.toFixed(2)}. #{mouse_y_value.toFixed(2)}"
58
+
59
+ @move_zoom(event) if @mouse_is_down
60
+
61
+ mousedown: (event) =>
62
+ unless @mouse_is_down
63
+ @zoom_box ||= {}
64
+ @zoom_box.left = event.pageX
65
+ @zoom_box.top = event.pageY
66
+ @zoom_element.css "left", event.pageX
67
+ @zoom_element.css "top", event.pageY
68
+ @zoom_element.css "width", 0
69
+ @zoom_element.css "height", 0
70
+ @zoom_element.removeClass("hidden")
71
+ @mouse_is_down = true
72
+
73
+ mouseup: (event) =>
74
+ @mouse_is_down = false
75
+ @zoom_element.addClass "hidden"
76
+
77
+ zoom_width = @parse_property(@zoom_element.css "width")
78
+ zoom_xstart_pixel = @parse_property(@zoom_element.css "left") - @canvas.offset().left
79
+ zoom_xend_pixel = zoom_xstart_pixel + zoom_width
80
+
81
+ relative_xstart_pos = zoom_xstart_pixel / @plot_width
82
+ relative_xend_pos = zoom_xend_pixel / @plot_width
83
+
84
+ zoom_xstart_value = relative_xstart_pos * @xscaled_end_value + (1.0 - relative_xstart_pos) * @xscaled_start_value
85
+ zoom_xend_value = relative_xend_pos * @xscaled_end_value + (1.0 - relative_xend_pos) * @xscaled_start_value
86
+
87
+ zoom_height = @parse_property(@zoom_element.css "height")
88
+ zoom_yend_pixel = @parse_property(@zoom_element.css "top") - @canvas.offset().top
89
+ zoom_ystart_pixel = zoom_yend_pixel + zoom_height
90
+
91
+ relative_ystart_pos = 1.0 - ((zoom_ystart_pixel) / @plot_height)
92
+ relative_yend_pos = 1.0 - ((zoom_yend_pixel) / @plot_height)
93
+
94
+ zoom_ystart_value = relative_ystart_pos * @yscaled_end_value + (1.0 - relative_ystart_pos) * @yscaled_start_value
95
+ zoom_yend_value = relative_yend_pos * @yscaled_end_value + (1.0 - relative_yend_pos) * @yscaled_start_value
96
+
97
+ console.log zoom_ystart_value, zoom_yend_value
98
+
99
+ @zoom_to(zoom_xstart_value, zoom_xend_value, zoom_ystart_value, zoom_yend_value)
100
+
101
+ keypress: (event) =>
102
+ switch event.which
103
+ when 114, 97
104
+ @zoom_to(@xstart_value, @xend_value, @ystart_value, @yend_value)
105
+ @draw(@data)
106
+
107
+ setup_hover: ->
108
+ @zoom_element = $('#plot-zoombox')
109
+ if @zoom_element.size() is 0
110
+ @zoom_element = $('<div id="plot-zoom-element" class="hidden"></div>')
111
+ $('body').append @zoom_element
112
+
113
+ @mouse_element = $('#plot-mouseover')
114
+ if @mouse_element.size() is 0
115
+ @mouse_element = $('<div id="plot-mouseover" class="hidden"></div>')
116
+ $('body').append(@mouse_element)
117
+
118
+ @canvas.mousemove @mousemove
119
+ @canvas.mouseout (event) => @mouse_element.addClass "hidden"
120
+ @canvas.mousedown @mousedown
121
+ @canvas.mouseup @mouseup
122
+ @canvas.keypress @keypress
123
+ @canvas.on 'removed', => @canvas.off()
124
+
125
+ create_container: ->
126
+ @container = $("<div class='plot' id='#{@id}'><canvas tabindex='1'></canvas></div>")
127
+ @__parent.add @container, @target, @options
128
+
129
+ set_canvas_size: ->
130
+ @container_width = @container.width()
131
+ @container_height = @container.height()
132
+ @canvas[0].width = @canvas_width = @container_width
133
+ @canvas[0].height = @canvas_height = @container_height
134
+ @set_scale_values()
135
+
136
+ zoom_to: (@xscaled_start_value, @xscaled_end_value, @yscaled_start_value, @yscaled_end_value) ->
137
+ @draw(@data)
138
+
139
+ set_scale_values: ->
140
+ @xvalue_scale = @options.xscale
141
+ @xend_value = @options.xend || (@data.length - 1)
142
+ @xstart_value = @options.xstart || 0
143
+
144
+ @yvalue_scale = @options.yscale
145
+ @ystart_value = @options.ystart || 0
146
+ @ystart_value = Math.min(@data...) if @ystart_value is 'min'
147
+ @yend_value = @options.yend || Math.max(@data...)
148
+
149
+ @plot_height = @canvas_height - @options.tick_height
150
+ @plot_width = @canvas_width
151
+
152
+ @xscaled_start_value = @xstart_value
153
+ @xscaled_end_value = @xend_value
154
+
155
+ @yscaled_start_value = @ystart_value
156
+ @yscaled_end_value = @yend_value
157
+
158
+ y_value_to_pixel: (y) ->
159
+ @plot_height - (y - @yscaled_start_value) / (@yscaled_end_value - @yscaled_start_value) * @plot_height
160
+
161
+ x_value_to_pixel: (i) ->
162
+ (i - @xscaled_start_value) / (@xscaled_end_value - @xscaled_start_value) * @plot_width
163
+
164
+ draw: (data) ->
165
+ @ctx.clearRect 0, 0, @canvas_width, @canvas_height
166
+ @ctx.fillStyle = @options.marker_color
167
+ @ctx.strokeStyle = @options.color
168
+
169
+ @ctx.font = "8px Monospace";
170
+ @ctx.textAlign = "center";
171
+
172
+ @ctx.beginPath()
173
+ @ctx.moveTo(@x_value_to_pixel(0), @y_value_to_pixel(data[0]))
174
+ for i in [1..data.length - 1]
175
+ @ctx.lineTo(@x_value_to_pixel(i), @y_value_to_pixel(data[i])) if @options.draw_line
176
+ @ctx.fillText("x", @x_value_to_pixel(i), @y_value_to_pixel(data[i])) if @options.draw_marker
177
+ @ctx.moveTo(@x_value_to_pixel(0), @y_value_to_pixel(data[0]))
178
+ @ctx.closePath()
179
+
180
+ @ctx.fillStyle = @options.fill_color
181
+ @ctx.fill() if @options.fill_color
182
+ @ctx.stroke()
183
+ @draw_ticks()
184
+
185
+ draw_ticks: ->
186
+ @ctx.font = "#{@options.tick_height - 3}px Monospace";
187
+ @ctx.fillStyle = @options.tick_color
188
+ @ctx.strokeStyle = @options.tick_color
189
+ @ctx.textAlign = "center";
190
+ @ctx.textBaseline = 'middle';
191
+ number_of_ticks = @options.number_of_ticks + 1
192
+ tick_height = @options.tick_height
193
+ for i in [1..number_of_ticks - 1]
194
+ @ctx.beginPath()
195
+ pos = i * @plot_width / number_of_ticks
196
+ @ctx.moveTo(pos, @plot_height + tick_height / 2)
197
+ @ctx.lineTo(pos, @plot_height - tick_height)
198
+ @ctx.stroke()
199
+
200
+ tickStart = @xscaled_start_value
201
+ tickEnd = @xscaled_end_value
202
+ tickValue = i * 1.0 / number_of_ticks
203
+ tickValue = tickValue * tickEnd + (1.0 - tickValue) * tickStart
204
+ tickValue = tickValue * @xvalue_scale
205
+ @ctx.textAlign = 'start'
206
+ @ctx.fillText("#{tickValue.toFixed(@options.tick_precision)}", pos + 3, @canvas_height - 3)
207
+
208
+ @ctx.beginPath()
209
+ @ctx.moveTo(0, @plot_height)
210
+ @ctx.lineTo(@canvas_width, @plot_height)
211
+ @ctx.stroke()
212
+
213
+ update: (data) ->
214
+ @data = data.data
215
+ $.extend @options, data
216
+ @draw(data.data)
217
+
218
+ constructor: (@target, @__parent, @input_options) ->
219
+ @options = $.extend({}, @default_options, @input_options)
220
+ @id = @options.id
221
+ @data = @options.data
222
+
223
+ @container = @target.find("##{@id}")
224
+
225
+ if @container.size() is 0
226
+ @create_container()
227
+
228
+ @canvas = @container.find("canvas")
229
+ @ctx = @canvas[0].getContext("2d")
230
+ @set_canvas_size()
231
+ @setup_hover()
232
+
233
+ @draw(@data)