volt-highcharts 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/LICENSE.txt +1 -1
- data/README.md +26 -31
- data/app/highcharts/config/dependencies.rb +5 -1
- data/app/highcharts/controllers/main_controller.rb +145 -49
- data/lib/volt/highcharts/version.rb +1 -1
- data/push +5 -0
- data/volt-highcharts.gemspec +2 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57bc486e2e61cd1b390da2fb6cba28705479531f
|
4
|
+
data.tar.gz: 2f1a36ef4888500b8933201f7cd533a0a774a20d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f45e348902daac3c71b825bcddbf8c7797ee3aed492a0718684062fd4ff56237c6fe4e62f9cf02a74bf0744caf9c39961c173d00c6f26f6034670d93a1ea9e25
|
7
|
+
data.tar.gz: 13aee26ca775e5e626688967d2365ce9314197f15ac0dc1cb49c27f2fffeab6d0bc7f5ec9e9fcd31a09605070690b9befd518a6c2514b785ab6a872829a8e04c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## 0.1.1
|
4
|
+
|
5
|
+
- now uses opal-highcharts gem
|
6
|
+
- first steps towards reactivitiy
|
7
|
+
- a chart is reactive if options are provided as a Volt::Model
|
8
|
+
- a chart is non-reactive if options are provided as a Hash
|
9
|
+
|
10
|
+
### opal-highcharts
|
11
|
+
a gem which wraps most Highcharts and Highstock functionality in a client-side Ruby API.
|
12
|
+
- https://github.com/balmoral/opal-highcharts
|
13
|
+
- https://rubygems.org/gems/opal-highcharts
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,9 +2,13 @@
|
|
2
2
|
|
3
3
|
A Volt component wrapping the Highcharts javascript charting tool.
|
4
4
|
|
5
|
+
It depends on opal-highcharts, a gem which wraps most Highcharts and Highstock functionality in a client-side Ruby API.
|
6
|
+
|
5
7
|
Highcharts is free for non-commercial use.
|
6
8
|
|
7
9
|
http://www.highcharts.com/products/highcharts
|
10
|
+
http://github.com/balmoral/volt-highcharts
|
11
|
+
https://rubygems.org/gems/volt-highcharts
|
8
12
|
|
9
13
|
## Installation
|
10
14
|
|
@@ -36,20 +40,25 @@ Pass a Ruby hash containing chart options in the appropriate view html file:
|
|
36
40
|
<:highcharts chart="{{ chart_options }}" />
|
37
41
|
```
|
38
42
|
|
39
|
-
where `chart_options` is provided by your controller or model.
|
43
|
+
where `chart_options` is a Volt::Model or Hash provided by your controller or model.
|
44
|
+
|
45
|
+
Reactivity is now supported.
|
40
46
|
|
47
|
+
To implement a reactive chart, the options provided on chart creation should be wrapped in a Volt::Model.
|
48
|
+
|
49
|
+
NB reactivity is currently limited to chart titles, number of series, and individual series options and data. More coming soon.
|
50
|
+
|
41
51
|
Documentation for Highcharts options can be found at: http://api.highcharts.com/highcharts#chart.
|
42
52
|
|
43
|
-
|
44
|
-
|
45
|
-
For convenience, the last chart added can simply be accessed as ```page._chart```, wrapped by Opal's Native().
|
53
|
+
For convenience, the last chart added can be accessed as ```page._chart```.
|
54
|
+
The object returned is a Highcharts::Chart, which can be used to directly query and manipulate the chart (see opal-highcharts).
|
46
55
|
|
47
56
|
To query or modify multiple chart(s) on the page a unique :id should be set in each chart's options.
|
48
57
|
|
49
58
|
For example:
|
50
59
|
```
|
51
60
|
def fruit_chart_options
|
52
|
-
{
|
61
|
+
Volt::Model.new( {
|
53
62
|
# to identity the chart in volt
|
54
63
|
id: 'fruit_chart',
|
55
64
|
|
@@ -79,7 +88,7 @@ For example:
|
|
79
88
|
},
|
80
89
|
...
|
81
90
|
]
|
82
|
-
}
|
91
|
+
} )
|
83
92
|
end
|
84
93
|
```
|
85
94
|
|
@@ -95,36 +104,22 @@ For example, in your controller you might have a method to return the native cha
|
|
95
104
|
```
|
96
105
|
If you only have one chart on the page use ```page._chart```.
|
97
106
|
|
98
|
-
|
99
|
-
|
100
|
-
The chart object(s) found in ```page._chart``` and ```page._charts``` have been wrapped in Opal's Native(). This is because Volt::Model and Volt::ArrayModel can only hold Ruby objects.
|
101
|
-
|
102
|
-
Opal's Native() wraps a JS object to provide access to properties and functions in the JS object via Ruby method calls. As of writing (July 30, 2015) Native has not yet been documented. If you prefer to use backticks or %x{} to inline JS code you can get the JS object using #to_n.
|
103
|
-
|
104
|
-
For example, to change a series in a chart using Native(), you might do:
|
105
|
-
```
|
106
|
-
def update_sales
|
107
|
-
e = page._charts.find { |e| e._id == 'sales' }
|
108
|
-
series = Native(e._chart.series)
|
109
|
-
Native(series[0]).setData(sales_data.to_n)
|
110
|
-
end
|
111
|
-
```
|
112
|
-
The equivalent using backticks is:
|
113
|
-
```
|
114
|
-
def update_sales
|
115
|
-
native_chart = page._chart.to_n # get the native JS chart
|
116
|
-
native_data = sales_data.to_n # get native sales data
|
117
|
-
`native_chart.series[0].setData(native_data)`
|
118
|
-
end
|
119
|
-
```
|
107
|
+
With opal-highcharts, which completely wraps the Highcharts API in client-side Ruby (and comes bundled with volt-highcharts),
|
108
|
+
you now have simple access to query and modify methods on the chart and all of its elements. No Native wraps or backticks required.
|
120
109
|
|
121
|
-
|
110
|
+
As reactivity support is improved, there should be less need for direct manipulation of the chart.
|
111
|
+
|
112
|
+
## To do
|
122
113
|
|
123
|
-
|
114
|
+
1. remove debug traces
|
115
|
+
2. chart option/configuration checks
|
116
|
+
3. improved documentation
|
117
|
+
4. improved error handling
|
118
|
+
5. finer grained reactivity?
|
124
119
|
|
125
120
|
## Contributing
|
126
121
|
|
127
|
-
|
122
|
+
Contributions, comments and suggestions are welcome.
|
128
123
|
|
129
124
|
1. Fork it ( http://github.com/balmoral/volt-highcharts/fork )
|
130
125
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
@@ -1,2 +1,6 @@
|
|
1
1
|
# Component dependencies
|
2
|
-
|
2
|
+
|
3
|
+
# highcharts.js is not required if highstock is loaded
|
4
|
+
# javascript_file 'http://code.highcharts.com/highcharts.src.js'
|
5
|
+
javascript_file 'http://code.highcharts.com/stock/highstock.src.js'
|
6
|
+
# javascript_file 'http://code.highcharts.com/maps/highmaps.src.js'
|
@@ -1,72 +1,168 @@
|
|
1
|
+
if RUBY_PLATFORM == 'opal'
|
2
|
+
|
3
|
+
require 'native'
|
4
|
+
require 'opal-highcharts'
|
5
|
+
|
1
6
|
module Highcharts
|
2
7
|
class MainController < Volt::ModelController
|
3
8
|
|
9
|
+
attr_reader :chart, :watches, :watch_counts, :reactive
|
10
|
+
|
4
11
|
def index_ready
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
set_model
|
13
|
+
create_chart
|
14
|
+
start_watching
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_index_remove
|
18
|
+
stop_watching
|
19
|
+
update_page
|
20
|
+
@chart = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_model
|
26
|
+
options = attrs.options
|
27
|
+
unless options
|
28
|
+
raise ArgumentError, 'no options attribute set for :highcharts component'
|
29
|
+
end
|
30
|
+
# if the options are a Hash then convert to a Volt::Model
|
31
|
+
if options.is_a?(Volt::Model)
|
32
|
+
@reactive = true
|
33
|
+
else
|
34
|
+
options = Volt::Model.new(options)
|
35
|
+
@reactive = false
|
36
|
+
end
|
37
|
+
# set controller's model to options, which captures its methods for self
|
38
|
+
self.model = options
|
39
|
+
debug __method__, __LINE__, "model._id = #{_id}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create the chart and add it to the page._charts.
|
43
|
+
# page._charts ia an array of Volt::Models with an id and a chart attribute.
|
44
|
+
# Also set page._chart to the newly (last) created Highcharts::Chart.
|
45
|
+
# Also set page._char_id to the id of the new (last) chart.
|
46
|
+
def create_chart
|
47
|
+
@chart = Highcharts::Chart.new(model.to_h)
|
48
|
+
page._charts << {id: _id, chart: @chart}
|
49
|
+
page._chart = @chart
|
50
|
+
page._chart_id = _id
|
51
|
+
end
|
52
|
+
|
53
|
+
# To be reactive we must watch for model changes
|
54
|
+
def start_watching
|
55
|
+
@watches = []
|
56
|
+
@watch_counts = {}
|
57
|
+
if reactive
|
58
|
+
watch_titles
|
59
|
+
watch_series
|
22
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def watch_titles
|
64
|
+
watches << -> do
|
65
|
+
setup_dependencies(_title)
|
66
|
+
setup_dependencies(_subtitle)
|
67
|
+
log_change "#{self.class.name}##{__method__}:#{__LINE__} : chart.set_title(#{_title.to_h} #{_subtitle.to_h})"
|
68
|
+
chart.set_title(_title.to_h, _subtitle.to_h, true) # redraw
|
69
|
+
end.watch!
|
70
|
+
end
|
23
71
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
72
|
+
def watch_series
|
73
|
+
@series_size = _series.size
|
74
|
+
watches << -> do
|
75
|
+
size = _series.size
|
76
|
+
if size == @series_size
|
77
|
+
_series.each_with_index do |a_series, index|
|
78
|
+
watches << -> do
|
79
|
+
log_change "@@@ _series[#{index}] changed", a_series
|
80
|
+
watches << -> do
|
81
|
+
data = a_series._data
|
82
|
+
log_change "@@@ _series[#{index}]._data changed", data
|
83
|
+
chart.series[index].set_data(data.to_a)
|
84
|
+
end.watch!
|
85
|
+
watches << -> do
|
86
|
+
title = a_series._title
|
87
|
+
log_change "@@@ _series[#{index}]._title changed", title
|
88
|
+
end.watch!
|
89
|
+
watches << -> do
|
90
|
+
setup_dependencies(a_series, nest: true, except: [:title, :data])
|
91
|
+
log_change "@@@ _series[#{index}] something other than _title or _data changed", nil
|
92
|
+
# chart.series[index].update(_series.to_h)
|
93
|
+
end
|
94
|
+
end.watch!
|
95
|
+
end
|
96
|
+
else
|
97
|
+
log_change "@@@ _series.size changed to ", size
|
98
|
+
@series_size = size
|
99
|
+
refresh_all_series
|
100
|
+
end
|
101
|
+
end.watch!
|
102
|
+
end
|
103
|
+
|
104
|
+
# Do complete refresh of all series:
|
105
|
+
# 1. remove all series from chart with no redraw
|
106
|
+
# 2. add all series in model to chart with no redraw
|
107
|
+
# 3. redraw chart
|
108
|
+
def refresh_all_series
|
109
|
+
until chart.series.empty? do
|
110
|
+
debug __method__, __LINE__, "chart.series[#{chart.series.size-1}].remove"
|
111
|
+
chart.series.last.remove(false)
|
34
112
|
end
|
113
|
+
_series.each_with_index do |a_series, index|
|
114
|
+
debug __method__, __LINE__, "chart.add_series ##{index}"
|
115
|
+
chart.add_series(a_series.to_h, false)
|
116
|
+
end
|
117
|
+
debug __method__, __LINE__, "chart.redraw"
|
118
|
+
chart.redraw
|
119
|
+
end
|
35
120
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
121
|
+
# Force computation dependencies for attributes of a model
|
122
|
+
# TODO: must be better or built-in way ??
|
123
|
+
def setup_dependencies(model, nest: true, except: [])
|
124
|
+
model.attributes.each { |key, val|
|
125
|
+
unless except.include?(key)
|
126
|
+
debug __method__, __LINE__, "#{model}.send(#{key})"
|
127
|
+
model.send :"_#{key}"
|
128
|
+
end
|
129
|
+
if nest && val.is_a?(Volt::Model)
|
130
|
+
setup_dependencies(val, nest: true, except: except)
|
131
|
+
end
|
132
|
+
}
|
44
133
|
end
|
45
134
|
|
46
|
-
def
|
47
|
-
|
135
|
+
def stop_watching
|
136
|
+
@watches.each {|w| w.stop}
|
137
|
+
@watches = @watch_counts = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
def update_page
|
141
|
+
debug __method__, _LINE__, Time.now.to_s
|
48
142
|
# clear all references to this chart
|
49
|
-
i = page._charts.find_index { |e| e._id ==
|
143
|
+
i = page._charts.find_index { |e| e._id == _id }
|
50
144
|
if i
|
51
145
|
deleted = page._charts.delete_at(i)
|
52
|
-
|
146
|
+
debug __method__, __LINE__, "deleted='#{deleted}' page._charts.size=#{page._charts.size}"
|
53
147
|
deleted._chart.destroy
|
54
148
|
deleted._chart = nil
|
55
149
|
end
|
56
|
-
|
57
|
-
|
150
|
+
if page._chart_id == _id
|
151
|
+
last = page._charts.last
|
152
|
+
page._chart_id = last ? last._id : nil
|
153
|
+
page._chart = last ? last._chart : nil
|
154
|
+
end
|
58
155
|
end
|
59
156
|
|
60
|
-
|
61
|
-
|
62
|
-
# generate a unique id for chart container
|
63
|
-
def random_id
|
64
|
-
"highcharts#{(rand * 1000000000).to_i}"
|
157
|
+
def debug(method, line, s)
|
158
|
+
Volt.logger.debug "#{self.class.name}##{method}[#{line}] : #{s}"
|
65
159
|
end
|
66
160
|
|
67
|
-
def
|
68
|
-
{
|
161
|
+
def log_change(label, object = 'nil')
|
162
|
+
Volt.logger.debug "#{label} : #{object}"
|
69
163
|
end
|
70
164
|
|
71
165
|
end
|
72
|
-
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end # RUBY_PLATFORM == 'opal'
|
data/push
ADDED
data/volt-highcharts.gemspec
CHANGED
@@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
+
spec.add_runtime_dependency 'opal-highcharts', '~> 0.1.0'
|
21
|
+
|
20
22
|
# spec.add_development_dependency "volt", "~> 0.9.5.pre3"
|
21
23
|
# spec.add_development_dependency 'rspec', '~> 3.2.0'
|
22
24
|
# spec.add_development_dependency "rake"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: volt-highcharts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Colin Gunn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
-
dependencies:
|
11
|
+
date: 2015-08-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: opal-highcharts
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.0
|
13
27
|
description:
|
14
28
|
email:
|
15
29
|
- colgunn@icloud.com
|
@@ -18,6 +32,7 @@ extensions: []
|
|
18
32
|
extra_rdoc_files: []
|
19
33
|
files:
|
20
34
|
- ".rspec"
|
35
|
+
- CHANGELOG.md
|
21
36
|
- Gemfile
|
22
37
|
- LICENSE.txt
|
23
38
|
- README.md
|
@@ -29,6 +44,7 @@ files:
|
|
29
44
|
- app/highcharts/views/main/index.html
|
30
45
|
- lib/volt/highcharts.rb
|
31
46
|
- lib/volt/highcharts/version.rb
|
47
|
+
- push
|
32
48
|
- spec/spec_helper.rb
|
33
49
|
- spec/volt/highcharts_spec.rb
|
34
50
|
- volt-highcharts.gemspec
|