minichart 0.2.0 → 0.2.1

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: 767c1bdbf55e5aedb689c5286535fb84d3c48cf2c1c054b01da97237dee3437a
4
- data.tar.gz: ea0b462ccfd166eea1df2e2a4ad08f32060c713a06f1aea36170079bc90a3671
3
+ metadata.gz: 144b47573abadc9f4bfe5e41dea006bb24705db37dc93767353ba62d389bdd1d
4
+ data.tar.gz: 7c4936f6947307fd106b1e0700fff88c9ad7f5721dfc50dfd23ca3051a79b7b5
5
5
  SHA512:
6
- metadata.gz: 57524a378c6ce4df0ad08d4edc134630d3ae6ebbb35e68638f11926ab61f4c3b3f6e8e0861d49213de54d619d52df2cb74c4813e2349409e9e444b0ddca2cb44
7
- data.tar.gz: 45820a40054e716bfe412d661ba814ea4fb8589b39145fbeff6a079841ea83990d2adbaf6733c328378627133eaaa5891f5e87d268f66abab69a412727cbc29a
6
+ metadata.gz: c66ae222164ccc21a98cd8eddd790f54d114897ed6374b7e36fd242d16364e49ccec532e580d3a180d094c48fd27853f7b01bd85c81e7b8a4af8254a595af191
7
+ data.tar.gz: 6d19ce05f98de008d26127b8046512b66e1c68af0972e3b66f15ce3a6bfe4ac8a99a6de76457757e34903e3012b757ba31eeba688a018393304ca8cff41a1e74
data/README.md CHANGED
@@ -33,15 +33,13 @@ Initialize a chart with data, and optional options:
33
33
 
34
34
  ```ruby
35
35
  data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9]
36
- line = LineChart.new data, color: 'blue'
37
- bars = BarChart.new data, color: 'blue'
38
- area = AreaChart.new data, color: 'blue'
36
+ chart = AreaChart.new data, color: 'blue'
39
37
  ```
40
38
 
41
39
  Get the full SVG output by calling `#render`:
42
40
 
43
41
  ```ruby
44
- puts area.render
42
+ puts chart.render
45
43
  #=> <?xml version="1.0" standalone="no"?>
46
44
  # <svg> ... </svg>
47
45
  ```
@@ -49,42 +47,105 @@ puts area.render
49
47
  Save it to file, by calling `#save`:
50
48
 
51
49
  ```ruby
52
- area.save "my-chart.svg"
50
+ chart.save "my-chart.svg"
53
51
  ```
54
52
 
55
53
  Get its inner SVG string by calling `#to_s`:
56
54
 
57
55
  ```ruby
58
- puts area.to_s
56
+ puts chart.to_s
59
57
  #=> <polyline fill="blue" stroke="blue" stroke-width="2" points="..."/>
60
58
  ```
61
59
 
62
60
 
63
61
  The objects returned from all the mini chart classes are [Victor::SVG][2] objects, so they support all methods supported by it as well.
64
62
 
63
+ ## Chart Types
64
+
65
+ ### Line Chart
66
+
67
+ <img src='examples/line_chart.svg' align='right'>
68
+
69
+ ```ruby
70
+ LineChart.new data, height: 50, background: '#eee',
71
+ aspect_ratio: 5, color: 'green'
72
+ ```
73
+
74
+ ### Bar Chart
75
+
76
+ <img src='examples/bar_chart.svg' align='right'>
77
+
78
+ ```ruby
79
+ BarChart.new data, height: 50, background: '#eee',
80
+ aspect_ratio: 5, color: 'green'
81
+ ```
82
+
83
+ ### Area Chart
84
+
85
+ <img src='examples/area_chart.svg' align='right'>
86
+
87
+ ```ruby
88
+ AreaChart.new data, height: 50, background: '#eee',
89
+ aspect_ratio: 5, color: 'green'
90
+ ```
91
+
92
+ ### Horizontal Bar Meter
93
+
94
+ <img src='examples/multiple_horizontal_bars.svg' align='right'>
95
+
96
+ ```ruby
97
+ positive = HorizontalBarMeter.new 70,
98
+ height: 20, width: 250, background: '#9f9', color: 'green'
99
+
100
+ negative = HorizontalBarMeter.new -80,
101
+ height: 20, width: 250, background: '#f99', color: 'red'
102
+
103
+ dual = HorizontalBarMeter.new 80,
104
+ height: 20, width: 250, background: '#99f', color: 'blue',
105
+ mode: :dual, zero_line: true
106
+ ```
107
+
108
+ Meter charts support [additional options](#meter-options).
109
+
65
110
  ## Options
66
111
 
67
- All minichart classes support a second hash argument for options
112
+ ### Basic Options
113
+
114
+ All chart classes support a second hash argument for options
68
115
 
69
116
  ```ruby
70
117
  chart = LineChart.new data, options
71
118
  ```
72
119
 
73
- | Option | Default | Description |
74
- | -------------- | ---------------------------- | ----------------------- |
75
- | `background` | *None* | Chart background color |
76
- | `color` | #333 | Chart color |
77
- | `aspect_ratio` | 3 | Set automatic width |
78
- | `height` | 100 | Chart height in pixels |
79
- | `width` | Calculated by `aspect_ratio` | Chart width in pixels |
80
- | `stroke` | 2 | Line stroke width |
81
- | `style` | *None* | Style hash for the SVG |
120
+ | Option | Default | Description |
121
+ | -------------- | ---------------------------- | ------------------------------------------------------------ |
122
+ | `background` | `"white"` | Chart background color |
123
+ | `color` | `"#333"` | Chart color |
124
+ | `aspect_ratio` | `3` | Set automatic width |
125
+ | `height` | `100` | Chart height in pixels |
126
+ | `width` | Calculated by `aspect_ratio` | Chart width in pixels |
127
+ | `stroke` | `2` | Line stroke width.<br />In `BarChart` determines the gap between bars |
128
+ | `style` | *None* | Style hash for the SVG |
129
+
130
+
131
+ ### Meter Options
82
132
 
133
+ Meter charts support these options in additon to the basic options:
134
+
135
+ | Option | Default | Description |
136
+ | ------------------ | --------- | ------------------------------------------------------------ |
137
+ | `mode` | `:auto` | Display mode.<br />Can be `:positive`, `:negative`, `:auto` or `:dual` |
138
+ | `max` | `100` | The absolute maximum value.<br />This number should be positive even for nengative charts |
139
+ | `zero_line` | `false` | If true, mark the zero line |
140
+ | `zero_line_stroke` | `4` | Width of the zero line |
141
+ | `zero_line_color` | `"black"` | Color of the zero line |
83
142
 
84
143
  ## Examples
85
144
 
86
145
  See more examples (code and SVG output) in the [examples folder][1].
87
146
 
147
+ ---
148
+
88
149
 
89
150
  [1]: https://github.com/DannyBen/minichart/tree/master/examples#examples
90
151
  [2]: https://github.com/DannyBen/victor
@@ -1,7 +1,11 @@
1
1
  require 'victor'
2
- require 'minichart/chart'
3
- require 'minichart/line_chart'
4
- require 'minichart/bar_chart'
5
- require 'minichart/area_chart'
2
+ require 'minichart/id_generator'
3
+ require 'minichart/base'
4
+ require 'minichart/charts/chart'
5
+ require 'minichart/charts/line_chart'
6
+ require 'minichart/charts/bar_chart'
7
+ require 'minichart/charts/area_chart'
8
+ require 'minichart/meters/meter'
9
+ require 'minichart/meters/horizontal_bar_meter'
6
10
 
7
11
  require 'byebug' if ENV['BYEBUG']
@@ -0,0 +1,65 @@
1
+ module Minichart
2
+ # Base class for all Minichart classes
3
+ class Base < Victor::SVGBase
4
+ attr_reader :aspect_ratio, :background, :color, :data,
5
+ :height, :stroke, :style, :width, :opts
6
+
7
+ def initialize(data, opts = {})
8
+ @data, @opts = data, opts
9
+
10
+ super height: height, width: width, style: style, viewBox: viewbox
11
+ element :rect, x: 0, y: 0, width: width, height: height, fill: background
12
+
13
+ clip_path_id = IDGenerator.next
14
+ setup_clip_path clip_path_id
15
+
16
+ element :g, clip_path: "url(##{clip_path_id})" do
17
+ build
18
+ end
19
+ end
20
+
21
+ def setup_clip_path(id)
22
+ element :defs do
23
+ element :clipPath, id: id do
24
+ element :rect, width: width, height: height
25
+ end
26
+ end
27
+ end
28
+
29
+ def background
30
+ opts[:background] ||= 'white'
31
+ end
32
+
33
+ def aspect_ratio
34
+ opts[:aspect_ratio] ||= 3
35
+ end
36
+
37
+ def height
38
+ opts[:height] ||= 100
39
+ end
40
+
41
+ def width
42
+ opts[:width] ||= (aspect_ratio * height).round
43
+ end
44
+
45
+ def stroke
46
+ opts[:stroke] ||= 2
47
+ end
48
+
49
+ def style
50
+ opts[:style] ||= {}
51
+ end
52
+
53
+ def color
54
+ opts[:color] ||= '#333'
55
+ end
56
+
57
+ def viewbox
58
+ "0 0 #{width} #{height}"
59
+ end
60
+
61
+ def build
62
+ raise NotImplementedError, "#build is not implemented"
63
+ end
64
+ end
65
+ end
@@ -1,7 +1,7 @@
1
1
  module Minichart
2
2
  class AreaChart < Chart
3
3
  def build
4
- polyline fill: color,
4
+ element :polyline, fill: color,
5
5
  stroke: color,
6
6
  stroke_width: stroke,
7
7
  stroke_linejoin: :round,
@@ -1,29 +1,29 @@
1
- module Minichart
2
- class BarChart < Chart
3
- def build
4
- opts = { x_point_count: data.size }
5
-
6
- inverted_points(opts).each do |x, y|
7
- rect bar_options x, y
8
- end
9
- end
10
-
11
- protected
12
-
13
- def bar_width
14
- @bar_width ||= width / data.size
15
- end
16
-
17
- def bar_options(x, y)
18
- y = y*height
19
- bar_height = height-y
20
- {
21
- x: x*width,
22
- y: y,
23
- width: bar_width,
24
- height: bar_height,
25
- style: { fill: color, stroke_width: stroke, stroke: background }
26
- }
27
- end
28
- end
29
- end
1
+ module Minichart
2
+ class BarChart < Chart
3
+ def build
4
+ opts = { x_point_count: data.size }
5
+
6
+ inverted_points(opts).each do |x, y|
7
+ element :rect, bar_options(x, y)
8
+ end
9
+ end
10
+
11
+ protected
12
+
13
+ def bar_width
14
+ @bar_width ||= width / data.size
15
+ end
16
+
17
+ def bar_options(x, y)
18
+ y = y*height
19
+ bar_height = height-y
20
+ {
21
+ x: x*width,
22
+ y: y,
23
+ width: bar_width,
24
+ height: bar_height,
25
+ style: { fill: color, stroke_width: stroke, stroke: background }
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ module Minichart
2
+ # Base class for charts with data series
3
+ class Chart < Base
4
+
5
+ protected
6
+
7
+ def inverted_points(opts={})
8
+ normalized_points(opts).map { |point| [point[0], 1-point[1]] }
9
+ end
10
+
11
+ def normalized_points(opts={})
12
+ x_point_count = opts[:x_point_count] || data.count-1
13
+
14
+ range = (data.max - data.min).to_f
15
+ x_width = 1 / (x_point_count).to_f
16
+ result = []
17
+
18
+ data.each_with_index do |y, index|
19
+ x = index*x_width
20
+ y = (y - data.min) / range
21
+ result << [x,y]
22
+ end
23
+
24
+ result
25
+ end
26
+
27
+ end
28
+ end
@@ -1,7 +1,7 @@
1
1
  module Minichart
2
2
  class LineChart < Chart
3
3
  def build
4
- polyline fill: :none,
4
+ element :polyline, fill: :none,
5
5
  stroke: color,
6
6
  stroke_width: stroke,
7
7
  stroke_linejoin: :round,
@@ -0,0 +1,14 @@
1
+ module Minichart
2
+ module IDGenerator
3
+ class << self
4
+ def next
5
+ @id ||= 0
6
+ "minichart-#{@id += 1}"
7
+ end
8
+
9
+ def reset
10
+ @id = 0
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,91 @@
1
+ module Minichart
2
+ class HorizontalBarMeter < Meter
3
+ def build
4
+ draw_bar
5
+ draw_zero_line if zero_line
6
+ end
7
+
8
+ protected
9
+
10
+ def draw_bar
11
+ x = if mode == :negative
12
+ width - bar_width
13
+ elsif mode == :dual
14
+ middle = width * 0.5
15
+ value >= 0 ? middle : middle - bar_width
16
+ else
17
+ 0
18
+ end
19
+
20
+ element :rect, x: x, y: 0, height: height, width: bar_width, style: style
21
+ end
22
+
23
+ def draw_zero_line
24
+ x = if mode == :negative
25
+ width-zero_line_stroke
26
+ elsif mode == :dual
27
+ width / 2 - zero_line_stroke / 2
28
+ else
29
+ 0
30
+ end
31
+
32
+ element :rect, x: x, y: 0,
33
+ height: height, width: zero_line_stroke,
34
+ fill: zero_line_color
35
+
36
+ end
37
+
38
+ def mode
39
+ opts[:mode] ||= :auto
40
+
41
+ if opts[:mode] == :auto
42
+ value >= 0 ? :positive : :negative
43
+ else
44
+ opts[:mode]
45
+ end
46
+ end
47
+
48
+ def max
49
+ opts[:max] ||= 100
50
+ end
51
+
52
+ def zero_line
53
+ opts[:zero_line]
54
+ end
55
+
56
+ def zero_line_stroke
57
+ opts[:zero_line_stroke] || 6
58
+ end
59
+
60
+ def zero_line_color
61
+ opts[:zero_line_color] || 'black'
62
+ end
63
+
64
+ def width_factor
65
+ width / max.to_f
66
+ end
67
+
68
+ def clamped_value
69
+ case mode
70
+ when :positive
71
+ value.clamp 0, max
72
+ when :negative
73
+ value.clamp -max, 0
74
+ when :dual
75
+ value.clamp -max, max
76
+ end
77
+ end
78
+
79
+ def bar_width
80
+ if mode == :dual
81
+ clamped_value.abs * width_factor * 0.5
82
+ else
83
+ clamped_value.abs * width_factor
84
+ end
85
+ end
86
+
87
+ def style
88
+ { fill: color, stroke_width: stroke, stroke: background }
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,8 @@
1
+ module Minichart
2
+ # Base class for charts with a single value
3
+ class Meter < Base
4
+ def value
5
+ data
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module Minichart
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
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.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
@@ -32,10 +32,14 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - README.md
34
34
  - lib/minichart.rb
35
- - lib/minichart/area_chart.rb
36
- - lib/minichart/bar_chart.rb
37
- - lib/minichart/chart.rb
38
- - lib/minichart/line_chart.rb
35
+ - lib/minichart/base.rb
36
+ - lib/minichart/charts/area_chart.rb
37
+ - lib/minichart/charts/bar_chart.rb
38
+ - lib/minichart/charts/chart.rb
39
+ - lib/minichart/charts/line_chart.rb
40
+ - lib/minichart/id_generator.rb
41
+ - lib/minichart/meters/horizontal_bar_meter.rb
42
+ - lib/minichart/meters/meter.rb
39
43
  - lib/minichart/version.rb
40
44
  homepage: https://github.com/DannyBen/minichart
41
45
  licenses:
@@ -1,50 +0,0 @@
1
- module Minichart
2
- class Chart < Victor::SVG
3
- attr_reader :aspect_ratio, :background, :color, :data,
4
- :height, :stroke, :style, :width
5
-
6
- def initialize(data, opts = {})
7
- @data = data
8
- @background = opts[:background]
9
- @aspect_ratio = opts[:aspect_ratio] || 3
10
- @height = opts[:height] || 100
11
- @width = opts[:width] || (aspect_ratio * height).round
12
- @stroke = opts[:stroke] || 2
13
- @style = opts[:style] || {}
14
- @color = opts[:color] || '#333'
15
-
16
- super height: height, width: width, style: style,
17
- viewBox: "0 0 #{width} #{height}"
18
-
19
- rect x: 0, y: 0, width: width, height: height, fill: background if background
20
-
21
- build
22
- end
23
-
24
- def build
25
- raise NotImplementedError, "#build is not implemented"
26
- end
27
-
28
- protected
29
-
30
- def inverted_points(opts={})
31
- normalized_points(opts).map { |point| [point[0], 1-point[1]] }
32
- end
33
-
34
- def normalized_points(opts={})
35
- x_point_count = opts[:x_point_count] || data.count-1
36
-
37
- range = (data.max - data.min).to_f
38
- x_width = 1/(x_point_count).to_f
39
- result = []
40
-
41
- data.each_with_index do |y, index|
42
- x = index*x_width
43
- y = (y-data.min)/range
44
- result << [x,y]
45
- end
46
-
47
- result
48
- end
49
- end
50
- end