minichart 0.2.2 → 0.3.0

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: 7debe086fa2ba7994f1362fa53ab2d5da5cc61a0010f6f08d6ca125cc447bc27
4
- data.tar.gz: 77dd9cf342830795872c284befe937cba7caa9c2372bdae2b8a42a44e6d4bb13
3
+ metadata.gz: 6109cfc57cb909c2ba0a9df4e184bc4319220399b774ff2098b728bf4a41f57e
4
+ data.tar.gz: 32cd8ff3c3260d08f81106c3ac74037e36990d4601eb8ff7e40c8840d44b3ca3
5
5
  SHA512:
6
- metadata.gz: 5a331fa46640d9bfb32759a5aa160680cd684bd7f57f194e212f7b0d0f5c2af61f03f8b526702de0421dbe608fbc70c39df8c219967b8c2de9fe647f04822e42
7
- data.tar.gz: 2fede85eef059f2ac6980ff9ba6249b1e7b716edb38eacfe514cebace11488e0cb1ca4520ff4d7a3bf58934e746e846130026c9c98f7bc41419c4216a68c8734
6
+ metadata.gz: 63e01d19bd4539ccf1283a98bee8f941a7e270ee0f1a2956aed20ecbab21661e7923420588c28f0aa90027cfc6fadc88f5f90b5776ff8dfa3523c9faf85c03ba
7
+ data.tar.gz: 1861ffff3d852e85fbf9b8c334d091f6dd40ce823086ae4215edb95c96f20a5f9e79e4da5caaf51b35956a8da92ca9de054ee35aae67c84884c02ad5f59af628
data/README.md CHANGED
@@ -6,6 +6,26 @@ Create SVG mini charts with Ruby
6
6
 
7
7
  ![demo](examples/multiple.svg)
8
8
 
9
+ ---
10
+
11
+ * [Install](#install)
12
+ * [Usage](#usage)
13
+ * [Chart Types](#chart-types)
14
+ * [Line Chart](#line-chart)
15
+ * [Bar Chart](#bar-chart)
16
+ * [Area Chart](#area-chart)
17
+ * [Horizontal Bar Meter](#horizontal-bar-meter)
18
+ * [Vertical Bar Meter](#vertical-bar-meter)
19
+ * [Configuration](#configuration)
20
+ * [Class-level default options](#class-level-default-options)
21
+ * [Instance initialization options](#instance-initialization-options)
22
+ * [Instance-level options](#instance-level-options)
23
+ * [Options Reference](#options-reference)
24
+ * [Basic Options](#basic-options)
25
+ * [Meter Options](#meter-options)
26
+ * [Examples](#examples)
27
+
28
+
9
29
  ---
10
30
 
11
31
  ## Install
@@ -126,49 +146,124 @@ dual = VerticalBarMeter.new 80,
126
146
  Meter charts support [additional options](#meter-options).
127
147
 
128
148
 
129
- ## Options
149
+ ## Configuration
130
150
 
131
- ### Basic Options
151
+ Chart options can be set in one of three ways.
152
+
153
+ ### Class-level default options
154
+
155
+ See or set default options for any chart class by calling its `::options` method:
156
+
157
+ ```ruby
158
+ # See all options
159
+ p AreaChart.options
160
+ #=> {:background=>"white", :height=>100, :width=>300, :stroke=>2, :style=>{}, :color=>"#66f"}
161
+
162
+ # Set a single default option
163
+ AreaChart.options[:color] = '#333'
164
+
165
+ # Set multiple options at once
166
+ AreaChart.options background: 'black', color: 'green'
167
+ ```
168
+
169
+ ### Instance initialization options
132
170
 
133
- All chart classes support a second hash argument for options
171
+ Set options by providing a hash as the second argument on initialization:
134
172
 
135
173
  ```ruby
136
- chart = LineChart.new data, options
174
+ chart = AreaChart.new data, height: 120, width: 500
137
175
  ```
138
176
 
139
- | Option | Default | Description |
140
- | -------------- | ----------------------------- | ------------------------------------------------------------ |
141
- | `background` | `"white"` | Chart background color |
142
- | `color` | `"#333"` | Chart color |
143
- | `aspect_ratio` | `3` | Set automatic width |
144
- | `height` | `100`<sup>*</sup> | Chart height in pixels |
145
- | `width` | Calculated by `aspect_ratio`<sup>*</sup> | Chart width in pixels |
146
- | `stroke` | `2` | Line stroke width.<br />In `BarChart` determines the gap between bars |
147
- | `style` | *None* | Style hash for the SVG |
177
+ ### Instance-level options
178
+
179
+ After initialization, you can still update individual options:
180
+
181
+ ```ruby
182
+ chart = AreaChart.new data
183
+ chart.options[:background] = 'yellow'
184
+ ```
185
+
186
+ ## Options Reference
187
+
188
+ ### Basic Options
189
+
190
+ #### background
191
+
192
+ Chart background color.
193
+
194
+ #### color
195
+
196
+ Chart color.
197
+
198
+ #### height
199
+
200
+ Chart height in pixels.
201
+
202
+ #### width
203
+
204
+ Chart width in pixels.
205
+
206
+ #### stroke
207
+
208
+ Line stroke width. This has a different effect in different chart types.
209
+
210
+ #### style
211
+
212
+ CSS Style hash to apply to the entire SVG.
148
213
 
149
- _* Default dimensions are reversed for horizontal meters - `width` defaults to 100, and `height` is calculated automatically._
150
214
 
151
215
  ### Meter Options
152
216
 
153
217
  Meter charts support these options in additon to the basic options:
154
218
 
155
- | Option | Default | Description |
156
- | -------------------------- | --------- | ------------------------------------------------------------ |
157
- | `mode` | `:auto` | Display mode.<br />Can be `:positive`, `:negative`, `:auto` or `:dual` |
158
- | `max` | `100` | The absolute maximum value.<br />This number should be positive even for negative charts |
159
- | `zero_line` | `false` | If true, mark the zero line |
160
- | `zero_line_size` | `6` | Size of the zero line |
161
- | `zero_line_color` | `"black"` | Color of the zero line |
162
- | `clipping_indicator` | `false` | If true, show when the value exceeds the range |
163
- | `clipping_indicator_size` | `6` | Size of the clipping indicator |
164
- | `clipping_indicator_color` | `"yelow"` | Color of the clipping indicator |
219
+ #### mode
220
+
221
+ Display mode. Can be `:positive`, `:negative`, `:dual` or `:auto` (default).
222
+
223
+ The `:auto` mode will switch between `:positive` and `:negative` based on the
224
+ value.
225
+
226
+ #### max
227
+
228
+ The absolute maximum value. This number should be positive even for negative
229
+ charts.
230
+
231
+ #### notches
232
+
233
+ An array of one or more levels to place a notch marker. Use positive values
234
+ only.
235
+
236
+ #### notch_thickness
237
+
238
+ Thickness of the notch markers.
239
+
240
+ #### notch_color
241
+
242
+ Color of the notch markers.
243
+
244
+ #### clipping_indicator
245
+
246
+ If true, show a marker when the value exceeds the range.
247
+
248
+ #### clipping_indicator_thickness
249
+
250
+ Thickness of the clipping indicator.
251
+
252
+ #### clipping_indicator_color
253
+
254
+ Color of the clipping indicator.
165
255
 
166
256
  ## Examples
167
257
 
168
258
  See more examples (code and SVG output) in the [examples folder][1].
169
259
 
170
- ---
260
+ ## Contributing / Support
261
+
262
+ If you experience any issue, have a question or a suggestion, or if you wish
263
+ to contribute, feel free to [open an issue][issues].
171
264
 
265
+ ---
172
266
 
173
267
  [1]: https://github.com/DannyBen/minichart/tree/master/examples#examples
174
- [2]: https://github.com/DannyBen/victor
268
+ [2]: https://github.com/DannyBen/victor
269
+ [issues]: https://github.com/DannyBen/minichart/issues
@@ -1,16 +1,40 @@
1
1
  module Minichart
2
2
  # Base class for all Minichart classes
3
3
  class Base < Victor::SVGBase
4
- attr_reader :aspect_ratio, :background, :color, :data,
5
- :height, :stroke, :style, :width, :opts
4
+ attr_reader :data, :options
5
+
6
+ class << self
7
+ def master_defaults
8
+ {
9
+ background: 'white',
10
+ height: 100,
11
+ width: 300,
12
+ stroke: 2,
13
+ style: {},
14
+ color: '#66f'
15
+ }
16
+ end
17
+
18
+ # For subclasses to define
19
+ def defaults
20
+ {}
21
+ end
22
+
23
+ def options(update_hash = nil)
24
+ @options ||= master_defaults.merge defaults
25
+ @options.merge! update_hash if update_hash
26
+ @options
27
+ end
28
+ end
6
29
 
7
- def initialize(data, opts = {})
8
- @data, @opts = data, opts
9
-
10
- # super height: height, width: width, style: style, viewBox: viewbox
11
- super viewBox: viewbox, style: style
12
- element :rect, x: 0, y: 0, width: width, height: height,
13
- fill: background, stroke_width: 0
30
+ def initialize(data, user_options = {})
31
+ @data = data
32
+ @options = self.class.options.merge user_options
33
+
34
+ super viewBox: viewbox, style: options[:style]
35
+ element :rect, x: 0, y: 0,
36
+ width: options[:width], height: options[:height],
37
+ fill: options[:background], stroke_width: 0
14
38
 
15
39
  clip_path_id = IDGenerator.next
16
40
  setup_clip_path clip_path_id
@@ -23,41 +47,13 @@ module Minichart
23
47
  def setup_clip_path(id)
24
48
  element :defs do
25
49
  element :clipPath, id: id do
26
- element :rect, width: width, height: height
50
+ element :rect, width: options[:width], height: options[:height]
27
51
  end
28
52
  end
29
53
  end
30
54
 
31
- def background
32
- opts[:background] ||= 'white'
33
- end
34
-
35
- def aspect_ratio
36
- opts[:aspect_ratio] ||= 3
37
- end
38
-
39
- def height
40
- opts[:height] ||= 100
41
- end
42
-
43
- def width
44
- opts[:width] ||= (aspect_ratio * height).round
45
- end
46
-
47
- def stroke
48
- opts[:stroke] ||= 2
49
- end
50
-
51
- def style
52
- opts[:style] ||= {}
53
- end
54
-
55
- def color
56
- opts[:color] ||= '#333'
57
- end
58
-
59
55
  def viewbox
60
- "0 0 #{width} #{height}"
56
+ "0 0 #{options[:width]} #{options[:height]}"
61
57
  end
62
58
 
63
59
  def build
@@ -1,9 +1,9 @@
1
1
  module Minichart
2
2
  class AreaChart < Chart
3
3
  def build
4
- element :polyline, fill: color,
5
- stroke: color,
6
- stroke_width: stroke,
4
+ element :polyline, fill: options[:color],
5
+ stroke: options[:color],
6
+ stroke_width: options[:stroke],
7
7
  stroke_linejoin: :round,
8
8
  points: points
9
9
  end
@@ -11,15 +11,15 @@ module Minichart
11
11
  protected
12
12
 
13
13
  def points
14
- result = ["0,#{height}"]
14
+ result = ["0,#{options[:height]}"]
15
15
 
16
16
  inverted_points.each do |point|
17
- x = width*point[0]
18
- y = height*point[1]
17
+ x = options[:width] *point[0]
18
+ y = options[:height] * point[1]
19
19
  result << "#{x},#{y}"
20
20
  end
21
21
 
22
- result << "#{width},#{height}"
22
+ result << "#{options[:width]},#{options[:height]}"
23
23
 
24
24
  result
25
25
  end
@@ -11,18 +11,22 @@ module Minichart
11
11
  protected
12
12
 
13
13
  def bar_width
14
- @bar_width ||= width / data.size
14
+ @bar_width ||= options[:width] / data.size
15
15
  end
16
16
 
17
17
  def bar_options(x, y)
18
- y = y*height
19
- bar_height = height-y
18
+ y = y * options[:height]
19
+ bar_height = options[:height] - y
20
20
  {
21
- x: x*width,
21
+ x: x * options[:width],
22
22
  y: y,
23
- width: bar_width,
24
- height: bar_height,
25
- style: { fill: color, stroke_width: stroke, stroke: background }
23
+ width: bar_width,
24
+ height: bar_height,
25
+ style: {
26
+ fill: options[:color],
27
+ stroke_width: options[:stroke],
28
+ stroke: options[:background]
29
+ }
26
30
  }
27
31
  end
28
32
  end
@@ -2,8 +2,8 @@ module Minichart
2
2
  class LineChart < Chart
3
3
  def build
4
4
  element :polyline, fill: :none,
5
- stroke: color,
6
- stroke_width: stroke,
5
+ stroke: options[:color],
6
+ stroke_width: options[:stroke],
7
7
  stroke_linejoin: :round,
8
8
  points: points
9
9
  end
@@ -13,8 +13,8 @@ module Minichart
13
13
  def points
14
14
  result = []
15
15
  inverted_points.each do |point|
16
- x = width*point[0]
17
- y = height*point[1]
16
+ x = options[:width] * point[0]
17
+ y = options[:height] * point[1]
18
18
  result << "#{x},#{y}"
19
19
  end
20
20
  result
@@ -1,56 +1,59 @@
1
1
  module Minichart
2
2
  class HorizontalBarMeter < Meter
3
+ class << self
4
+ def defaults
5
+ meter_defaults.merge width: 300, height: 50
6
+ end
7
+ end
8
+
3
9
  def build
4
10
  draw_bar
5
- draw_zero_line if zero_line
6
- draw_clipping_indicator if clipping_indicator and clipping?
11
+ draw_notches if options[:notches]
12
+ draw_clipping_indicator if options[:clipping_indicator] and clipping?
7
13
  end
8
14
 
9
15
  protected
10
16
 
11
17
  def draw_bar
12
- x = if mode == :negative
13
- width - bar_width
14
- elsif mode == :dual
15
- middle = width * 0.5
16
- value >= 0 ? middle : middle - bar_width
17
- else
18
- 0
19
- end
18
+ x1 = x_for 0
19
+ x2 = x_for clamped_value
20
+ x = [x1, x2].min
20
21
 
21
- element :rect, x: x, y: 0, height: height, width: bar_width, style: style
22
+ element :rect, x: x, y: 0, height: options[:height],
23
+ width: bar_width, style: style
22
24
  end
23
25
 
24
- def draw_clipping_indicator
25
- x = if mode == :positive or (mode == :dual and value > 0)
26
- width - clipping_indicator_size
27
- else
28
- 0
26
+ def draw_notches
27
+ options[:notches].each do |notch|
28
+ draw_notch notch
29
+ draw_notch -notch if mode == :dual and notch != 0
29
30
  end
31
+ end
30
32
 
31
- element :rect, x: x, y: 0,
32
- height: height, width: clipping_indicator_size,
33
- fill: clipping_indicator_color, stroke_width: 0
34
-
33
+ def draw_notch(notch)
34
+ draw_vertical_line notch, stroke: options[:notch_thickness],
35
+ color: options[:notch_color]
35
36
  end
36
37
 
37
- def draw_zero_line
38
- x = if mode == :negative
39
- width - zero_line_size
40
- elsif mode == :dual
41
- width / 2 - zero_line_size / 2
42
- else
43
- 0
44
- end
38
+ def draw_clipping_indicator
39
+ draw_vertical_line clamped_value,
40
+ stroke: options[:clipping_indicator_thickness],
41
+ color: options[:clipping_indicator_color]
42
+ end
45
43
 
46
- element :rect, x: x, y: 0,
47
- height: height, width: zero_line_size,
48
- fill: zero_line_color, stroke_width: 0
44
+ def draw_vertical_line(target_value, color:, stroke:)
45
+ x = x_for target_value
49
46
 
47
+ element :line, x1: x, x2: x, y1: 0, y2: options[:height],
48
+ stroke: color, stroke_width: stroke
50
49
  end
51
50
 
52
51
  def width_factor
53
- width / max.to_f
52
+ options[:width] / options[:max].to_f
53
+ end
54
+
55
+ def half_width
56
+ options[:width] * 0.5
54
57
  end
55
58
 
56
59
  def bar_width
@@ -60,5 +63,18 @@ module Minichart
60
63
  clamped_value.abs * width_factor
61
64
  end
62
65
  end
66
+
67
+ def x_for(target_value)
68
+ result = target_value.abs / options[:max].to_f * options[:width]
69
+
70
+ case mode
71
+ when :positive
72
+ result
73
+ when :negative
74
+ options[:width] - result
75
+ when :dual
76
+ target_value / options[:max].to_f * half_width + half_width
77
+ end
78
+ end
63
79
  end
64
80
  end
@@ -2,6 +2,22 @@ module Minichart
2
2
  # Base class for charts with a single value
3
3
  class Meter < Base
4
4
 
5
+ class << self
6
+ def meter_defaults
7
+ @meter_defaults ||= {
8
+ height: 50,
9
+ max: 100,
10
+ notches: [],
11
+ notch_thickness: 10,
12
+ notch_color: 'black',
13
+ clipping_indicator: false,
14
+ clipping_indicator_thickness: 20,
15
+ clipping_indicator_color: 'yellow',
16
+ }
17
+ end
18
+ end
19
+
20
+
5
21
  protected
6
22
 
7
23
  def value
@@ -9,7 +25,7 @@ module Minichart
9
25
  end
10
26
 
11
27
  def clipping?
12
- value > max || value < -max
28
+ value > options[:max] || value < -options[:max]
13
29
  end
14
30
 
15
31
  def mode
@@ -17,56 +33,32 @@ module Minichart
17
33
  end
18
34
 
19
35
  def mode!
20
- opts[:mode] ||= :auto
36
+ options[:mode] ||= :auto
21
37
 
22
- if opts[:mode] == :auto
38
+ if options[:mode] == :auto
23
39
  value >= 0 ? :positive : :negative
24
40
  else
25
- opts[:mode].to_sym
41
+ options[:mode].to_sym
26
42
  end
27
43
  end
28
44
 
29
- def max
30
- opts[:max] ||= 100
31
- end
32
-
33
- def zero_line
34
- opts[:zero_line]
35
- end
36
-
37
- def zero_line_size
38
- opts[:zero_line_size] ||= 6
39
- end
40
-
41
- def zero_line_color
42
- opts[:zero_line_color] ||= 'black'
43
- end
44
-
45
- def clipping_indicator
46
- opts[:clipping_indicator]
47
- end
48
-
49
- def clipping_indicator_size
50
- opts[:clipping_indicator_size] ||= 6
51
- end
52
-
53
- def clipping_indicator_color
54
- opts[:clipping_indicator_color] ||= 'yellow'
55
- end
56
-
57
45
  def clamped_value
58
46
  case mode
59
47
  when :positive
60
- value.clamp 0, max
48
+ value.clamp 0, options[:max]
61
49
  when :negative
62
- value.clamp -max, 0
50
+ value.clamp -options[:max], 0
63
51
  when :dual
64
- value.clamp -max, max
52
+ value.clamp -options[:max], options[:max]
65
53
  end
66
54
  end
67
55
 
68
56
  def style
69
- { fill: color, stroke_width: stroke, stroke: background }
57
+ {
58
+ fill: options[:color],
59
+ stroke_width: options[:stroke],
60
+ stroke: options[:background]
61
+ }
70
62
  end
71
63
 
72
64
  end
@@ -1,64 +1,59 @@
1
1
  module Minichart
2
2
  class VerticalBarMeter < Meter
3
+ class << self
4
+ def defaults
5
+ meter_defaults.merge width: 50, height: 300
6
+ end
7
+ end
8
+
3
9
  def build
4
10
  draw_bar
5
- draw_zero_line if zero_line
6
- draw_clipping_indicator if clipping_indicator and clipping?
11
+ draw_notches if options[:notches]
12
+ draw_clipping_indicator if options[:clipping_indicator] and clipping?
7
13
  end
8
14
 
9
15
  protected
10
16
 
11
- def width
12
- opts[:width] ||= 100
13
- end
17
+ def draw_bar
18
+ y1 = y_for 0
19
+ y2 = y_for clamped_value
20
+ y = [y1, y2].min
14
21
 
15
- def height
16
- opts[:height] ||= (aspect_ratio * width).round
22
+ element :rect, x: 0, y: y, height: bar_height,
23
+ width: options[:width], style: style
17
24
  end
18
25
 
19
- def draw_bar
20
- y = if mode == :positive
21
- height - bar_height
22
- elsif mode == :dual
23
- middle = height * 0.5
24
- value >= 0 ? middle - bar_height : middle
25
- else
26
- 0
26
+ def draw_notches
27
+ options[:notches].each do |notch|
28
+ draw_notch notch
29
+ draw_notch -notch if mode == :dual and notch != 0
27
30
  end
31
+ end
28
32
 
29
- element :rect, x: 0, y: y, height: bar_height, width: width, style: style
33
+ def draw_notch(notch)
34
+ draw_horizontal_line notch, stroke: options[:notch_thickness],
35
+ color: options[:notch_color]
30
36
  end
31
37
 
32
38
  def draw_clipping_indicator
33
- y = if mode == :negative or (mode == :dual and value < 0)
34
- height - clipping_indicator_size
35
- else
36
- 0
37
- end
38
-
39
- element :rect, x: 0, y: y,
40
- height: clipping_indicator_size, width: width,
41
- fill: clipping_indicator_color, stroke_width: 0
42
-
39
+ draw_horizontal_line clamped_value,
40
+ stroke: options[:clipping_indicator_thickness],
41
+ color: options[:clipping_indicator_color]
43
42
  end
44
43
 
45
- def draw_zero_line
46
- y = if mode == :positive
47
- height - zero_line_size
48
- elsif mode == :dual
49
- height / 2 - zero_line_size / 2
50
- else
51
- 0
52
- end
53
-
54
- element :rect, x: 0, y: y,
55
- height: zero_line_size, width: width,
56
- fill: zero_line_color, stroke_width: 0
44
+ def draw_horizontal_line(target_value, color:, stroke:)
45
+ y = y_for target_value
57
46
 
47
+ element :line, x1: 0, x2: options[:width], y1: y, y2: y,
48
+ stroke: color, stroke_width: stroke
58
49
  end
59
50
 
60
51
  def height_factor
61
- height / max.to_f
52
+ options[:height] / options[:max].to_f
53
+ end
54
+
55
+ def half_height
56
+ options[:height] * 0.5
62
57
  end
63
58
 
64
59
  def bar_height
@@ -68,5 +63,18 @@ module Minichart
68
63
  clamped_value.abs * height_factor
69
64
  end
70
65
  end
66
+
67
+ def y_for(target_value)
68
+ result = target_value.abs / options[:max].to_f * options[:height]
69
+
70
+ case mode
71
+ when :positive
72
+ options[:height] - result
73
+ when :negative
74
+ result
75
+ when :dual
76
+ options[:height] - (target_value / options[:max].to_f * half_height + half_height)
77
+ end
78
+ end
71
79
  end
72
80
  end
@@ -1,3 +1,3 @@
1
1
  module Minichart
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minichart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit