minichart 0.2.2 → 0.3.0

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