glimmer-libui-cc-graphs_and_charts 0.1.4 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa1f107626b30af5f1158617ad578b5fcd82663700f60f36d581489026c7d5c8
4
- data.tar.gz: 3c38aab6b233810235a2ad87e2ce78a0bc58def745d9a72c1c9a27243b9be140
3
+ metadata.gz: bad5c6db427c320e3b452ee60e2b3af416604525c96e74c915b59c905d746b07
4
+ data.tar.gz: 3659c73cd8a91a9da31c5cf2cb896b04130a7e1a4c58d2f2e92f7b841726de58
5
5
  SHA512:
6
- metadata.gz: 131eddeb423e5b7c2194cddd21c7ce828b63dd6554f05c6377cf4960057bd30a5535ae705477e95d9b72782d7d355090e75ad08acad08f84bfa48ac5eeeafe17
7
- data.tar.gz: bbe9afaafbc760c80f73c59979f9354e9826129310b7122331e566dc24039ce5525b3968239c085ffc369b06a233a63d33ca0aa7f91a8c9f9560fa7f7783d248
6
+ metadata.gz: 9ff88818e482120a5492d7bb2a789afc89d1a40efed3411d355afcc5db7737ef5f5a5e206a3a2737ccdcaf11a8ba01592a398878b1cd005153d1d3ead08d2728
7
+ data.tar.gz: b487f6b49b979d6b3a72a2c174f8cd55c558037e2baf2997b6ddaf0a2b2e9ffa243d62ce48558966115a07bfaccf69802682a7d94b0af4043dad29da5e33e909
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.1.6
4
+
5
+ - Support passing line `values` as a `Hash` map of x-axis values to y-axis values instead of using the combination of `y_values`, `x_value_start`, and `x_interval_in_seconds`
6
+ - Rename `examples/graphs_and_charts/basic_line_graph.rb` to `examples/graphs_and_charts/basic_line_graph_relative.rb`
7
+ - New `examples/graphs_and_charts/basic_line_graph.rb` (replacing older example that got renamed to `basic_line_graph_relative.rb`)
8
+ - Add graph auto-scaling logic to both `examples/graphs_and_charts/basic_line_graph.rb` & `examples/graphs_and_charts/basic_line_graph_relative.rb`
9
+
10
+ ## 0.1.5
11
+
12
+ - Render circles for every point in addition to the lines connecting all the points
13
+ - Render a single point if there is only 1 value in `lines` `y_values` instead of rendering nothing until 2 values exist at least
14
+ - Support `graph_point_radius`, `graph_selected_point_radius`, and `graph_fill_selected_point` options for customizing the circle of every rendered point and selected point.
15
+ - Avoid rendering on top of the grid markers on the left side
16
+ - Optimize performance of rendering grid markers and showing mouse hover selection stats of a point
17
+
3
18
  ## 0.1.4
4
19
 
5
20
  - Fix issue with crashing at `lib/glimmer/view/line_graph.rb:243:in y_value_max_for_all_lines': undefined method max for nil:NilClass`
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Graphs and Charts 0.1.4 (Alpha)
1
+ # Graphs and Charts 0.1.6 (Alpha)
2
2
  ## [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui) Custom Controls
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-libui-cc-graphs_and_charts.svg)](http://badge.fury.io/rb/glimmer-libui-cc-graphs_and_charts)
4
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -12,7 +12,7 @@ Graphs and Charts (Custom Controls) for [Glimmer DSL for LibUI](https://github.c
12
12
  Add this line to Bundler `Gemfile`:
13
13
 
14
14
  ```ruby
15
- gem 'glimmer-libui-cc-graphs_and_charts', '~> 0.1.4'
15
+ gem 'glimmer-libui-cc-graphs_and_charts', '~> 0.1.6'
16
16
  ```
17
17
 
18
18
  Run:
@@ -47,7 +47,7 @@ line_graph(
47
47
  width: 900,
48
48
  height: 300,
49
49
  graph_point_distance: :width_divided_by_point_count,
50
- lines: [
50
+ series: [
51
51
  {
52
52
  name: 'Feature A',
53
53
  stroke: [163, 40, 39, thickness: 2],
@@ -71,6 +71,8 @@ line_graph(
71
71
 
72
72
  ![basic line graph](/screenshots/glimmer-libui-cc-graphs_and_charts-mac-basic-line-graph.png)
73
73
 
74
+ Look into [lib/glimmer/view/line_graph.rb](/lib/glimmer/view/line_graph.rb) to learn about all supported options.
75
+
74
76
  Basic Line Graph Example:
75
77
 
76
78
  [examples/graphs_and_charts/basic_line_graph.rb](/examples/graphs_and_charts/basic_line_graph.rb)
@@ -92,7 +94,7 @@ class BasicLineGraph
92
94
  width: 900,
93
95
  height: 300,
94
96
  graph_point_distance: :width_divided_by_point_count,
95
- lines: [
97
+ series: [
96
98
  {
97
99
  name: 'Feature A',
98
100
  stroke: [163, 40, 39, thickness: 2],
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.6
@@ -7,36 +7,43 @@ require 'glimmer/view/line_graph'
7
7
  class BasicLineGraph
8
8
  include Glimmer::LibUI::Application
9
9
 
10
- before_body do
11
- @start_time = Time.now
12
- end
13
-
14
10
  body {
15
- window('Basic Line Graph', 900, 330) {
16
- line_graph(
11
+ window('Basic Line Graph', 900, 300) { |main_window|
12
+ @line_graph = line_graph(
17
13
  width: 900,
18
14
  height: 300,
19
- graph_point_distance: :width_divided_by_point_count,
20
15
  lines: [
21
16
  {
22
- name: 'Feature A',
17
+ name: 'Stock 1',
23
18
  stroke: [163, 40, 39, thickness: 2],
24
- x_value_start: @start_time,
25
- x_interval_in_seconds: 8,
19
+ values: {
20
+ Time.new(2030, 12, 1) => 80,
21
+ Time.new(2030, 12, 2) => 36,
22
+ Time.new(2030, 12, 4) => 10,
23
+ Time.new(2030, 12, 5) => 60,
24
+ Time.new(2030, 12, 6) => 20,
25
+ },
26
26
  x_value_format: -> (time) {time.strftime("%a %d %b %Y %T GMT")},
27
- y_values: [80, 36, 10, 60, 20, 110, 16, 5, 36, 1, 77, 15, 3, 34, 8, 63, 12, 17, 90, 28, 70]
28
27
  },
29
28
  {
30
- name: 'Feature B',
29
+ name: 'Stock 2',
31
30
  stroke: [47, 109, 104, thickness: 2],
32
- x_value_start: @start_time,
33
- x_interval_in_seconds: 8,
31
+ values: {
32
+ Time.new(2030, 12, 1) => 62,
33
+ Time.new(2030, 12, 2) => 0,
34
+ Time.new(2030, 12, 3) => 90,
35
+ Time.new(2030, 12, 5) => 0,
36
+ Time.new(2030, 12, 7) => 17,
37
+ },
34
38
  x_value_format: -> (time) {time.strftime("%a %d %b %Y %T GMT")},
35
- y_values: [62, 0, 90, 0, 0, 27, 0, 56, 0, 0, 24, 0, 60, 0, 30, 0, 47, 0, 38, 90, 0]
36
39
  },
37
40
  ],
38
- display_attributes_on_hover: true,
39
41
  )
42
+
43
+ on_content_size_changed do
44
+ @line_graph.width = main_window.content_size[0]
45
+ @line_graph.height = main_window.content_size[1]
46
+ end
40
47
  }
41
48
  }
42
49
  end
@@ -0,0 +1,49 @@
1
+ # This line is only needed when running the example from inside the project directory
2
+ $LOAD_PATH.prepend(File.expand_path(File.join(__dir__, '..', '..', 'lib'))) if File.exist?(File.join(__dir__, '..', '..', 'lib'))
3
+
4
+ require 'glimmer-dsl-libui'
5
+ require 'glimmer/view/line_graph'
6
+
7
+ class BasicLineGraph
8
+ include Glimmer::LibUI::Application
9
+
10
+ before_body do
11
+ @start_time = Time.now
12
+ end
13
+
14
+ body {
15
+ window('Basic Line Graph', 900, 330) { |main_window|
16
+ @line_graph = line_graph(
17
+ width: 900,
18
+ height: 300,
19
+ graph_point_distance: :width_divided_by_point_count,
20
+ lines: [
21
+ {
22
+ name: 'Feature A',
23
+ stroke: [163, 40, 39, thickness: 2],
24
+ x_value_start: @start_time,
25
+ x_interval_in_seconds: 8,
26
+ x_value_format: -> (time) {time.strftime("%a %d %b %Y %T GMT")},
27
+ y_values: [80, 36, 10, 60, 20, 110, 16, 5, 36, 1, 77, 15, 3, 34, 8, 63, 12, 17, 90, 28, 70]
28
+ },
29
+ {
30
+ name: 'Feature B',
31
+ stroke: [47, 109, 104, thickness: 2],
32
+ x_value_start: @start_time,
33
+ x_interval_in_seconds: 8,
34
+ x_value_format: -> (time) {time.strftime("%a %d %b %Y %T GMT")},
35
+ y_values: [62, 0, 90, 0, 0, 27, 0, 56, 0, 0, 24, 0, 60, 0, 30, 0, 47, 0, 38, 90, 0]
36
+ },
37
+ ],
38
+ display_attributes_on_hover: true,
39
+ )
40
+
41
+ on_content_size_changed do
42
+ @line_graph.width = main_window.content_size[0]
43
+ @line_graph.height = main_window.content_size[1] - 30
44
+ end
45
+ }
46
+ }
47
+ end
48
+
49
+ BasicLineGraph.launch
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-libui-cc-graphs_and_charts 0.1.4 ruby lib
5
+ # stub: glimmer-libui-cc-graphs_and_charts 0.1.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-libui-cc-graphs_and_charts".freeze
9
- s.version = "0.1.4".freeze
9
+ s.version = "0.1.6".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Andy Maleh".freeze]
14
- s.date = "2023-12-19"
14
+ s.date = "2023-12-22"
15
15
  s.description = "Graphs and Charts (Custom Controls) for Glimmer DSL for LibUI, like Line Graph.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  "README.md",
26
26
  "VERSION",
27
27
  "examples/graphs_and_charts/basic_line_graph.rb",
28
+ "examples/graphs_and_charts/basic_line_graph_relative.rb",
28
29
  "glimmer-libui-cc-graphs_and_charts.gemspec",
29
30
  "lib/glimmer-libui-cc-graphs_and_charts.rb",
30
31
  "lib/glimmer/view/line_graph.rb"
@@ -4,12 +4,21 @@ module Glimmer
4
4
  module View
5
5
  # General-Purpose Line Graph Custom Control
6
6
  class LineGraph
7
+ class << self
8
+ def interpret_color(color_object)
9
+ @color_cache ||= {}
10
+ @color_cache[color_object] ||= Glimmer::LibUI.interpret_color(color_object)
11
+ end
12
+ end
13
+
7
14
  include Glimmer::LibUI::CustomControl
8
15
 
9
16
  DEFAULT_GRAPH_PADDING_WIDTH = 5.0
10
17
  DEFAULT_GRAPH_PADDING_HEIGHT = 5.0
11
- DEFAULT_GRAPH_GRID_MARKER_PADDING_WIDTH = 30.0
18
+ DEFAULT_GRAPH_GRID_MARKER_PADDING_WIDTH = 37.0
12
19
  DEFAULT_GRAPH_POINT_DISTANCE = 15.0
20
+ DEFAULT_GRAPH_POINT_RADIUS = 1.0
21
+ DEFAULT_GRAPH_SELECTED_POINT_RADIUS = 3.0
13
22
 
14
23
  DEFAULT_GRAPH_STROKE_GRID = [185, 184, 185]
15
24
  DEFAULT_GRAPH_STROKE_MARKER = [185, 184, 185]
@@ -17,6 +26,8 @@ module Glimmer
17
26
  DEFAULT_GRAPH_STROKE_PERIODIC_LINE = [121, 121, 121, thickness: 1, dashes: [1, 1]]
18
27
  DEFAULT_GRAPH_STROKE_HOVER_LINE = [133, 133, 133]
19
28
 
29
+ DEFAULT_GRAPH_FILL_SELECTED_POINT = :white
30
+
20
31
  DEFAULT_GRAPH_COLOR_MARKER_TEXT = [96, 96, 96]
21
32
  DEFAULT_GRAPH_COLOR_PERIOD_TEXT = [163, 40, 39]
22
33
 
@@ -44,6 +55,8 @@ module Glimmer
44
55
  option :graph_padding_height, default: DEFAULT_GRAPH_PADDING_HEIGHT
45
56
  option :graph_grid_marker_padding_width, default: DEFAULT_GRAPH_GRID_MARKER_PADDING_WIDTH
46
57
  option :graph_point_distance, default: DEFAULT_GRAPH_POINT_DISTANCE
58
+ option :graph_point_radius, default: DEFAULT_GRAPH_POINT_RADIUS
59
+ option :graph_selected_point_radius, default: DEFAULT_GRAPH_SELECTED_POINT_RADIUS
47
60
 
48
61
  option :graph_stroke_grid, default: DEFAULT_GRAPH_STROKE_GRID
49
62
  option :graph_stroke_marker, default: DEFAULT_GRAPH_STROKE_MARKER
@@ -51,6 +64,8 @@ module Glimmer
51
64
  option :graph_stroke_periodic_line, default: DEFAULT_GRAPH_STROKE_PERIODIC_LINE
52
65
  option :graph_stroke_hover_line, default: DEFAULT_GRAPH_STROKE_HOVER_LINE
53
66
 
67
+ option :graph_fill_selected_point, default: DEFAULT_GRAPH_FILL_SELECTED_POINT
68
+
54
69
  option :graph_color_marker_text, default: DEFAULT_GRAPH_COLOR_MARKER_TEXT
55
70
  option :graph_color_period_text, default: DEFAULT_GRAPH_COLOR_PERIOD_TEXT
56
71
 
@@ -93,7 +108,7 @@ module Glimmer
93
108
 
94
109
  if @hover_point && lines && lines[0] && @points && @points[lines[0]] && !@points[lines[0]].empty?
95
110
  x = @hover_point[:x]
96
- closest_point_index = @points[lines[0]].each_with_index.min_by { |point, index| (point[:x] - x).abs }[1]
111
+ closest_point_index = ((width - graph_padding_width - x) / graph_point_distance_for_line(lines[0])).round
97
112
  if closest_point_index != @closest_point_index
98
113
  @closest_point_index = closest_point_index
99
114
  graph_area.queue_redraw_all
@@ -116,8 +131,17 @@ module Glimmer
116
131
  def clear_drawing_cache
117
132
  @graph_point_distance_per_line = nil
118
133
  @y_value_max_for_all_lines = nil
134
+ @x_resolution = nil
135
+ @x_value_range_for_all_lines = nil
136
+ @x_value_min_for_all_lines = nil
137
+ @x_value_max_for_all_lines = nil
119
138
  @grid_marker_points = nil
120
139
  @points = nil
140
+ @grid_marker_number_values = nil
141
+ @grid_marker_numbers = nil
142
+ @graph_stroke_marker_values = nil
143
+ @mod_values = nil
144
+ @estimated_widths_of_text = nil
121
145
  end
122
146
 
123
147
  def calculate_dynamic_options
@@ -125,13 +149,19 @@ module Glimmer
125
149
  end
126
150
 
127
151
  def calculate_graph_point_distance_per_line
128
- return unless graph_point_distance == :width_divided_by_point_count
152
+ return unless lines[0]&.[](:y_values) && graph_point_distance == :width_divided_by_point_count
129
153
 
130
- @graph_point_distance_per_line = lines.inject({}) do |hash, line|
131
- hash.merge(line => (width - 2.0*graph_padding_width - graph_grid_marker_padding_width) / (line[:y_values].size - 1).to_f)
154
+ @graph_point_distance_per_line ||= lines.inject({}) do |hash, line|
155
+ value = (width - 2.0*graph_padding_width - graph_grid_marker_padding_width) / (line[:y_values].size - 1).to_f
156
+ value = [value, drawable_width].min
157
+ hash.merge(line => value)
132
158
  end
133
159
  end
134
160
 
161
+ def drawable_width
162
+ width - 2.0*graph_padding_width - graph_grid_marker_padding_width
163
+ end
164
+
135
165
  def graph_point_distance_for_line(line)
136
166
  @graph_point_distance_per_line&.[](line) || graph_point_distance
137
167
  end
@@ -149,12 +179,25 @@ module Glimmer
149
179
  line(graph_padding_width, height - graph_padding_height, width - graph_padding_width, height - graph_padding_height) {
150
180
  stroke graph_stroke_grid
151
181
  }
182
+ grid_marker_number_font = graph_font_marker_text.merge(size: 11)
183
+ @grid_marker_number_values ||= []
184
+ @grid_marker_numbers ||= []
185
+ @graph_stroke_marker_values ||= []
186
+ @mod_values ||= []
152
187
  grid_marker_points.each_with_index do |marker_point, index|
153
- grid_marker_number_value = (grid_marker_points.size - index).to_i
154
- grid_marker_number = (grid_marker_number_value >= 1000) ? "#{grid_marker_number_value / 1000}K" : grid_marker_number_value.to_s
155
- graph_stroke_marker_value = Glimmer::LibUI.interpret_color(graph_stroke_marker)
156
- graph_stroke_marker_value[:thickness] = (index != grid_marker_points.size - 1 ? 2 : 1) if graph_stroke_marker_value[:thickness].nil?
157
- mod_value = (2 * ((grid_marker_points.size / max_marker_count) + 1))
188
+ @grid_marker_number_values[index] ||= (grid_marker_points.size - index).to_i
189
+ grid_marker_number_value = @grid_marker_number_values[index]
190
+ @grid_marker_numbers[index] ||= (grid_marker_number_value >= 1000) ? "#{grid_marker_number_value / 1000}K" : grid_marker_number_value.to_s
191
+ grid_marker_number = @grid_marker_numbers[index]
192
+ @graph_stroke_marker_values[index] ||= LineGraph.interpret_color(graph_stroke_marker).tap do |color_hash|
193
+ color_hash[:thickness] = (index != grid_marker_points.size - 1 ? 2 : 1) if color_hash[:thickness].nil?
194
+ end
195
+ graph_stroke_marker_value = @graph_stroke_marker_values[index]
196
+ @mod_values[index] ||= begin
197
+ mod_value_multiplier = ((grid_marker_points.size / max_marker_count) + 1)
198
+ [((mod_value_multiplier <= 2 ? 2 : 5) * mod_value_multiplier), 1].max
199
+ end
200
+ mod_value = @mod_values[index]
158
201
  comparison_value = (mod_value > 2) ? 0 : 1
159
202
  if mod_value > 2
160
203
  if grid_marker_number_value % mod_value == comparison_value
@@ -173,7 +216,6 @@ module Glimmer
173
216
  }
174
217
  end
175
218
  if grid_marker_number_value % mod_value == comparison_value
176
- grid_marker_number_font = graph_font_marker_text.merge(size: 11)
177
219
  grid_marker_number_width = estimate_width_of_text(grid_marker_number, grid_marker_number_font)
178
220
  text(marker_point[:x] + 4 + 3, marker_point[:y] - 6, grid_marker_number_width) {
179
221
  string(grid_marker_number) {
@@ -210,17 +252,30 @@ module Glimmer
210
252
  def single_line_graph(graph_line)
211
253
  last_point = nil
212
254
  points = calculate_points(graph_line)
213
- points.each do |point|
255
+ points.to_a.each do |point|
214
256
  if last_point
215
257
  line(last_point[:x], last_point[:y], point[:x], point[:y]) {
216
258
  stroke graph_line[:stroke]
217
259
  }
218
260
  end
261
+ if last_point.nil? || graph_point_radius > 1
262
+ circle(point[:x], point[:y], graph_point_radius) {
263
+ fill graph_line[:stroke]
264
+ }
265
+ end
219
266
  last_point = point
220
267
  end
221
268
  end
222
269
 
223
270
  def calculate_points(graph_line)
271
+ if lines[0]&.[](:y_values)
272
+ calculate_points_relative(graph_line)
273
+ else
274
+ calculate_points_absolute(graph_line)
275
+ end
276
+ end
277
+
278
+ def calculate_points_relative(graph_line)
224
279
  @points ||= {}
225
280
  if @points[graph_line].nil?
226
281
  y_values = graph_line[:y_values] || []
@@ -236,9 +291,67 @@ module Glimmer
236
291
  @points[graph_line]
237
292
  end
238
293
 
294
+ def calculate_points_absolute(graph_line)
295
+ @points ||= {}
296
+ if @points[graph_line].nil?
297
+ values = graph_line[:values] || []
298
+ # all points are visible when :values is supplied because we stretch the graph to show them all
299
+ graph_y_max = [y_value_max_for_all_lines, 1].max
300
+ x_value_range_for_all_lines
301
+ points = values.each_with_index.map do |(x_value, y_value), index|
302
+ relative_x_value = x_value - x_value_min_for_all_lines
303
+ stretched_x_value = x_value_range_for_all_lines == 0 ? 0 : relative_x_value.to_f * x_resolution.to_f
304
+ x = width - graph_padding_width - stretched_x_value
305
+ y = ((height - graph_padding_height) - y_value * ((height - graph_padding_height * 2) / graph_y_max))
306
+ {x: x, y: y, index: index, x_value: x_value, y_value: y_value}
307
+ end
308
+ # Translation is not supported today
309
+ # TODO consider supporting in the future
310
+ # @points[graph_line] = translate_points(graph_line, points)
311
+ @points[graph_line] = points
312
+ end
313
+ @points[graph_line]
314
+ end
315
+
316
+ # this is the multiplier that we must multiply by the relative_x_value
317
+ def x_resolution
318
+ @x_resolution ||= drawable_width.to_f / x_value_range_for_all_lines.to_f
319
+ end
320
+
321
+ def x_value_range_for_all_lines
322
+ @x_value_range_for_all_lines ||= x_value_max_for_all_lines - x_value_min_for_all_lines
323
+ end
324
+
325
+ def x_value_min_for_all_lines
326
+ if @x_value_min_for_all_lines.nil?
327
+ line_visible_x_values = lines.map { |line| line[:values].to_h.keys }
328
+ all_visible_x_values = line_visible_x_values.reduce(:+) || []
329
+ # Right now, we assume Time objects
330
+ # TODO support String representations of Time (w/ some auto-detection of format)
331
+ @x_value_min_for_all_lines = all_visible_x_values.min
332
+ end
333
+ @x_value_min_for_all_lines
334
+ end
335
+
336
+ def x_value_max_for_all_lines
337
+ if @x_value_max_for_all_lines.nil?
338
+ line_visible_x_values = lines.map { |line| line[:values].to_h.keys }
339
+ all_visible_x_values = line_visible_x_values.reduce(:+) || []
340
+ # Right now, we assume Time objects
341
+ # TODO support String representations of Time (w/ some auto-detection of format)
342
+ @x_value_max_for_all_lines = all_visible_x_values.max
343
+ end
344
+ @x_value_max_for_all_lines
345
+ end
346
+
239
347
  def y_value_max_for_all_lines
240
348
  if @y_value_max_for_all_lines.nil?
241
- line_visible_y_values = lines.map { |line| line[:y_values][0, max_visible_point_count(line)] }
349
+ if lines[0]&.[](:y_values)
350
+ line_visible_y_values = lines.map { |line| line[:y_values][0, max_visible_point_count(line)] }
351
+ else
352
+ # When using :values , we always stretch the graph so that all points are visible
353
+ line_visible_y_values = lines.map { |line| line[:values].to_h.values }
354
+ end
242
355
  all_visible_y_values = line_visible_y_values.reduce(:+) || []
243
356
  @y_value_max_for_all_lines = all_visible_y_values.max.to_f
244
357
  end
@@ -257,14 +370,16 @@ module Glimmer
257
370
  points
258
371
  end
259
372
 
260
- def max_visible_point_count(graph_line) = (width / graph_point_distance_for_line(graph_line)).to_i + 1
373
+ def max_visible_point_count(graph_line) = ((width - graph_grid_marker_padding_width) / graph_point_distance_for_line(graph_line)).to_i + 1
261
374
 
262
375
  def periodic_lines
263
376
  return unless lines && lines[0] && lines[0][:x_interval_in_seconds] && lines[0][:x_interval_in_seconds] == DAY_IN_SECONDS
264
377
  day_count = lines[0][:y_values].size
265
378
  case day_count
266
379
  when ..7
267
- @points[lines[0]].each do |point|
380
+ @points[lines[0]].each_with_index do |point, index|
381
+ next if index == 0
382
+
268
383
  line(point[:x], graph_padding_height, point[:x], height - graph_padding_height) {
269
384
  stroke graph_stroke_periodic_line
270
385
  }
@@ -323,68 +438,64 @@ module Glimmer
323
438
  x = @hover_point[:x]
324
439
  closest_points = lines.map { |line| @points[line][@closest_point_index] }
325
440
  closest_x = closest_points[0]&.[](:x)
326
- closest_x_distance = PerfectShape::Point.point_distance(x.to_f, 0, closest_x.to_f, 0)
327
- # Today, we make the assumption that all lines have points along the same x-axis values
328
- # TODO In the future, we can support different x values along different lines
329
- if closest_x_distance < graph_point_distance_for_line(lines[0])
330
- line(closest_x, graph_padding_height, closest_x, height - graph_padding_height) {
331
- stroke graph_stroke_hover_line
441
+ line(closest_x, graph_padding_height, closest_x, height - graph_padding_height) {
442
+ stroke graph_stroke_hover_line
443
+ }
444
+ closest_points.each_with_index do |closest_point, index|
445
+ next unless closest_point && closest_point[:x] && closest_point[:y]
446
+
447
+ circle(closest_point[:x], closest_point[:y], graph_selected_point_radius) {
448
+ fill graph_fill_selected_point == :line_stroke ? lines[index][:stroke] : graph_fill_selected_point
449
+ stroke_value = lines[index][:stroke].dup
450
+ stroke_value << {} unless stroke_value.last.is_a?(Hash)
451
+ stroke_value.last[:thickness] = 2
452
+ stroke stroke_value
332
453
  }
333
- closest_points.each_with_index do |closest_point, index|
334
- next unless closest_point && closest_point[:x] && closest_point[:y]
335
-
336
- circle(closest_point[:x], closest_point[:y], 4) {
337
- fill lines[index][:stroke]
338
- }
339
- circle(closest_point[:x], closest_point[:y], 2) {
340
- fill :white
341
- }
342
- end
343
- text_label = formatted_x_value(@closest_point_index)
344
- text_label_width = estimate_width_of_text(text_label, DEFAULT_GRAPH_FONT_MARKER_TEXT)
345
- lines_with_closest_points = lines.each_with_index.map do |line, index|
346
- next if closest_points[index].nil?
347
-
348
- line
349
- end
350
- closest_point_texts = lines_with_closest_points.map { |line| "#{line[:name]}: #{line[:y_values][@closest_point_index]}" }
351
- closest_point_text_widths = closest_point_texts.map do |text|
352
- estimate_width_of_text(text, graph_font_marker_text)
353
- end
354
- square_size = 12.0
355
- square_to_label_padding = 10.0
356
- label_padding = 10.0
357
- text_label_x = width - graph_padding_width - text_label_width - label_padding -
358
- (lines_with_closest_points.size*(square_size + square_to_label_padding) + (lines_with_closest_points.size - 1)*label_padding + closest_point_text_widths.sum)
359
- text_label_y = height + graph_padding_height
454
+ end
455
+ text_label = formatted_x_value(@closest_point_index)
456
+ text_label_width = estimate_width_of_text(text_label, DEFAULT_GRAPH_FONT_MARKER_TEXT)
457
+ lines_with_closest_points = lines.each_with_index.map do |line, index|
458
+ next if closest_points[index].nil?
459
+
460
+ line
461
+ end.compact
462
+ closest_point_texts = lines_with_closest_points.map { |line| "#{line[:name]}: #{line[:y_values][@closest_point_index]}" }
463
+ closest_point_text_widths = closest_point_texts.map do |text|
464
+ estimate_width_of_text(text, graph_font_marker_text)
465
+ end
466
+ square_size = 12.0
467
+ square_to_label_padding = 10.0
468
+ label_padding = 10.0
469
+ text_label_x = width - graph_padding_width - text_label_width - label_padding -
470
+ (lines_with_closest_points.size*(square_size + square_to_label_padding) + (lines_with_closest_points.size - 1)*label_padding + closest_point_text_widths.sum)
471
+ text_label_y = height + graph_padding_height
360
472
 
361
- text(text_label_x, text_label_y, text_label_width) {
362
- string(text_label) {
363
- font DEFAULT_GRAPH_FONT_MARKER_TEXT
364
- color graph_color_marker_text
365
- }
473
+ text(text_label_x, text_label_y, text_label_width) {
474
+ string(text_label) {
475
+ font DEFAULT_GRAPH_FONT_MARKER_TEXT
476
+ color graph_color_marker_text
366
477
  }
478
+ }
367
479
 
368
- relative_x = text_label_x + text_label_width
369
- lines_with_closest_points.size.times do |index|
370
- square_x = relative_x + label_padding
480
+ relative_x = text_label_x + text_label_width
481
+ lines_with_closest_points.size.times do |index|
482
+ square_x = relative_x + label_padding
371
483
 
372
- square(square_x, text_label_y + 2, square_size) {
373
- fill lines_with_closest_points[index][:stroke]
374
- }
484
+ square(square_x, text_label_y + 2, square_size) {
485
+ fill lines_with_closest_points[index][:stroke]
486
+ }
375
487
 
376
- attribute_label_x = square_x + square_size + square_to_label_padding
377
- attribute_text = closest_point_texts[index]
378
- attribute_text_width = closest_point_text_widths[index]
379
- relative_x = attribute_label_x + attribute_text_width
488
+ attribute_label_x = square_x + square_size + square_to_label_padding
489
+ attribute_text = closest_point_texts[index]
490
+ attribute_text_width = closest_point_text_widths[index]
491
+ relative_x = attribute_label_x + attribute_text_width
380
492
 
381
- text(attribute_label_x, text_label_y, attribute_text_width) {
382
- string(attribute_text) {
383
- font graph_font_marker_text
384
- color graph_color_marker_text
385
- }
493
+ text(attribute_label_x, text_label_y, attribute_text_width) {
494
+ string(attribute_text) {
495
+ font graph_font_marker_text
496
+ color graph_color_marker_text
386
497
  }
387
- end
498
+ }
388
499
  end
389
500
  end
390
501
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-libui-cc-graphs_and_charts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-19 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer-dsl-libui
@@ -81,6 +81,7 @@ files:
81
81
  - README.md
82
82
  - VERSION
83
83
  - examples/graphs_and_charts/basic_line_graph.rb
84
+ - examples/graphs_and_charts/basic_line_graph_relative.rb
84
85
  - glimmer-libui-cc-graphs_and_charts.gemspec
85
86
  - lib/glimmer-libui-cc-graphs_and_charts.rb
86
87
  - lib/glimmer/view/line_graph.rb