highcharts-ng-rails 0.0.3 → 0.0.7

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
  SHA1:
3
- metadata.gz: 2d44849fc5f006276f6f570d58cc84cd977e0dfd
4
- data.tar.gz: 47a5f57fc5653de34d947dff8d2dc78ebfff2c5b
3
+ metadata.gz: 5efcce932c820f3505f256d788b361a40c3bd804
4
+ data.tar.gz: c8c84695a4acd68e52c3c751844343cadc892666
5
5
  SHA512:
6
- metadata.gz: c99170b2331eaba3c511d6c7fa98b5c79ce878e3f1f42bb6292d4ca070828f2fcd24b80564f4e501eed8ea159262be7ffa6b303afaeff4fcd7cd62d7e717b370
7
- data.tar.gz: 5e6507837b3b63f84fe381e1c16e7ead84dbb690d4f56208857257708a1eb227d715393404db3442898f3bcf4bba2164f6e32fa470c67464151d4229bd558edf
6
+ metadata.gz: 44f698b6e1775a9ff8226b9f069215a3e784300bc45e5d5e7f8466d0d28c9cc390b88226027a8054c850f10bb29d6bee7b56276383a30f723460e14941046e52
7
+ data.tar.gz: 9daae96317a7a6de351d74b1541df97c36ed83ce977dfed2f40d49e5d1bc673179e2138a995c316345a07a8da0e69d6b40d3f73c15969c8c14d9e47faf170d0b
@@ -7,7 +7,7 @@ This gem just includes [highcharts-ng](https://github.com/pablojim/highcharts-ng
7
7
  Add the gem to the Gemfile
8
8
 
9
9
  gem "highcharts-rails"
10
- gem "highcharts-ng-rails", "~> 0.0.3"
10
+ gem "highcharts-ng-rails", "~> 0.0.7"
11
11
  # The gem version mirrors the included version of highcharts-ng
12
12
 
13
13
  ## Usage
@@ -1,199 +1,352 @@
1
- 'use strict';
2
-
3
- angular.module('highcharts-ng', [])
4
- .directive('highchart', function () {
5
-
6
- function prependMethod(obj, method, func) {
7
- var original = obj[method];
8
- obj[method] = function () {
9
- var args = Array.prototype.slice.call(arguments);
10
- func.apply(this, args);
11
- if(original) {
12
- return original.apply(this, args);
13
- } else {
14
- return;
15
- }
1
+ (function () {
2
+ 'use strict';
3
+ /*global angular: false, Highcharts: false */
16
4
 
17
- };
18
- }
19
-
20
- function deepExtend(destination, source) {
21
- for (var property in source) {
22
- if (source[property] && source[property].constructor &&
23
- source[property].constructor === Object) {
24
- destination[property] = destination[property] || {};
25
- deepExtend(destination[property], source[property]);
5
+ angular.module('highcharts-ng', [])
6
+ .factory('highchartsNGUtils', highchartsNGUtils)
7
+ .directive('highchart', ['highchartsNGUtils', highchart]);
8
+
9
+ function highchartsNGUtils() {
10
+
11
+ return {
12
+
13
+ //IE8 support
14
+ indexOf: function (arr, find, i /*opt*/) {
15
+ if (i === undefined) i = 0;
16
+ if (i < 0) i += arr.length;
17
+ if (i < 0) i = 0;
18
+ for (var n = arr.length; i < n; i++)
19
+ if (i in arr && arr[i] === find)
20
+ return i;
21
+ return -1;
22
+ },
23
+
24
+ prependMethod: function (obj, method, func) {
25
+ var original = obj[method];
26
+ obj[method] = function () {
27
+ var args = Array.prototype.slice.call(arguments);
28
+ func.apply(this, args);
29
+ if (original) {
30
+ return original.apply(this, args);
31
+ } else {
32
+ return;
33
+ }
34
+
35
+ };
36
+ },
37
+
38
+ deepExtend: function deepExtend(destination, source) {
39
+ //Slightly strange behaviour in edge cases (e.g. passing in non objects)
40
+ //But does the job for current use cases.
41
+ if (angular.isArray(source)) {
42
+ destination = angular.isArray(destination) ? destination : [];
43
+ for (var i = 0; i < source.length; i++) {
44
+ destination[i] = deepExtend(destination[i] || {}, source[i]);
45
+ }
46
+ } else if (angular.isObject(source)) {
47
+ for (var property in source) {
48
+ destination[property] = deepExtend(destination[property] || {}, source[property]);
49
+ }
26
50
  } else {
27
- destination[property] = source[property];
51
+ destination = source;
28
52
  }
53
+ return destination;
29
54
  }
30
- return destination;
31
- }
55
+ };
56
+ }
57
+
58
+ function highchart(highchartsNGUtils) {
32
59
 
60
+ // acceptable shared state
33
61
  var seriesId = 0;
34
62
  var ensureIds = function (series) {
35
- series.forEach(function (s) {
63
+ var changed = false;
64
+ angular.forEach(series, function(s) {
36
65
  if (!angular.isDefined(s.id)) {
37
- s.id = "series-" + seriesId++;
66
+ s.id = 'series-' + seriesId++;
67
+ changed = true;
38
68
  }
39
69
  });
40
- }
70
+ return changed;
71
+ };
41
72
 
42
- var defaultOptions = {
43
- chart: {
44
- events: {}
45
- },
46
- title: {},
47
- series: [],
48
- navigator: {enabled: false}
49
- }
73
+ // immutable
74
+ var axisNames = [ 'xAxis', 'yAxis' ];
50
75
 
51
76
  var getMergedOptions = function (scope, element, config) {
52
- var mergedOptions = {}
77
+ var mergedOptions = {};
78
+
79
+ var defaultOptions = {
80
+ chart: {
81
+ events: {}
82
+ },
83
+ title: {},
84
+ subtitle: {},
85
+ series: [],
86
+ credits: {},
87
+ plotOptions: {},
88
+ navigator: {enabled: false}
89
+ };
90
+
53
91
  if (config.options) {
54
- mergedOptions = deepExtend(defaultOptions, config.options);
92
+ mergedOptions = highchartsNGUtils.deepExtend(defaultOptions, config.options);
55
93
  } else {
56
94
  mergedOptions = defaultOptions;
57
95
  }
58
96
  mergedOptions.chart.renderTo = element[0];
59
- if(config.xAxis) {
60
- prependMethod(mergedOptions.chart.events, 'selection', function(e){
61
- var thisChart = this;
62
- if(e.xAxis) {
63
- scope.$apply(function () {
64
- scope.config.xAxis.currentMin = e.xAxis[0].min;
65
- scope.config.xAxis.currentMax = e.xAxis[0].max;
97
+
98
+ angular.forEach(axisNames, function(axisName) {
99
+ if(angular.isDefined(config[axisName])) {
100
+ mergedOptions[axisName] = angular.copy(config[axisName]);
101
+
102
+ if(angular.isDefined(config[axisName].currentMin) ||
103
+ angular.isDefined(config[axisName].currentMax)) {
104
+
105
+ highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'selection', function(e){
106
+ var thisChart = this;
107
+ if (e[axisName]) {
108
+ scope.$apply(function () {
109
+ scope.config[axisName].currentMin = e[axisName][0].min;
110
+ scope.config[axisName].currentMax = e[axisName][0].max;
111
+ });
112
+ } else {
113
+ //handle reset button - zoom out to all
114
+ scope.$apply(function () {
115
+ scope.config[axisName].currentMin = thisChart[axisName][0].dataMin;
116
+ scope.config[axisName].currentMax = thisChart[axisName][0].dataMax;
117
+ });
118
+ }
66
119
  });
67
- } else {
68
- //handle reset button - zoom out to all
69
- scope.$apply(function () {
70
- scope.config.xAxis.currentMin = thisChart.xAxis[0].dataMin;
71
- scope.config.xAxis.currentMax = thisChart.xAxis[0].dataMax;
120
+
121
+ highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
122
+ scope.config[axisName].currentMin = this[axisName][0].min || scope.config[axisName].currentMin;
123
+ scope.config[axisName].currentMax = this[axisName][0].max || scope.config[axisName].currentMax;
72
124
  });
73
125
  }
74
- });
126
+ }
127
+ });
75
128
 
76
- prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
77
- scope.config.xAxis.currentMin = this.xAxis[0].min || scope.config.xAxis.currentMin;
78
- scope.config.xAxis.currentMax = this.xAxis[0].max || scope.config.xAxis.currentMax;
79
- });
129
+ if(config.title) {
130
+ mergedOptions.title = config.title;
80
131
  }
81
-
82
- if(config.xAxis) {
83
- mergedOptions.xAxis = angular.copy(config.xAxis)
132
+ if (config.subtitle) {
133
+ mergedOptions.subtitle = config.subtitle;
84
134
  }
85
- if(config.title) {
86
- mergedOptions.title = config.title
135
+ if (config.credits) {
136
+ mergedOptions.credits = config.credits;
137
+ }
138
+ if(config.size) {
139
+ if (config.size.width) {
140
+ mergedOptions.chart.width = config.size.width;
141
+ }
142
+ if (config.size.height) {
143
+ mergedOptions.chart.height = config.size.height;
144
+ }
87
145
  }
88
- return mergedOptions
89
- }
146
+ return mergedOptions;
147
+ };
90
148
 
91
149
  var updateZoom = function (axis, modelAxis) {
92
150
  var extremes = axis.getExtremes();
93
151
  if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
94
152
  axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
95
153
  }
96
- }
154
+ };
97
155
 
98
- var processExtremes = function(chart, axis) {
156
+ var processExtremes = function(chart, axis, axisName) {
99
157
  if(axis.currentMin || axis.currentMax) {
100
- chart.xAxis[0].setExtremes(axis.currentMin, axis.currentMax, true);
101
- }
102
- }
103
-
104
- var processSeries = function(chart, series) {
105
- var ids = []
106
- if(series) {
107
- ensureIds(series);
108
-
109
- //Find series to add or update
110
- series.forEach(function (s) {
111
- ids.push(s.id)
112
- var chartSeries = chart.get(s.id);
113
- if (chartSeries) {
114
- chartSeries.update(angular.copy(s), false);
115
- } else {
116
- chart.addSeries(angular.copy(s), false)
117
- }
118
- });
119
- }
120
-
121
- //Now remove any missing series
122
- for(var i = chart.series.length - 1; i >= 0; i--) {
123
- var s = chart.series[i];
124
- if (ids.indexOf(s.options.id) < 0) {
125
- s.remove(false);
126
- }
127
- };
128
-
129
- }
130
-
131
- var initialiseChart = function(scope, element, config) {
132
- config || (config = {});
133
- var mergedOptions = getMergedOptions(scope, element, config);
134
- var chart = config.useHighStocks ? new Highcharts.StockChart(mergedOptions) : new Highcharts.Chart(mergedOptions);
135
- if(config.xAxis) {
136
- processExtremes(chart, config.xAxis);
137
- }
138
- processSeries(chart, config.series);
139
- if(config.loading) {
140
- chart.showLoading()
158
+ chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
141
159
  }
142
- chart.redraw();
143
- return chart;
144
- }
160
+ };
145
161
 
162
+ var chartOptionsWithoutEasyOptions = function (options) {
163
+ return angular.extend({}, options, {data: null, visible: null});
164
+ };
146
165
 
147
166
  return {
148
167
  restrict: 'EAC',
149
168
  replace: true,
150
169
  template: '<div></div>',
151
170
  scope: {
152
- config: '='
171
+ config: '=',
172
+ disableDataWatch: '='
153
173
  },
154
174
  link: function (scope, element, attrs) {
175
+ // We keep some chart-specific variables here as a closure
176
+ // instead of storing them on 'scope'.
155
177
 
156
- var chart = initialiseChart(scope, element, scope.config);
178
+ // prevSeriesOptions is maintained by processSeries
179
+ var prevSeriesOptions = {};
157
180
 
158
- scope.$watch("config.series", function (newSeries, oldSeries) {
159
- //do nothing when called on registration
160
- if (newSeries === oldSeries) return;
161
- processSeries(chart, newSeries);
162
- chart.redraw();
163
- }, true);
181
+ var processSeries = function(series) {
182
+ var i;
183
+ var ids = [];
184
+
185
+ if(series) {
186
+ var setIds = ensureIds(series);
187
+ if(setIds) {
188
+ //If we have set some ids this will trigger another digest cycle.
189
+ //In this scenario just return early and let the next cycle take care of changes
190
+ return false;
191
+ }
192
+
193
+ //Find series to add or update
194
+ angular.forEach(series, function(s) {
195
+ ids.push(s.id);
196
+ var chartSeries = chart.get(s.id);
197
+ if (chartSeries) {
198
+ if (!angular.equals(prevSeriesOptions[s.id], chartOptionsWithoutEasyOptions(s))) {
199
+ chartSeries.update(angular.copy(s), false);
200
+ } else {
201
+ if (s.visible !== undefined && chartSeries.visible !== s.visible) {
202
+ chartSeries.setVisible(s.visible, false);
203
+ }
204
+ chartSeries.setData(angular.copy(s.data), false);
205
+ }
206
+ } else {
207
+ chart.addSeries(angular.copy(s), false);
208
+ }
209
+ prevSeriesOptions[s.id] = chartOptionsWithoutEasyOptions(s);
210
+ });
211
+
212
+ // Shows no data text if all series are empty
213
+ if(scope.config.noData) {
214
+ var chartContainsData = false;
215
+
216
+ for(i = 0; i < series.length; i++) {
217
+ if (series[i].data && series[i].data.length > 0) {
218
+ chartContainsData = true;
219
+
220
+ break;
221
+ }
222
+ }
223
+
224
+ if (!chartContainsData) {
225
+ chart.showLoading(scope.config.noData);
226
+ } else {
227
+ chart.hideLoading();
228
+ }
229
+ }
230
+ }
231
+
232
+ //Now remove any missing series
233
+ for(i = chart.series.length - 1; i >= 0; i--) {
234
+ var s = chart.series[i];
235
+ if (s.options.id !== 'highcharts-navigator-series' && highchartsNGUtils.indexOf(ids, s.options.id) < 0) {
236
+ s.remove(false);
237
+ }
238
+ }
239
+
240
+ return true;
241
+ };
242
+
243
+ // chart is maintained by initChart
244
+ var chart = false;
245
+ var initChart = function() {
246
+ if (chart) chart.destroy();
247
+ prevSeriesOptions = {};
248
+ var config = scope.config || {};
249
+ var mergedOptions = getMergedOptions(scope, element, config);
250
+ var func = config.func || undefined;
251
+ chart = config.useHighStocks ?
252
+ new Highcharts.StockChart(mergedOptions, func) :
253
+ new Highcharts.Chart(mergedOptions, func);
254
+ for (var i = 0; i < axisNames.length; i++) {
255
+ if (config[axisNames[i]]) {
256
+ processExtremes(chart, config[axisNames[i]], axisNames[i]);
257
+ }
258
+ }
259
+ if(config.loading) {
260
+ chart.showLoading();
261
+ }
262
+
263
+ };
264
+ initChart();
265
+
266
+
267
+ if(scope.disableDataWatch){
268
+ scope.$watchCollection('config.series', function (newSeries, oldSeries) {
269
+ processSeries(newSeries);
270
+ chart.redraw();
271
+ });
272
+ } else {
273
+ scope.$watch('config.series', function (newSeries, oldSeries) {
274
+ var needsRedraw = processSeries(newSeries);
275
+ if(needsRedraw) {
276
+ chart.redraw();
277
+ }
278
+ }, true);
279
+ }
164
280
 
165
- scope.$watch("config.title", function (newTitle) {
281
+ scope.$watch('config.title', function (newTitle) {
166
282
  chart.setTitle(newTitle, true);
167
283
  }, true);
168
284
 
169
- scope.$watch("config.loading", function (loading) {
285
+ scope.$watch('config.subtitle', function (newSubtitle) {
286
+ chart.setTitle(true, newSubtitle);
287
+ }, true);
288
+
289
+ scope.$watch('config.loading', function (loading) {
170
290
  if(loading) {
171
- chart.showLoading()
291
+ chart.showLoading();
172
292
  } else {
173
- chart.hideLoading()
293
+ chart.hideLoading();
174
294
  }
175
295
  });
176
296
 
177
- scope.$watch("config.useHighStocks", function (useHighStocks) {
178
- chart.destroy();
179
- chart = initialiseChart(scope, element, scope.config);
297
+ scope.$watch('config.credits.enabled', function (enabled) {
298
+ if (enabled) {
299
+ chart.credits.show();
300
+ } else if (chart.credits) {
301
+ chart.credits.hide();
302
+ }
180
303
  });
181
304
 
182
- scope.$watch("config.xAxis", function (newAxes, oldAxes) {
183
- if (newAxes === oldAxes) return;
184
- if(newAxes) {
185
- chart.xAxis[0].update(newAxes);
186
- updateZoom(chart.xAxis[0], angular.copy(newAxes));
187
- chart.redraw();
188
- }
189
- }, true);
190
- scope.$watch("config.options", function (newOptions, oldOptions, scope) {
305
+ scope.$watch('config.useHighStocks', function (useHighStocks, oldUseHighStocks) {
306
+ if(useHighStocks === oldUseHighStocks) return;
307
+ initChart();
308
+ });
309
+
310
+ angular.forEach(axisNames, function(axisName) {
311
+ scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
312
+ if (newAxes === oldAxes) return;
313
+ if(newAxes) {
314
+ chart[axisName][0].update(newAxes, false);
315
+ updateZoom(chart[axisName][0], angular.copy(newAxes));
316
+ chart.redraw();
317
+ }
318
+ }, true);
319
+ });
320
+ scope.$watch('config.options', function (newOptions, oldOptions, scope) {
191
321
  //do nothing when called on registration
192
322
  if (newOptions === oldOptions) return;
193
- chart.destroy();
194
- chart = initialiseChart(scope, element, scope.config);
323
+ initChart();
324
+ processSeries(scope.config.series);
325
+ chart.redraw();
326
+ }, true);
195
327
 
328
+ scope.$watch('config.size', function (newSize, oldSize) {
329
+ if(newSize === oldSize) return;
330
+ if(newSize) {
331
+ chart.setSize(newSize.width || undefined, newSize.height || undefined);
332
+ }
196
333
  }, true);
334
+
335
+ scope.$on('highchartsng.reflow', function () {
336
+ chart.reflow();
337
+ });
338
+
339
+ scope.$on('$destroy', function() {
340
+ if (chart) {
341
+ chart.destroy();
342
+ setTimeout(function(){
343
+ element.remove();
344
+ }, 0);
345
+ }
346
+ });
347
+
197
348
  }
198
- }
199
- });
349
+ };
350
+ }
351
+
352
+ }());
@@ -1,3 +1,3 @@
1
1
  module HighchartsNG
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.7"
3
3
  end
metadata CHANGED
@@ -1,55 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: highcharts-ng-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iven Hsu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-01 00:00:00.000000000 Z
11
+ date: 2014-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.1'
55
55
  description: Gem that includes AngularJS directive for Highcharts (Interactive JavaScript
@@ -60,7 +60,7 @@ executables: []
60
60
  extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
- - .gitignore
63
+ - ".gitignore"
64
64
  - Gemfile
65
65
  - LICENSE
66
66
  - README.markdown
@@ -80,17 +80,17 @@ require_paths:
80
80
  - lib
81
81
  required_ruby_version: !ruby/object:Gem::Requirement
82
82
  requirements:
83
- - - '>='
83
+ - - ">="
84
84
  - !ruby/object:Gem::Version
85
85
  version: '0'
86
86
  required_rubygems_version: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - '>='
88
+ - - ">="
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
91
  requirements: []
92
92
  rubyforge_project:
93
- rubygems_version: 2.0.3
93
+ rubygems_version: 2.2.2
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: AngularJS directive for Highcharts