chartjs-ror 1.0.0 → 1.0.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.
- data/README.md +8 -1
- data/Rakefile +7 -0
- data/chartjs-ror.gemspec +3 -0
- data/lib/chartjs/axis_helpers.rb +130 -0
- data/lib/chartjs/chart_helpers.rb +9 -0
- data/lib/chartjs/railtie.rb +2 -0
- data/lib/chartjs/version.rb +1 -1
- data/test/axis_helpers_test.rb +64 -0
- metadata +39 -4
data/README.md
CHANGED
@@ -6,6 +6,8 @@ Simplifies using [Chart.js][] in Rails views.
|
|
6
6
|
* Legends for your charts.
|
7
7
|
* Renders charts on page load rather than DOMContentReady ([reason][browsersupport]).
|
8
8
|
* Animates unless you have Modernizr and it doesn't detect canvas support ([reason][browsersupport]). You can manually override this.
|
9
|
+
* Optional alternative (better?) abscissa scale calculations.
|
10
|
+
* Utility method for filling in gaps in integer series.
|
9
11
|
|
10
12
|
NOTE: this is Rails 3.0 only at the moment, so pre-asset pipeline. I plan to upgrade soon.
|
11
13
|
|
@@ -165,7 +167,7 @@ And in Ruby:
|
|
165
167
|
|
166
168
|
You can put anything in the `options` hash that Chart.js recognises. It also supports these non-Chart.js settings:
|
167
169
|
|
168
|
-
* `:
|
170
|
+
* `:class` - class of the enclosing `<figure/>` - default is `chart`.
|
169
171
|
* `:element_id` - id of the `<canvas/>` - default is `chart-n` where `n` is the 0-based index of the chart on the page.
|
170
172
|
* `:width` - width of the canvas in px - default is `400`.
|
171
173
|
* `:height` - height of the canvas in px - default is `400`.
|
@@ -214,6 +216,11 @@ Each item in the legend array is given two classes:
|
|
214
216
|
This lets you style legends in general but override the styles for specific charts.
|
215
217
|
|
216
218
|
|
219
|
+
### Scale calculations
|
220
|
+
|
221
|
+
The plugin implements its own abscissa scale calculations which I prefer to Chart.js's. You can opt-in to these calculations by passing `scaleOverride: true` in the `options` hash, without any of the other scale override keys (`scaleSteps`, `scaleStepWidth`, `scaleStartValue`).
|
222
|
+
|
223
|
+
|
217
224
|
## Inspiration
|
218
225
|
|
219
226
|
* [Chart.js][] (obviously)
|
data/Rakefile
CHANGED
data/chartjs-ror.gemspec
CHANGED
@@ -16,4 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'activesupport', '>3'
|
21
|
+
gem.add_development_dependency 'rake'
|
19
22
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Chartjs
|
4
|
+
module AxisHelpers
|
5
|
+
|
6
|
+
# Returns an ordered copy of data with "missing" keys mapped to 0 values.
|
7
|
+
#
|
8
|
+
# data - a Hash of Integer keys mapped to to Integer values.
|
9
|
+
#
|
10
|
+
# Returns an OrderedHash whose Integer keys run from 0 to data's maximum key
|
11
|
+
# and whose values are the corresponding values in data or 0.
|
12
|
+
def series(data)
|
13
|
+
return {} if data.nil? || data.empty?
|
14
|
+
(0..data.keys.max).reduce(ActiveSupport::OrderedHash.new) { |hash,k| hash[k] = data[k] || 0; hash }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Calculates the number of steps and the step width for ordinate axis labels.
|
18
|
+
# The ordinate axis is assumed to start at 0.
|
19
|
+
#
|
20
|
+
# data - an Array of Numerics.
|
21
|
+
#
|
22
|
+
# Returns a Hash with:
|
23
|
+
# :scaleSteps - the number of steps (always <= 10)
|
24
|
+
# :scaleStepWidth - the value jump between steps
|
25
|
+
# :scaleStartValue - 0
|
26
|
+
def ordinate_scale(data)
|
27
|
+
scale_max = calculate_scale_max data.max
|
28
|
+
normalised_scale_max = normalise scale_max
|
29
|
+
|
30
|
+
# normalised_scale_max number_steps step_width
|
31
|
+
# 0 0 0
|
32
|
+
# 0.5 5 1
|
33
|
+
# 1 5 2
|
34
|
+
# 1.5 5 3
|
35
|
+
# 2 4 5
|
36
|
+
# 2.5 5 5
|
37
|
+
# 3 6 5
|
38
|
+
# 3.5 7 5
|
39
|
+
# 4 8 5
|
40
|
+
# 4.5 9 5
|
41
|
+
# 5 10 5
|
42
|
+
# 5.5 6 10
|
43
|
+
# 6 6 10
|
44
|
+
# 6.5 7 10
|
45
|
+
# 7 7 10
|
46
|
+
# 7.5 8 10
|
47
|
+
# 8 8 10
|
48
|
+
# 8.5 9 10
|
49
|
+
# 9 9 10
|
50
|
+
# 9.5 10 10
|
51
|
+
if normalised_scale_max.zero?
|
52
|
+
number_steps = 0
|
53
|
+
step_width = 0
|
54
|
+
elsif normalised_scale_max < 2
|
55
|
+
number_steps = 5
|
56
|
+
step_width = scale_max / number_steps
|
57
|
+
elsif normalised_scale_max < 5.5
|
58
|
+
step_width = 5 * 10**(order_of_magnitude(scale_max) - 1)
|
59
|
+
number_steps = scale_max / step_width.to_f
|
60
|
+
else
|
61
|
+
step_width = 10**(order_of_magnitude(scale_max))
|
62
|
+
number_steps = scale_max / step_width.to_f
|
63
|
+
end
|
64
|
+
|
65
|
+
{scaleSteps: number_steps.ceil, scaleStepWidth: step_width, scaleStartValue: 0}
|
66
|
+
end
|
67
|
+
|
68
|
+
# Rounds up value to the next "increment", where an increment is half
|
69
|
+
# the order of magnitude value.
|
70
|
+
#
|
71
|
+
# value - a Numeric.
|
72
|
+
#
|
73
|
+
# Examples
|
74
|
+
#
|
75
|
+
# input output
|
76
|
+
# 12 15
|
77
|
+
# 15 15
|
78
|
+
# 16 20
|
79
|
+
# 1432 1500
|
80
|
+
# 7654 8000
|
81
|
+
#
|
82
|
+
# Returns an Integer.
|
83
|
+
def calculate_scale_max(value)
|
84
|
+
normalised = normalise value
|
85
|
+
quotient, modulus = normalised.divmod 1
|
86
|
+
next_increment = if modulus.zero?
|
87
|
+
quotient
|
88
|
+
elsif modulus <= 0.5
|
89
|
+
quotient + 0.5
|
90
|
+
else
|
91
|
+
quotient + 1
|
92
|
+
end
|
93
|
+
(next_increment * 10**(order_of_magnitude(value))).to_i
|
94
|
+
end
|
95
|
+
|
96
|
+
# Normalises the value to between 0 inclusive and 10.
|
97
|
+
#
|
98
|
+
# value - a Numeric.
|
99
|
+
#
|
100
|
+
# Returns a Float or 0 if value is nil or zero..
|
101
|
+
def normalise(value)
|
102
|
+
return 0 if value.nil? || value.zero?
|
103
|
+
value.to_f / 10**(order_of_magnitude(value))
|
104
|
+
end
|
105
|
+
|
106
|
+
# Calculates the order of magnitude of value.
|
107
|
+
#
|
108
|
+
# value - a Numeric.
|
109
|
+
#
|
110
|
+
# Examples
|
111
|
+
#
|
112
|
+
# order_of_magnitude(3)
|
113
|
+
# # => 1
|
114
|
+
#
|
115
|
+
# order_of_magnitude(13)
|
116
|
+
# # => 1
|
117
|
+
#
|
118
|
+
# order_of_magnitude(153)
|
119
|
+
# # => 2
|
120
|
+
#
|
121
|
+
# Returns a Integer or 0 if value is nil or zero.
|
122
|
+
def order_of_magnitude(value)
|
123
|
+
return 0 if value.nil? || value.zero?
|
124
|
+
magnitude = Math.log10 value
|
125
|
+
order_of_magnitude = magnitude.floor
|
126
|
+
order_of_magnitude.zero? ? 1 : order_of_magnitude
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -56,6 +56,11 @@ module Chartjs
|
|
56
56
|
''
|
57
57
|
end
|
58
58
|
|
59
|
+
# Alternative scale calculations.
|
60
|
+
if options[:scaleOverride] && !options.has_key?(:scaleSteps)
|
61
|
+
options.merge! ordinate_scale(combined_data(datasets))
|
62
|
+
end
|
63
|
+
|
59
64
|
script = javascript_tag do
|
60
65
|
<<-END.html_safe
|
61
66
|
var initChart = function() {
|
@@ -87,5 +92,9 @@ module Chartjs
|
|
87
92
|
end
|
88
93
|
end
|
89
94
|
|
95
|
+
def combined_data(datasets)
|
96
|
+
datasets.map { |d| d[:data] || d[:value] }.flatten
|
97
|
+
end
|
98
|
+
|
90
99
|
end
|
91
100
|
end
|
data/lib/chartjs/railtie.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'chartjs/chart_helpers'
|
2
|
+
require 'chartjs/axis_helpers'
|
2
3
|
|
3
4
|
module Chartjs
|
4
5
|
class Railtie < Rails::Railtie
|
5
6
|
initializer 'chartjs.chart_helpers' do
|
6
7
|
ActionView::Base.send :include, Chartjs::ChartHelpers
|
8
|
+
ActionView::Base.send :include, Chartjs::AxisHelpers
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/lib/chartjs/version.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'chartjs/axis_helpers'
|
3
|
+
|
4
|
+
class AxisHelpersTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@subject = Object.new
|
8
|
+
@subject.extend Chartjs::AxisHelpers
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_series_empty_data
|
12
|
+
data = {}
|
13
|
+
result = @subject.series data
|
14
|
+
assert_equal 0, result.length
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_series
|
18
|
+
data = { 2 => 42 }
|
19
|
+
result = @subject.series data
|
20
|
+
assert_equal 3, result.length
|
21
|
+
assert_equal({0 => 0, 1 => 0, 2 => 42}, result)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_calculate_scale_max
|
25
|
+
{
|
26
|
+
0 => 0,
|
27
|
+
3 => 5,
|
28
|
+
5 => 5,
|
29
|
+
6 => 10,
|
30
|
+
9 => 10,
|
31
|
+
10 => 10,
|
32
|
+
12 => 15,
|
33
|
+
16 => 20,
|
34
|
+
60 => 60,
|
35
|
+
65 => 65,
|
36
|
+
601 => 650,
|
37
|
+
1430 => 1500,
|
38
|
+
7654 => 8000,
|
39
|
+
}.each do |input, expected_output|
|
40
|
+
assert_equal expected_output, @subject.calculate_scale_max(input)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_ordinate_scale
|
45
|
+
data = []
|
46
|
+
assert_equal({scaleSteps: 0, scaleStepWidth: 0, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
47
|
+
|
48
|
+
data = [ 12 ]
|
49
|
+
assert_equal({scaleSteps: 5, scaleStepWidth: 3, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
50
|
+
|
51
|
+
data = [ 33 ]
|
52
|
+
assert_equal({scaleSteps: 7, scaleStepWidth: 5, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
53
|
+
|
54
|
+
data = [ 601 ]
|
55
|
+
assert_equal({scaleSteps: 7, scaleStepWidth: 100, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
56
|
+
|
57
|
+
data = [ 999 ]
|
58
|
+
assert_equal({scaleSteps: 5, scaleStepWidth: 200, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
59
|
+
|
60
|
+
data = [ 13001 ]
|
61
|
+
assert_equal({scaleSteps: 5, scaleStepWidth: 3000, scaleStartValue: 0}, @subject.ordinate_scale(data))
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chartjs-ror
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,40 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
13
|
-
dependencies:
|
12
|
+
date: 2013-06-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>'
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>'
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
14
46
|
description: Simplifies using Chart.js in Rails
|
15
47
|
email:
|
16
48
|
- boss@airbladesoftware.com
|
@@ -26,9 +58,11 @@ files:
|
|
26
58
|
- chartjs-ror.gemspec
|
27
59
|
- lib/chartjs-ror.rb
|
28
60
|
- lib/chartjs.rb
|
61
|
+
- lib/chartjs/axis_helpers.rb
|
29
62
|
- lib/chartjs/chart_helpers.rb
|
30
63
|
- lib/chartjs/railtie.rb
|
31
64
|
- lib/chartjs/version.rb
|
65
|
+
- test/axis_helpers_test.rb
|
32
66
|
homepage: https://github.com/airblade/chartjs-ror
|
33
67
|
licenses: []
|
34
68
|
post_install_message:
|
@@ -53,4 +87,5 @@ rubygems_version: 1.8.23
|
|
53
87
|
signing_key:
|
54
88
|
specification_version: 3
|
55
89
|
summary: Simplifies using Chart.js in Rails
|
56
|
-
test_files:
|
90
|
+
test_files:
|
91
|
+
- test/axis_helpers_test.rb
|