wads 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +9 -3
- data/lib/wads/app.rb +91 -66
- data/lib/wads/data_structures.rb +281 -12
- data/lib/wads/textinput.rb +49 -4
- data/lib/wads/version.rb +1 -1
- data/lib/wads/widgets.rb +656 -207
- data/media/WadsScreenshot.png +0 -0
- data/sample_app.rb +9 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2652d96c92be67ffd117365e2eb1ed93c21fd6f6c83cae037c6761f3f70754d5
|
4
|
+
data.tar.gz: e1680952ab2bdd333bc518ae7d97bca0a8bfc4033e2b0b9f8bf062e689ee22e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e07cd62b59ca7d4e73176a94f3396f37f2981b6d448ebdd9490f9b6d5c0a69e0cd531805fed3e5512435b2d9a669521b1a047e0d022dd9ee0fb1ffb9ddd1941
|
7
|
+
data.tar.gz: 9189a546fe8c0f74fa0e18abbca8de17eacd70b63b7092e09374b4315f832ed359f62add905a3ce9c82641728b569846fc44f04007b2e14bcdb28e0608f35e3d
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
A number of Ruby Gosu-based (W)idgets (a)nd (D)ata (S)tructures for your applications.
|
4
4
|
|
5
|
+

|
5
6
|
## Installation
|
6
7
|
|
7
8
|
Add this line to your application’s Gemfile:
|
@@ -9,7 +10,7 @@ Add this line to your application’s Gemfile:
|
|
9
10
|
```
|
10
11
|
gem 'wads'
|
11
12
|
```
|
12
|
-
And
|
13
|
+
And then run bundle install.
|
13
14
|
|
14
15
|
## Sample Application
|
15
16
|
|
@@ -20,7 +21,7 @@ git clone https://github.com/dbroemme/ruby-wads.git
|
|
20
21
|
cd ruby-wads
|
21
22
|
./bin/setup
|
22
23
|
./run
|
23
|
-
./run-sample-app -s
|
24
|
+
./run-sample-app -s
|
24
25
|
```
|
25
26
|
|
26
27
|
This will run the sample NASDAQ stocks analysis that features the use of the
|
@@ -30,7 +31,12 @@ You can also see the graph capabilities by running the Star Wars analysis exampl
|
|
30
31
|
This uses a data set that captures all character interactions within Episode 4.
|
31
32
|
|
32
33
|
```
|
33
|
-
./run-sample-app -j
|
34
|
+
./run-sample-app -j
|
35
|
+
```
|
36
|
+
|
37
|
+
There is also a sample Graph display using the following command.
|
38
|
+
```
|
39
|
+
./run-sample-app -g
|
34
40
|
```
|
35
41
|
|
36
42
|
## References
|
data/lib/wads/app.rb
CHANGED
@@ -33,25 +33,33 @@ class WadsSampleApp < Gosu::Window
|
|
33
33
|
opts = SampleAppCommand.new.parse.run
|
34
34
|
if opts[:stocks]
|
35
35
|
stats = process_stock_data
|
36
|
-
if opts[:
|
36
|
+
if opts[:text]
|
37
|
+
stats.report(Date::DAYNAMES[1..5])
|
38
|
+
else
|
37
39
|
@display_widget = SampleStocksDisplay.new(@small_font, stats)
|
38
40
|
show
|
39
|
-
else
|
40
|
-
stats.report(Date::DAYNAMES[1..5])
|
41
41
|
end
|
42
42
|
|
43
43
|
elsif opts[:jedi]
|
44
44
|
graph = process_star_wars_data
|
45
45
|
@display_widget = SampleStarWarsDisplay.new(@small_font, graph)
|
46
46
|
show
|
47
|
+
|
47
48
|
elsif opts[:lottery]
|
48
49
|
process_lottery_data
|
50
|
+
|
51
|
+
elsif opts[:graph]
|
52
|
+
graph = create_test_graph
|
53
|
+
if not opts[:text]
|
54
|
+
@display_widget = SampleGraphDisplay.new(@small_font, graph)
|
55
|
+
show
|
56
|
+
end
|
49
57
|
else
|
50
58
|
puts " "
|
51
59
|
puts "Select one of the following sample analysis options"
|
52
60
|
puts "-s Run sample stocks analysis"
|
53
61
|
puts "-j Run sample Star Wars character analysis"
|
54
|
-
puts "-
|
62
|
+
puts "-g Run sample graph display"
|
55
63
|
puts " "
|
56
64
|
exit
|
57
65
|
end
|
@@ -78,8 +86,10 @@ class WadsSampleApp < Gosu::Window
|
|
78
86
|
close if id == Gosu::KbEscape
|
79
87
|
# Delegate button events to the primary display widget
|
80
88
|
result = @display_widget.button_down id, mouse_x, mouse_y
|
81
|
-
if result.
|
82
|
-
|
89
|
+
if not result.nil? and result.is_a? WidgetResult
|
90
|
+
if result.close_widget
|
91
|
+
close
|
92
|
+
end
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
@@ -174,10 +184,26 @@ class WadsSampleApp < Gosu::Window
|
|
174
184
|
number_of_scenes_together = interaction['value']
|
175
185
|
edge_tags = {}
|
176
186
|
edge_tags["scenes"] = number_of_scenes_together
|
177
|
-
|
187
|
+
graph.add_edge(character_one, character_two, edge_tags)
|
178
188
|
end
|
179
189
|
graph
|
180
190
|
end
|
191
|
+
|
192
|
+
def create_test_graph
|
193
|
+
g = Graph.new
|
194
|
+
g.add("a")
|
195
|
+
g.add("b")
|
196
|
+
g.add("c")
|
197
|
+
g.add("d")
|
198
|
+
g.add("e")
|
199
|
+
g.add("f")
|
200
|
+
g.connect("a", "b")
|
201
|
+
g.connect("a", "c")
|
202
|
+
g.connect("b", "d")
|
203
|
+
g.connect("b", "e")
|
204
|
+
g.connect("e", "f")
|
205
|
+
g
|
206
|
+
end
|
181
207
|
end
|
182
208
|
|
183
209
|
class SampleStocksDisplay < Widget
|
@@ -187,15 +213,16 @@ class SampleStocksDisplay < Widget
|
|
187
213
|
super(10, 100, COLOR_HEADER_BRIGHT_BLUE)
|
188
214
|
set_dimensions(780, 500)
|
189
215
|
set_font(font)
|
190
|
-
|
191
|
-
|
192
|
-
|
216
|
+
add_document(sample_content, 5, 5, @width, @height)
|
217
|
+
add_button("Exit", 380, @height - 30) do
|
218
|
+
WidgetResult.new(true)
|
219
|
+
end
|
193
220
|
|
194
221
|
@stats = stats
|
195
|
-
@data_table =
|
196
|
-
|
222
|
+
@data_table = add_single_select_table(5, 100, # top left corner
|
223
|
+
770, 200, # width, height
|
197
224
|
["Day", "Min", "Avg", "StdDev", "Max", "p10", "p90"], # column headers
|
198
|
-
|
225
|
+
COLOR_WHITE) # font and text color
|
199
226
|
@data_table.selected_color = COLOR_LIGHT_GRAY
|
200
227
|
Date::DAYNAMES[1..5].each do |day|
|
201
228
|
min = format_percent(@stats.min(day))
|
@@ -206,7 +233,7 @@ class SampleStocksDisplay < Widget
|
|
206
233
|
p90 = format_percent(@stats.percentile(day, 0.90))
|
207
234
|
@data_table.add_row([day, min, avg, std, max, p10, p90], COLOR_HEADER_BRIGHT_BLUE)
|
208
235
|
end
|
209
|
-
|
236
|
+
|
210
237
|
@selection_text = nil
|
211
238
|
end
|
212
239
|
|
@@ -228,21 +255,15 @@ class SampleStocksDisplay < Widget
|
|
228
255
|
end
|
229
256
|
end
|
230
257
|
|
231
|
-
def
|
232
|
-
if
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
@selection_text = Text.new("You selected #{val}, a great day!",
|
241
|
-
x + 5, y + 400, @font)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
WidgetResult.new(false)
|
258
|
+
def handle_mouse_down mouse_x, mouse_y
|
259
|
+
if @data_table.contains_click(mouse_x, mouse_y)
|
260
|
+
val = @data_table.set_selected_row(mouse_y, 0)
|
261
|
+
if not val.nil?
|
262
|
+
@selection_text = Text.new("You selected #{val}, a great day!",
|
263
|
+
x + 5, y + 400, @font)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
nil
|
246
267
|
end
|
247
268
|
end
|
248
269
|
|
@@ -253,22 +274,24 @@ class SampleStarWarsDisplay < Widget
|
|
253
274
|
super(10, 100, COLOR_HEADER_BRIGHT_BLUE)
|
254
275
|
set_dimensions(780, 500)
|
255
276
|
set_font(font)
|
256
|
-
add_child(Document.new(sample_content, x + 5, y + 5, @width, @height, @font))
|
257
|
-
@exit_button = Button.new("Exit", 380, bottom_edge - 30, @font)
|
258
|
-
add_child(@exit_button)
|
259
|
-
|
260
277
|
@graph = graph
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
278
|
+
|
279
|
+
add_document(sample_content, 5, 5, @width, @height)
|
280
|
+
add_button("Exit", 370, @height - 30) do
|
281
|
+
WidgetResult.new(true)
|
282
|
+
end
|
283
|
+
|
284
|
+
@data_table = add_single_select_table(5, 70, # top left corner
|
285
|
+
770, 180, # width, height
|
286
|
+
["Character", "Number of Scenes"], # column headers
|
287
|
+
COLOR_WHITE, # font and text color
|
288
|
+
5) # max visible rows
|
266
289
|
@data_table.selected_color = COLOR_LIGHT_GRAY
|
290
|
+
|
267
291
|
@graph.node_list.each do |character|
|
268
292
|
@data_table.add_row([character.name, character.value], character.get_tag("color"))
|
269
293
|
end
|
270
|
-
|
271
|
-
@graph_display = GraphWidget.new(x + 5, y + 260, 770, 200, @font, @color, @graph)
|
294
|
+
@graph_display = add_graph_display(5, 260, 770, 200, @graph)
|
272
295
|
end
|
273
296
|
|
274
297
|
def sample_content
|
@@ -278,38 +301,40 @@ class SampleStarWarsDisplay < Widget
|
|
278
301
|
HEREDOC
|
279
302
|
end
|
280
303
|
|
281
|
-
def
|
282
|
-
|
283
|
-
end
|
284
|
-
|
285
|
-
def button_down id, mouse_x, mouse_y
|
286
|
-
if id == Gosu::MsLeft
|
287
|
-
if @exit_button.contains_click(mouse_x, mouse_y)
|
288
|
-
return WidgetResult.new(true)
|
289
|
-
elsif @data_table.contains_click(mouse_x, mouse_y)
|
290
|
-
val = @data_table.set_selected_row(mouse_y, 0)
|
291
|
-
if val.nil?
|
292
|
-
# nothing to do
|
293
|
-
else
|
294
|
-
node = @graph.find_node(val)
|
295
|
-
@graph_display.set_display(node, 2)
|
296
|
-
end
|
297
|
-
elsif @graph_display.contains_click(mouse_x, mouse_y)
|
298
|
-
@graph_display.button_down id, mouse_x, mouse_y
|
299
|
-
end
|
300
|
-
elsif id == Gosu::KbUp
|
304
|
+
def handle_key_press id, mouse_x, mouse_y
|
305
|
+
if id == Gosu::KbUp
|
301
306
|
@data_table.scroll_up
|
302
307
|
elsif id == Gosu::KbDown
|
303
308
|
@data_table.scroll_down
|
304
309
|
end
|
305
310
|
WidgetResult.new(false)
|
306
|
-
end
|
307
|
-
|
308
|
-
def button_up id, mouse_x, mouse_y
|
309
|
-
@graph_display.button_up id, mouse_x, mouse_y
|
310
311
|
end
|
311
312
|
|
312
|
-
def
|
313
|
-
@
|
313
|
+
def handle_mouse_down mouse_x, mouse_y
|
314
|
+
if @data_table.contains_click(mouse_x, mouse_y)
|
315
|
+
val = @data_table.set_selected_row(mouse_y, 0)
|
316
|
+
if not val.nil?
|
317
|
+
node = @graph.find_node(val)
|
318
|
+
@graph_display.set_center_node(node, 2)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
nil
|
314
322
|
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class SampleGraphDisplay < Widget
|
326
|
+
attr_accessor :graph
|
327
|
+
|
328
|
+
def initialize(font, graph)
|
329
|
+
super(10, 100, COLOR_CYAN)
|
330
|
+
set_dimensions(780, 500)
|
331
|
+
set_font(font)
|
332
|
+
@graph = graph
|
333
|
+
exit_button = add_button("Exit", 370, @height - 30) do
|
334
|
+
WidgetResult.new(true)
|
335
|
+
end
|
336
|
+
exit_button.text_color = COLOR_CYAN
|
337
|
+
@graph_display = add_graph_display(5, 60, 770, 400, @graph)
|
338
|
+
@graph_display.set_tree_display
|
339
|
+
end
|
315
340
|
end
|
data/lib/wads/data_structures.rb
CHANGED
@@ -32,21 +32,29 @@ module Wads
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def set(data_set_name, x, y)
|
35
|
-
data_set = @data[
|
35
|
+
data_set = @data[data_set_name]
|
36
36
|
if data_set.nil?
|
37
37
|
data_set = {}
|
38
|
-
@data[
|
38
|
+
@data[data_set_name] = data_set
|
39
39
|
end
|
40
40
|
data_set[x] = y
|
41
41
|
end
|
42
42
|
|
43
43
|
def get(data_set_name, x)
|
44
|
-
data_set = @data[
|
44
|
+
data_set = @data[data_set_name]
|
45
45
|
if data_set.nil?
|
46
46
|
return nil
|
47
47
|
end
|
48
48
|
data_set[x]
|
49
49
|
end
|
50
|
+
|
51
|
+
def keys(data_set_name)
|
52
|
+
data_set = @data[data_set_name]
|
53
|
+
if data_set.nil?
|
54
|
+
return nil
|
55
|
+
end
|
56
|
+
data_set.keys
|
57
|
+
end
|
50
58
|
end
|
51
59
|
|
52
60
|
class Stats
|
@@ -250,6 +258,11 @@ module Wads
|
|
250
258
|
attr_accessor :visited
|
251
259
|
attr_accessor :tags
|
252
260
|
|
261
|
+
def id
|
262
|
+
# id is an alias for name
|
263
|
+
@name
|
264
|
+
end
|
265
|
+
|
253
266
|
def initialize(name, value = nil, tags = {})
|
254
267
|
@name = name
|
255
268
|
@value = value
|
@@ -281,6 +294,35 @@ module Wads
|
|
281
294
|
edge
|
282
295
|
end
|
283
296
|
|
297
|
+
def remove_output(name)
|
298
|
+
output_to_delete = nil
|
299
|
+
@outputs.each do |output|
|
300
|
+
if output.is_a? Edge
|
301
|
+
output_node = output.destination
|
302
|
+
if output_node.id == name
|
303
|
+
output_to_delete = output
|
304
|
+
end
|
305
|
+
elsif output.id == name
|
306
|
+
output_to_delete = output
|
307
|
+
end
|
308
|
+
end
|
309
|
+
if output_to_delete
|
310
|
+
@outputs.delete(output_to_delete)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def remove_backlink(name)
|
315
|
+
backlink_to_delete = nil
|
316
|
+
@backlinks.each do |backlink|
|
317
|
+
if backlink.id == name
|
318
|
+
backlink_to_delete = backlink
|
319
|
+
end
|
320
|
+
end
|
321
|
+
if backlink_to_delete
|
322
|
+
@backlinks.delete(backlink_to_delete)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
284
326
|
def add_tag(key, value)
|
285
327
|
@tags[key] = value
|
286
328
|
end
|
@@ -313,8 +355,8 @@ module Wads
|
|
313
355
|
node = node_queue.shift
|
314
356
|
yield node
|
315
357
|
node.outputs.each do |c|
|
316
|
-
if
|
317
|
-
|
358
|
+
if c.is_a? Edge
|
359
|
+
c = c.destination
|
318
360
|
end
|
319
361
|
node_queue << c
|
320
362
|
end
|
@@ -363,18 +405,49 @@ module Wads
|
|
363
405
|
@node_map = {}
|
364
406
|
end
|
365
407
|
|
408
|
+
def add(name, value = nil, tags = {})
|
409
|
+
add_node(Node.new(name, value, tags))
|
410
|
+
end
|
411
|
+
|
412
|
+
def connect(source, destination, tags = {})
|
413
|
+
add_edge(source, destination)
|
414
|
+
end
|
415
|
+
|
416
|
+
def delete(node)
|
417
|
+
if node.is_a? String
|
418
|
+
node = find_node(node)
|
419
|
+
end
|
420
|
+
node.backlinks.each do |backlink|
|
421
|
+
backlink.remove_output(node.name)
|
422
|
+
end
|
423
|
+
@node_list.delete(node)
|
424
|
+
@node_map.delete(node.name)
|
425
|
+
end
|
426
|
+
|
427
|
+
def disconnect(source, target)
|
428
|
+
if source.is_a? String
|
429
|
+
source = find_node(source)
|
430
|
+
end
|
431
|
+
if target.is_a? String
|
432
|
+
target = find_node(target)
|
433
|
+
end
|
434
|
+
source.remove_output(target.name)
|
435
|
+
target.remove_backlink(source.name)
|
436
|
+
end
|
437
|
+
|
366
438
|
def add_node(node)
|
367
439
|
@node_list << node
|
368
440
|
@node_map[node.name] = node
|
369
441
|
end
|
370
442
|
|
371
|
-
def add_edge(source, target, tags)
|
443
|
+
def add_edge(source, target, tags = {})
|
372
444
|
if source.is_a? String
|
373
445
|
source = find_node(source)
|
374
446
|
end
|
375
447
|
if target.is_a? String
|
376
448
|
target = find_node(target)
|
377
449
|
end
|
450
|
+
source.add_output_edge(target, tags)
|
378
451
|
end
|
379
452
|
|
380
453
|
def find_node(name)
|
@@ -401,6 +474,16 @@ module Wads
|
|
401
474
|
list
|
402
475
|
end
|
403
476
|
|
477
|
+
def leaf_nodes
|
478
|
+
list = []
|
479
|
+
@node_list.each do |node|
|
480
|
+
if node.outputs.empty?
|
481
|
+
list << node
|
482
|
+
end
|
483
|
+
end
|
484
|
+
list
|
485
|
+
end
|
486
|
+
|
404
487
|
def is_cycle(node)
|
405
488
|
reset_visited
|
406
489
|
node.visit do |n|
|
@@ -413,14 +496,21 @@ module Wads
|
|
413
496
|
false
|
414
497
|
end
|
415
498
|
|
416
|
-
def
|
417
|
-
if
|
418
|
-
|
499
|
+
def traverse_and_collect_nodes(node, max_depth, current_depth = 1)
|
500
|
+
if max_depth > 0
|
501
|
+
if current_depth > max_depth
|
502
|
+
return {}
|
503
|
+
end
|
419
504
|
end
|
420
505
|
map = {}
|
421
|
-
|
506
|
+
if node.visited
|
507
|
+
return {}
|
508
|
+
else
|
509
|
+
map[node.name] = node
|
510
|
+
node.visited = true
|
511
|
+
end
|
422
512
|
node.backlinks.each do |child|
|
423
|
-
map_from_child =
|
513
|
+
map_from_child = traverse_and_collect_nodes(child, max_depth, current_depth + 1)
|
424
514
|
map_from_child.each do |key, value|
|
425
515
|
map[key] = value
|
426
516
|
end
|
@@ -429,7 +519,7 @@ module Wads
|
|
429
519
|
if child.is_a? Edge
|
430
520
|
child = child.destination
|
431
521
|
end
|
432
|
-
map_from_child =
|
522
|
+
map_from_child = traverse_and_collect_nodes(child, max_depth, current_depth + 1)
|
433
523
|
map_from_child.each do |key, value|
|
434
524
|
map[key] = value
|
435
525
|
end
|
@@ -437,4 +527,183 @@ module Wads
|
|
437
527
|
map
|
438
528
|
end
|
439
529
|
end
|
530
|
+
|
531
|
+
class GraphReverseIterator
|
532
|
+
attr_accessor :output
|
533
|
+
def initialize(graph)
|
534
|
+
@output = []
|
535
|
+
graph.root_nodes.each do |root|
|
536
|
+
partial_list = process_node(root)
|
537
|
+
@output.push(*partial_list)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def process_node(node)
|
542
|
+
list = []
|
543
|
+
node.outputs.each do |child_node|
|
544
|
+
if child_node.is_a? Edge
|
545
|
+
child_node = child_node.destination
|
546
|
+
end
|
547
|
+
child_list = process_node(child_node)
|
548
|
+
list.push(*child_list)
|
549
|
+
end
|
550
|
+
|
551
|
+
list << node
|
552
|
+
list
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
class VisibleRange
|
557
|
+
attr_accessor :left_x
|
558
|
+
attr_accessor :right_x
|
559
|
+
attr_accessor :bottom_y
|
560
|
+
attr_accessor :top_y
|
561
|
+
attr_accessor :x_range
|
562
|
+
attr_accessor :y_range
|
563
|
+
attr_accessor :is_time_based
|
564
|
+
|
565
|
+
def initialize(l, r, b, t, is_time_based = false)
|
566
|
+
if l < r
|
567
|
+
@left_x = l
|
568
|
+
@right_x = r
|
569
|
+
else
|
570
|
+
@left_x = r
|
571
|
+
@right_x = l
|
572
|
+
end
|
573
|
+
if b < t
|
574
|
+
@bottom_y = b
|
575
|
+
@top_y = t
|
576
|
+
else
|
577
|
+
@bottom_y = t
|
578
|
+
@top_y = b
|
579
|
+
end
|
580
|
+
@x_range = @right_x - @left_x
|
581
|
+
@y_range = @top_y - @bottom_y
|
582
|
+
@is_time_based = is_time_based
|
583
|
+
|
584
|
+
@orig_left_x = @left_x
|
585
|
+
@orig_right_x = @right_x
|
586
|
+
@orig_bottom_y = @bottom_y
|
587
|
+
@orig_top_y = @top_y
|
588
|
+
@orig_range_x = @x_range
|
589
|
+
@orig_range_y = @y_range
|
590
|
+
end
|
591
|
+
|
592
|
+
def plus(other_range)
|
593
|
+
l = @left_x < other_range.left_x ? @left_x : other_range.left_x
|
594
|
+
r = @right_x > other_range.right_x ? @right_x : other_range.right_x
|
595
|
+
b = @bottom_y < other_range.bottom_y ? @bottom_y : other_range.bottom_y
|
596
|
+
t = @top_y > other_range.top_y ? @top_y : other_range.top_y
|
597
|
+
VisibleRange.new(l, r, b, t, (@is_time_based or other_range.is_time_based))
|
598
|
+
end
|
599
|
+
|
600
|
+
def x_ten_percent
|
601
|
+
@x_range.to_f / 10
|
602
|
+
end
|
603
|
+
|
604
|
+
def y_ten_percent
|
605
|
+
@y_range.to_f / 10
|
606
|
+
end
|
607
|
+
|
608
|
+
def scale(zoom_level)
|
609
|
+
x_mid_point = @orig_left_x + (@orig_range_x.to_f / 2)
|
610
|
+
x_extension = (@orig_range_x.to_f * zoom_level) / 2
|
611
|
+
@left_x = x_mid_point - x_extension
|
612
|
+
@right_x = x_mid_point + x_extension
|
613
|
+
|
614
|
+
y_mid_point = @orig_bottom_y + (@orig_range_y.to_f / 2)
|
615
|
+
y_extension = (@orig_range_y.to_f * zoom_level) / 2
|
616
|
+
@bottom_y = y_mid_point - y_extension
|
617
|
+
@top_y = y_mid_point + y_extension
|
618
|
+
|
619
|
+
@x_range = @right_x - @left_x
|
620
|
+
@y_range = @top_y - @bottom_y
|
621
|
+
end
|
622
|
+
|
623
|
+
def scroll_up
|
624
|
+
@bottom_y = @bottom_y + y_ten_percent
|
625
|
+
@top_y = @top_y + y_ten_percent
|
626
|
+
@y_range = @top_y - @bottom_y
|
627
|
+
end
|
628
|
+
|
629
|
+
def scroll_down
|
630
|
+
@bottom_y = @bottom_y - y_ten_percent
|
631
|
+
@top_y = @top_y - y_ten_percent
|
632
|
+
@y_range = @top_y - @bottom_y
|
633
|
+
end
|
634
|
+
|
635
|
+
def scroll_right
|
636
|
+
@left_x = @left_x + x_ten_percent
|
637
|
+
@right_x = @right_x + x_ten_percent
|
638
|
+
@x_range = @right_x - @left_x
|
639
|
+
end
|
640
|
+
|
641
|
+
def scroll_left
|
642
|
+
@left_x = @left_x - x_ten_percent
|
643
|
+
@right_x = @right_x - x_ten_percent
|
644
|
+
@x_range = @right_x - @left_x
|
645
|
+
end
|
646
|
+
|
647
|
+
def grid_line_x_values
|
648
|
+
if @cached_grid_line_x_values
|
649
|
+
return @cached_grid_line_x_values
|
650
|
+
end
|
651
|
+
@cached_grid_line_x_values = divide_range_into_values(@x_range, @left_x, @right_x, false)
|
652
|
+
@cached_grid_line_x_values
|
653
|
+
end
|
654
|
+
|
655
|
+
def grid_line_y_values
|
656
|
+
if @cached_grid_line_y_values
|
657
|
+
return @cached_grid_line_y_values
|
658
|
+
end
|
659
|
+
@cached_grid_line_y_values = divide_range_into_values(@y_range, @bottom_y, @top_y, false)
|
660
|
+
@cached_grid_line_y_values
|
661
|
+
end
|
662
|
+
|
663
|
+
def calc_x_values
|
664
|
+
if @cached_calc_x_values
|
665
|
+
return @cached_calc_x_values
|
666
|
+
end
|
667
|
+
@cached_calc_x_values = divide_range_into_values(@x_range, @left_x, @right_x)
|
668
|
+
#puts "The x_axis value to calculate are: #{@cached_calc_x_values}"
|
669
|
+
@cached_calc_x_values
|
670
|
+
end
|
671
|
+
|
672
|
+
def clear_cache
|
673
|
+
@cached_grid_line_x_values = nil
|
674
|
+
@cached_grid_line_y_values = nil
|
675
|
+
@cached_calc_x_values = nil
|
676
|
+
end
|
677
|
+
|
678
|
+
# This method determines what are equidistant points along
|
679
|
+
# the x-axis that we can use to draw gridlines and calculate
|
680
|
+
# derived values from functions
|
681
|
+
def divide_range_into_values(range_size, start_value, end_value, is_derived_values = true)
|
682
|
+
values = []
|
683
|
+
# How big is x-range? What should the step size be?
|
684
|
+
# Generally we want a hundred display points. Let's start there.
|
685
|
+
if range_size < 1.1
|
686
|
+
step_size = is_derived_values ? 0.01 : 0.1
|
687
|
+
elsif range_size < 11
|
688
|
+
step_size = is_derived_values ? 0.1 : 1
|
689
|
+
elsif range_size < 111
|
690
|
+
step_size = is_derived_values ? 1 : 10
|
691
|
+
elsif range_size < 1111
|
692
|
+
step_size = is_derived_values ? 10 : 100
|
693
|
+
elsif range_size < 11111
|
694
|
+
step_size = is_derived_values ? 100 : 1000
|
695
|
+
elsif range_size < 111111
|
696
|
+
step_size = is_derived_values ? 1000 : 10000
|
697
|
+
else
|
698
|
+
step_size = is_derived_values ? 10000 : 100000
|
699
|
+
end
|
700
|
+
grid_x = start_value
|
701
|
+
while grid_x < end_value
|
702
|
+
values << grid_x
|
703
|
+
grid_x = grid_x + step_size
|
704
|
+
end
|
705
|
+
values
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
440
709
|
end
|