flammarion 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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)