sidekiq-benchmark 0.6.0 → 0.7.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
- SHA1:
3
- metadata.gz: 6c898838a3feaf17b7341bddb15518de139bd15c
4
- data.tar.gz: 4dc7b3cf64d00f464cd201c63bd1c36fe238c0d7
2
+ SHA256:
3
+ metadata.gz: 9ff40d5ce3fb48bd55615763f3e3ac80512aa698f55b654f6c42bb028ee573e0
4
+ data.tar.gz: b430cac0a57e74485caaac5e9c726f2fb17de9f5637c3febd3f9925258da3c2d
5
5
  SHA512:
6
- metadata.gz: d15d44a724dbe9d1506fce8ef67407e76edefef1824df968d0a0aa15a86a9959cba9341103baa386de62849fe2bcd54ff6260df77c71174b134d252c3e473c09
7
- data.tar.gz: f3115064a2db5bf22b09f42131b97e92ddbacfdfd6011805eef4b3ab783a21e05bd6d255fc9fd757071e597f580769f8f0e14b5e850d24914d677d7fde8637fa
6
+ metadata.gz: 2f651f4b5349baea57d53f747a2813e349004521e628e82615a14f228b8ae5b5991e7d4603f1e0487068b02cfa44c89d2487402a848ffd590e0abc93c60f5b78
7
+ data.tar.gz: 985cc8dff35334d70e23121185fe7adc390145fdc237e9adccf423e9614f0a2e0e5616ed9cee94d55867ff4ff4ef88d95b100843291bb7307335c5488a7ea234
data/.gitignore CHANGED
@@ -18,3 +18,4 @@ spec/reports
18
18
  test/tmp
19
19
  test/version_tmp
20
20
  tmp
21
+ vendor/
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.2
4
- - 2.3.1
3
+ - 2.7.1
5
4
  services:
6
5
  - redis-server
@@ -0,0 +1,26 @@
1
+ .PHONY: test
2
+
3
+ DOCKER_CONSOLE := docker-compose run -w /app --rm console
4
+ PROJECT_NAME ?= $(shell basename $(shell pwd))
5
+
6
+ container:
7
+ mkdir -p gem/
8
+ mkdir -p vendor/
9
+ docker-compose build
10
+ $(DOCKER_CONSOLE) bundle install
11
+
12
+ bundle bundle_install bundle_update:
13
+ $(eval bundle_cmd ?= $(shell echo $@ | tr _ ' '))
14
+ $(DOCKER_CONSOLE) $(bundle_cmd)
15
+
16
+ build:
17
+ $(DOCKER_CONSOLE) gem build $(PROJECT_NAME).gemspec
18
+
19
+ clean:
20
+ $(DOCKER_CONSOLE) rm -fr gem/
21
+
22
+ test:
23
+ $(DOCKER_CONSOLE) bundle exec rake test
24
+
25
+ console:
26
+ $(DOCKER_CONSOLE)
@@ -0,0 +1,35 @@
1
+ version: '3.8'
2
+
3
+ x-logging: &logging
4
+ options:
5
+ max-size: '5k'
6
+ max-file: '5'
7
+ labels: "{{.Name}}"
8
+ driver: json-file
9
+
10
+ services:
11
+ app: &base
12
+ image: ruby:latest
13
+ environment: &app_env
14
+ - BUNDLE_PATH=/app/vendor
15
+ - REDIS_HOST=redis
16
+ volumes:
17
+ - .:/app:cached
18
+ - ./vendor:/app/vendor
19
+ - ./gem:/app/gem
20
+ - ~/.pry_history:/root/.pry_history
21
+ - ~/.bash_history:/root/.bash_history
22
+ links:
23
+ - redis:redis
24
+ logging: *logging
25
+
26
+ redis:
27
+ image: redis:alpine
28
+ logging: *logging
29
+
30
+ console:
31
+ <<: *base
32
+ command: bash
33
+
34
+ volumes:
35
+ vendor_cache:
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Benchmark
3
- VERSION = "0.6.0"
3
+ VERSION = "0.7.0"
4
4
  end
5
5
  end
@@ -12,12 +12,12 @@ class Sidekiq::Benchmark::TestingTest < Minitest::Spec
12
12
  it "save nothing to redis" do
13
13
  Sidekiq.redis do |conn|
14
14
  total_time = conn.hget(@worker.benchmark.redis_keys[:total], :job_time)
15
- total_time.must_be_nil
15
+ _(total_time).must_be_nil
16
16
  end
17
17
  end
18
18
 
19
19
  it "run code in bm blocks" do
20
- @worker.counter.wont_equal 0
20
+ _(@worker.counter).wont_equal 0
21
21
  end
22
22
  end
23
23
  end
@@ -16,36 +16,36 @@ module Sidekiq
16
16
 
17
17
  it "display index without stats" do
18
18
  get '/benchmarks'
19
- last_response.status.must_equal 200
19
+ _(last_response.status).must_equal 200
20
20
  end
21
21
 
22
22
  it "display index with stats" do
23
23
  WorkerMock.new
24
24
 
25
25
  get '/benchmarks'
26
- last_response.status.must_equal 200
26
+ _(last_response.status).must_equal 200
27
27
  end
28
28
 
29
29
  it "remove all benchmarks data" do
30
30
  WorkerMock.new
31
31
 
32
- Sidekiq.redis { |conn| conn.keys("benchmark:*").wont_be_empty }
32
+ Sidekiq.redis { |conn| _(conn.keys("benchmark:*")).wont_be_empty }
33
33
 
34
34
  post '/benchmarks/remove_all'
35
- last_response.status.must_equal 302
35
+ _(last_response.status).must_equal 302
36
36
 
37
- Sidekiq.redis { |conn| conn.keys("benchmark:*").must_be_empty }
37
+ Sidekiq.redis { |conn| _(conn.keys("benchmark:*")).must_be_empty }
38
38
  end
39
39
 
40
40
  it "remove benchmark data" do
41
41
  WorkerMock.new
42
42
 
43
- Sidekiq.redis { |conn| conn.keys("benchmark:sidekiq_benchmark_test_workermock:*").wont_be_empty }
43
+ Sidekiq.redis { |conn| _(conn.keys("benchmark:sidekiq_benchmark_test_workermock:*")).wont_be_empty }
44
44
 
45
45
  post '/benchmarks/remove', type: :sidekiq_benchmark_test_workermock
46
- last_response.status.must_equal 302
46
+ _(last_response.status).must_equal 302
47
47
 
48
- Sidekiq.redis { |conn| conn.keys("benchmark:sidekiq_benchmark_test_workermock:*").must_be_empty }
48
+ Sidekiq.redis { |conn| _(conn.keys("benchmark:sidekiq_benchmark_test_workermock:*")).must_be_empty }
49
49
  end
50
50
  end
51
51
  end
@@ -16,12 +16,12 @@ module Sidekiq
16
16
  metrics = @worker.benchmark.metrics
17
17
 
18
18
  @worker.metric_names.each do |metric_name|
19
- metrics[metric_name].wont_be_nil
19
+ _(metrics[metric_name]).wont_be_nil
20
20
  end
21
21
 
22
- @worker.benchmark.start_time.wont_be_nil
23
- @worker.benchmark.finish_time.wont_be_nil
24
- metrics[:assigned_metric].must_equal @worker.assigned_metric
22
+ _(@worker.benchmark.start_time).wont_be_nil
23
+ _(@worker.benchmark.finish_time).wont_be_nil
24
+ _(metrics[:assigned_metric]).must_equal @worker.assigned_metric
25
25
  end
26
26
 
27
27
  it 'should add up metrics' do
@@ -34,10 +34,10 @@ module Sidekiq
34
34
  it "should save metrics to redis" do
35
35
  Sidekiq.redis do |conn|
36
36
  total_time = conn.hget(@worker.benchmark.redis_keys[:total], :job_time)
37
- total_time.wont_be_nil
37
+ _(total_time).wont_be_nil
38
38
 
39
39
  metrics = conn.hkeys(@worker.benchmark.redis_keys[:stats])
40
- metrics.wont_be_empty
40
+ _(metrics).wont_be_empty
41
41
  end
42
42
  end
43
43
 
@@ -47,20 +47,20 @@ module Sidekiq
47
47
 
48
48
  Sidekiq.redis do |conn|
49
49
  metric_set = conn.hkeys(worker.benchmark.redis_keys[:stats])
50
- metric_set.must_be_empty
50
+ _(metric_set).must_be_empty
51
51
  end
52
52
 
53
53
  worker.metric_names.each do |metric_name|
54
- metrics[metric_name].wont_be_nil
54
+ _(metrics[metric_name]).wont_be_nil
55
55
  end
56
56
 
57
- worker.benchmark.finish_time.must_be_nil
57
+ _(worker.benchmark.finish_time).must_be_nil
58
58
  worker.finish
59
- worker.benchmark.finish_time.wont_be_nil
59
+ _(worker.benchmark.finish_time).wont_be_nil
60
60
 
61
61
  Sidekiq.redis do |conn|
62
62
  metric_set = conn.hkeys(worker.benchmark.redis_keys[:stats])
63
- metric_set.wont_be_empty
63
+ _(metric_set).wont_be_empty
64
64
  end
65
65
  end
66
66
 
@@ -68,8 +68,8 @@ module Sidekiq
68
68
  worker = AlterWorkerMock.new
69
69
  value = worker.benchmark.call(:multiply, 4, 4)
70
70
 
71
- value.must_equal 16
72
- worker.benchmark.metrics[:multiply].wont_be_nil
71
+ _(value).must_equal 16
72
+ _(worker.benchmark.metrics[:multiply]).wont_be_nil
73
73
  end
74
74
 
75
75
  end
@@ -18,7 +18,7 @@ require 'sidekiq-benchmark'
18
18
  require 'delorean'
19
19
  require 'pry'
20
20
 
21
- REDIS = Sidekiq::RedisConnection.create url: "redis://localhost/15"
21
+ REDIS = Sidekiq::RedisConnection.create url: "redis://#{ENV['REDIS_HOST'] || 'localhost'}/15"
22
22
  Bundler.require
23
23
 
24
24
  module Sidekiq
@@ -1,31 +1,37 @@
1
1
  /*
2
2
  * Chartkick.js
3
- * Create beautiful Javascript charts with minimal code
3
+ * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v1.0.2
5
+ * v3.2.1
6
6
  * MIT License
7
7
  */
8
8
 
9
- /*jslint browser: true, indent: 2, plusplus: true */
10
- /*global google, $*/
11
-
12
- (function() {
13
- 'use strict';
14
-
15
- // helpers
9
+ (function (global, factory) {
10
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
+ typeof define === 'function' && define.amd ? define(factory) :
12
+ (global = global || self, global.Chartkick = factory());
13
+ }(this, (function () { 'use strict';
16
14
 
17
15
  function isArray(variable) {
18
16
  return Object.prototype.toString.call(variable) === "[object Array]";
19
17
  }
20
18
 
19
+ function isFunction(variable) {
20
+ return variable instanceof Function;
21
+ }
22
+
21
23
  function isPlainObject(variable) {
22
- return variable instanceof Object;
24
+ // protect against prototype pollution, defense 2
25
+ return Object.prototype.toString.call(variable) === "[object Object]" && !isFunction(variable) && variable instanceof Object;
23
26
  }
24
27
 
25
28
  // https://github.com/madrobby/zepto/blob/master/src/zepto.js
26
29
  function extend(target, source) {
27
30
  var key;
28
31
  for (key in source) {
32
+ // protect against prototype pollution, defense 1
33
+ if (key === "__proto__") { continue; }
34
+
29
35
  if (isPlainObject(source[key]) || isArray(source[key])) {
30
36
  if (isPlainObject(source[key]) && !isPlainObject(target[key])) {
31
37
  target[key] = {};
@@ -34,8 +40,7 @@
34
40
  target[key] = [];
35
41
  }
36
42
  extend(target[key], source[key]);
37
- }
38
- else if (source[key] !== undefined) {
43
+ } else if (source[key] !== undefined) {
39
44
  target[key] = source[key];
40
45
  }
41
46
  }
@@ -48,20 +53,23 @@
48
53
  return target;
49
54
  }
50
55
 
56
+ var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
57
+
51
58
  // https://github.com/Do/iso8601.js
52
- var ISO8601_PATTERN = /(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([\.,]\d+)?($|Z|([\+\-])(\d\d)(:)?(\d\d)?)/i;
59
+ var ISO8601_PATTERN = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([.,]\d+)?($|Z|([+-])(\d\d)(:)?(\d\d)?)/i;
53
60
  var DECIMAL_SEPARATOR = String(1.5).charAt(1);
54
61
 
55
62
  function parseISO8601(input) {
56
63
  var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
57
64
  type = Object.prototype.toString.call(input);
58
- if (type === '[object Date]') {
65
+ if (type === "[object Date]") {
59
66
  return input;
60
67
  }
61
- if (type !== '[object String]') {
68
+ if (type !== "[object String]") {
62
69
  return;
63
70
  }
64
- if (matches = input.match(ISO8601_PATTERN)) {
71
+ matches = input.match(ISO8601_PATTERN);
72
+ if (matches) {
65
73
  year = parseInt(matches[1], 10);
66
74
  month = parseInt(matches[3], 10) - 1;
67
75
  day = parseInt(matches[5], 10);
@@ -75,7 +83,7 @@
75
83
  if (matches[17]) {
76
84
  offset += parseInt(matches[17], 10);
77
85
  }
78
- offset *= matches[14] === '-' ? -1 : 1;
86
+ offset *= matches[14] === "-" ? -1 : 1;
79
87
  result -= offset * 60 * 1000;
80
88
  }
81
89
  return new Date(result);
@@ -96,29 +104,92 @@
96
104
  return false;
97
105
  }
98
106
 
99
- function jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax) {
100
- return function(series, opts) {
107
+ function toStr(n) {
108
+ return "" + n;
109
+ }
110
+
111
+ function toFloat(n) {
112
+ return parseFloat(n);
113
+ }
114
+
115
+ function toDate(n) {
116
+ var matches, year, month, day;
117
+ if (typeof n !== "object") {
118
+ if (typeof n === "number") {
119
+ n = new Date(n * 1000); // ms
120
+ } else {
121
+ n = toStr(n);
122
+ if ((matches = n.match(DATE_PATTERN))) {
123
+ year = parseInt(matches[1], 10);
124
+ month = parseInt(matches[3], 10) - 1;
125
+ day = parseInt(matches[5], 10);
126
+ return new Date(year, month, day);
127
+ } else { // str
128
+ // try our best to get the str into iso8601
129
+ // TODO be smarter about this
130
+ var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
131
+ n = parseISO8601(str) || new Date(n);
132
+ }
133
+ }
134
+ }
135
+ return n;
136
+ }
137
+
138
+ function toArr(n) {
139
+ if (!isArray(n)) {
140
+ var arr = [], i;
141
+ for (i in n) {
142
+ if (n.hasOwnProperty(i)) {
143
+ arr.push([i, n[i]]);
144
+ }
145
+ }
146
+ n = arr;
147
+ }
148
+ return n;
149
+ }
150
+
151
+ function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
152
+ return function (chart, opts, chartOptions) {
153
+ var series = chart.data;
101
154
  var options = merge({}, defaultOptions);
155
+ options = merge(options, chartOptions || {});
156
+
157
+ if (chart.hideLegend || "legend" in opts) {
158
+ hideLegend(options, opts.legend, chart.hideLegend);
159
+ }
102
160
 
103
- // hide legend
104
- // this is *not* an external option!
105
- if (opts.hideLegend) {
106
- hideLegend(options);
161
+ if (opts.title) {
162
+ setTitle(options, opts.title);
107
163
  }
108
164
 
109
165
  // min
110
166
  if ("min" in opts) {
111
167
  setMin(options, opts.min);
112
- }
113
- else if (!negativeValues(series)) {
168
+ } else if (!negativeValues(series)) {
114
169
  setMin(options, 0);
115
170
  }
116
171
 
117
172
  // max
118
- if ("max" in opts) {
173
+ if (opts.max) {
119
174
  setMax(options, opts.max);
120
175
  }
121
176
 
177
+ if ("stacked" in opts) {
178
+ setStacked(options, opts.stacked);
179
+ }
180
+
181
+ if (opts.colors) {
182
+ options.colors = opts.colors;
183
+ }
184
+
185
+ if (opts.xtitle) {
186
+ setXtitle(options, opts.xtitle);
187
+ }
188
+
189
+ if (opts.ytitle) {
190
+ setYtitle(options, opts.ytitle);
191
+ }
192
+
122
193
  // merge library last
123
194
  options = merge(options, opts.library || {});
124
195
 
@@ -126,422 +197,2268 @@
126
197
  };
127
198
  }
128
199
 
129
- // only functions that need defined specific to charting library
130
- var renderLineChart, renderPieChart, renderColumnChart;
200
+ function sortByTime(a, b) {
201
+ return a[0].getTime() - b[0].getTime();
202
+ }
203
+
204
+ function sortByNumberSeries(a, b) {
205
+ return a[0] - b[0];
206
+ }
207
+
208
+ function sortByNumber(a, b) {
209
+ return a - b;
210
+ }
211
+
212
+ function isMinute(d) {
213
+ return d.getMilliseconds() === 0 && d.getSeconds() === 0;
214
+ }
215
+
216
+ function isHour(d) {
217
+ return isMinute(d) && d.getMinutes() === 0;
218
+ }
219
+
220
+ function isDay(d) {
221
+ return isHour(d) && d.getHours() === 0;
222
+ }
223
+
224
+ function isWeek(d, dayOfWeek) {
225
+ return isDay(d) && d.getDay() === dayOfWeek;
226
+ }
227
+
228
+ function isMonth(d) {
229
+ return isDay(d) && d.getDate() === 1;
230
+ }
231
+
232
+ function isYear(d) {
233
+ return isMonth(d) && d.getMonth() === 0;
234
+ }
235
+
236
+ function isDate(obj) {
237
+ return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
238
+ }
239
+
240
+ function isNumber(obj) {
241
+ return typeof obj === "number";
242
+ }
243
+
244
+ var byteSuffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB"];
245
+
246
+ function formatValue(pre, value, options, axis) {
247
+ pre = pre || "";
248
+ if (options.prefix) {
249
+ if (value < 0) {
250
+ value = value * -1;
251
+ pre += "-";
252
+ }
253
+ pre += options.prefix;
254
+ }
131
255
 
132
- if ("Highcharts" in window) {
256
+ var suffix = options.suffix || "";
257
+ var precision = options.precision;
258
+ var round = options.round;
259
+
260
+ if (options.byteScale) {
261
+ var suffixIdx;
262
+ var baseValue = axis ? options.byteScale : value;
263
+
264
+ if (baseValue >= 1152921504606846976) {
265
+ value /= 1152921504606846976;
266
+ suffixIdx = 6;
267
+ } else if (baseValue >= 1125899906842624) {
268
+ value /= 1125899906842624;
269
+ suffixIdx = 5;
270
+ } else if (baseValue >= 1099511627776) {
271
+ value /= 1099511627776;
272
+ suffixIdx = 4;
273
+ } else if (baseValue >= 1073741824) {
274
+ value /= 1073741824;
275
+ suffixIdx = 3;
276
+ } else if (baseValue >= 1048576) {
277
+ value /= 1048576;
278
+ suffixIdx = 2;
279
+ } else if (baseValue >= 1024) {
280
+ value /= 1024;
281
+ suffixIdx = 1;
282
+ } else {
283
+ suffixIdx = 0;
284
+ }
133
285
 
134
- var defaultOptions = {
135
- xAxis: {
136
- labels: {
137
- style: {
138
- fontSize: "12px"
286
+ // TODO handle manual precision case
287
+ if (precision === undefined && round === undefined) {
288
+ if (value >= 1023.5) {
289
+ if (suffixIdx < byteSuffixes.length - 1) {
290
+ value = 1.0;
291
+ suffixIdx += 1;
139
292
  }
140
293
  }
141
- },
142
- yAxis: {
143
- title: {
144
- text: null
145
- },
146
- labels: {
147
- style: {
148
- fontSize: "12px"
149
- }
294
+ precision = value >= 1000 ? 4 : 3;
295
+ }
296
+ suffix = " " + byteSuffixes[suffixIdx];
297
+ }
298
+
299
+ if (precision !== undefined && round !== undefined) {
300
+ throw Error("Use either round or precision, not both");
301
+ }
302
+
303
+ if (!axis) {
304
+ if (precision !== undefined) {
305
+ value = value.toPrecision(precision);
306
+ if (!options.zeros) {
307
+ value = parseFloat(value);
150
308
  }
151
- },
152
- title: {
153
- text: null
154
- },
155
- credits: {
156
- enabled: false
157
- },
158
- legend: {
159
- borderWidth: 0
160
- },
161
- tooltip: {
162
- style: {
163
- fontSize: "12px"
309
+ }
310
+
311
+ if (round !== undefined) {
312
+ if (round < 0) {
313
+ var num = Math.pow(10, -1 * round);
314
+ value = parseInt((1.0 * value / num).toFixed(0)) * num;
315
+ } else {
316
+ value = value.toFixed(round);
317
+ if (!options.zeros) {
318
+ value = parseFloat(value);
319
+ }
164
320
  }
165
321
  }
166
- };
322
+ }
167
323
 
168
- var hideLegend = function(options) {
169
- options.legend.enabled = false;
170
- };
324
+ if (options.thousands || options.decimal) {
325
+ value = toStr(value);
326
+ var parts = value.split(".");
327
+ value = parts[0];
328
+ if (options.thousands) {
329
+ value = value.replace(/\B(?=(\d{3})+(?!\d))/g, options.thousands);
330
+ }
331
+ if (parts.length > 1) {
332
+ value += (options.decimal || ".") + parts[1];
333
+ }
334
+ }
171
335
 
172
- var setMin = function(options, min) {
173
- options.yAxis.min = min;
174
- };
336
+ return pre + value + suffix;
337
+ }
175
338
 
176
- var setMax = function(options, max) {
177
- options.yAxis.max = max;
178
- };
339
+ function seriesOption(chart, series, option) {
340
+ if (option in series) {
341
+ return series[option];
342
+ } else if (option in chart.options) {
343
+ return chart.options[option];
344
+ }
345
+ return null;
346
+ }
179
347
 
180
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax);
348
+ function allZeros(data) {
349
+ var i, j, d;
350
+ for (i = 0; i < data.length; i++) {
351
+ d = data[i].data;
352
+ for (j = 0; j < d.length; j++) {
353
+ if (d[j][1] != 0) {
354
+ return false;
355
+ }
356
+ }
357
+ }
358
+ return true;
359
+ }
181
360
 
182
- renderLineChart = function(element, series, opts) {
183
- var options = jsOptions(series, opts), data, i, j;
184
- options.xAxis.type = "datetime";
185
- options.chart = {type: "spline", renderTo: element.id};
361
+ var baseOptions = {
362
+ maintainAspectRatio: false,
363
+ animation: false,
364
+ tooltips: {
365
+ displayColors: false,
366
+ callbacks: {}
367
+ },
368
+ legend: {},
369
+ title: {fontSize: 20, fontColor: "#333"}
370
+ };
186
371
 
187
- for (i = 0; i < series.length; i++) {
188
- data = series[i].data;
189
- for (j = 0; j < data.length; j++) {
190
- data[j][0] = data[j][0].getTime();
372
+ var defaultOptions = {
373
+ scales: {
374
+ yAxes: [
375
+ {
376
+ ticks: {
377
+ maxTicksLimit: 4
378
+ },
379
+ scaleLabel: {
380
+ fontSize: 16,
381
+ // fontStyle: "bold",
382
+ fontColor: "#333"
383
+ }
384
+ }
385
+ ],
386
+ xAxes: [
387
+ {
388
+ gridLines: {
389
+ drawOnChartArea: false
390
+ },
391
+ scaleLabel: {
392
+ fontSize: 16,
393
+ // fontStyle: "bold",
394
+ fontColor: "#333"
395
+ },
396
+ time: {},
397
+ ticks: {}
191
398
  }
192
- series[i].marker = {symbol: "circle"};
399
+ ]
400
+ }
401
+ };
402
+
403
+ // http://there4.io/2012/05/02/google-chart-color-list/
404
+ var defaultColors = [
405
+ "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6",
406
+ "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11",
407
+ "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
408
+ ];
409
+
410
+ var hideLegend = function (options, legend, hideLegend) {
411
+ if (legend !== undefined) {
412
+ options.legend.display = !!legend;
413
+ if (legend && legend !== true) {
414
+ options.legend.position = legend;
193
415
  }
194
- options.series = series;
195
- new Highcharts.Chart(options);
196
- };
416
+ } else if (hideLegend) {
417
+ options.legend.display = false;
418
+ }
419
+ };
197
420
 
198
- renderPieChart = function(element, series, opts) {
199
- var options = merge(defaultOptions, opts.library || {});
200
- options.chart = {renderTo: element.id};
201
- options.series = [{
202
- type: "pie",
203
- name: "Value",
204
- data: series
205
- }];
206
- new Highcharts.Chart(options);
207
- };
421
+ var setTitle = function (options, title) {
422
+ options.title.display = true;
423
+ options.title.text = title;
424
+ };
208
425
 
209
- renderColumnChart = function(element, series, opts) {
210
- var options = jsOptions(series, opts), i, j, s, d, rows = [];
211
- options.chart = {type: "column", renderTo: element.id};
426
+ var setMin = function (options, min) {
427
+ if (min !== null) {
428
+ options.scales.yAxes[0].ticks.min = toFloat(min);
429
+ }
430
+ };
212
431
 
213
- for (i = 0; i < series.length; i++) {
214
- s = series[i];
432
+ var setMax = function (options, max) {
433
+ options.scales.yAxes[0].ticks.max = toFloat(max);
434
+ };
215
435
 
216
- for (j = 0; j < s.data.length; j++) {
217
- d = s.data[j];
218
- if (!rows[d[0]]) {
219
- rows[d[0]] = new Array(series.length);
220
- }
221
- rows[d[0]][i] = d[1];
222
- }
223
- }
436
+ var setBarMin = function (options, min) {
437
+ if (min !== null) {
438
+ options.scales.xAxes[0].ticks.min = toFloat(min);
439
+ }
440
+ };
441
+
442
+ var setBarMax = function (options, max) {
443
+ options.scales.xAxes[0].ticks.max = toFloat(max);
444
+ };
445
+
446
+ var setStacked = function (options, stacked) {
447
+ options.scales.xAxes[0].stacked = !!stacked;
448
+ options.scales.yAxes[0].stacked = !!stacked;
449
+ };
224
450
 
225
- var categories = [];
226
- for (i in rows) {
227
- if (rows.hasOwnProperty(i)) {
228
- categories.push(i);
451
+ var setXtitle = function (options, title) {
452
+ options.scales.xAxes[0].scaleLabel.display = true;
453
+ options.scales.xAxes[0].scaleLabel.labelString = title;
454
+ };
455
+
456
+ var setYtitle = function (options, title) {
457
+ options.scales.yAxes[0].scaleLabel.display = true;
458
+ options.scales.yAxes[0].scaleLabel.labelString = title;
459
+ };
460
+
461
+ // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
462
+ var addOpacity = function(hex, opacity) {
463
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
464
+ return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
465
+ };
466
+
467
+ // check if not null or undefined
468
+ // https://stackoverflow.com/a/27757708/1177228
469
+ var notnull = function(x) {
470
+ return x != null;
471
+ };
472
+
473
+ var setLabelSize = function (chart, data, options) {
474
+ var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
475
+ if (maxLabelSize > 25) {
476
+ maxLabelSize = 25;
477
+ } else if (maxLabelSize < 10) {
478
+ maxLabelSize = 10;
479
+ }
480
+ if (!options.scales.xAxes[0].ticks.callback) {
481
+ options.scales.xAxes[0].ticks.callback = function (value) {
482
+ value = toStr(value);
483
+ if (value.length > maxLabelSize) {
484
+ return value.substring(0, maxLabelSize - 2) + "...";
485
+ } else {
486
+ return value;
229
487
  }
488
+ };
489
+ }
490
+ };
491
+
492
+ var setFormatOptions = function(chart, options, chartType) {
493
+ var formatOptions = {
494
+ prefix: chart.options.prefix,
495
+ suffix: chart.options.suffix,
496
+ thousands: chart.options.thousands,
497
+ decimal: chart.options.decimal,
498
+ precision: chart.options.precision,
499
+ round: chart.options.round,
500
+ zeros: chart.options.zeros
501
+ };
502
+
503
+ if (chart.options.bytes) {
504
+ var series = chart.data;
505
+ if (chartType === "pie") {
506
+ series = [{data: series}];
230
507
  }
231
- options.xAxis.categories = categories;
232
508
 
233
- var newSeries = [];
234
- for (i = 0; i < series.length; i++) {
235
- d = [];
236
- for (j = 0; j < categories.length; j++) {
237
- d.push(rows[categories[j]][i]);
509
+ // calculate max
510
+ var max = 0;
511
+ for (var i = 0; i < series.length; i++) {
512
+ var s = series[i];
513
+ for (var j = 0; j < s.data.length; j++) {
514
+ if (s.data[j][1] > max) {
515
+ max = s.data[j][1];
516
+ }
238
517
  }
518
+ }
239
519
 
240
- newSeries.push({
241
- name: series[i].name,
242
- data: d
243
- });
520
+ // calculate scale
521
+ var scale = 1;
522
+ while (max >= 1024) {
523
+ scale *= 1024;
524
+ max /= 1024;
244
525
  }
245
- options.series = newSeries;
246
526
 
247
- new Highcharts.Chart(options);
248
- };
249
- } else if ("google" in window) { // Google charts
250
- // load from google
251
- var loaded = false;
252
- google.setOnLoadCallback(function() {
253
- loaded = true;
254
- });
255
- google.load("visualization", "1.0", {"packages": ["corechart"]});
527
+ // set step size
528
+ formatOptions.byteScale = scale;
529
+ }
256
530
 
257
- var waitForLoaded = function(callback) {
258
- google.setOnLoadCallback(callback); // always do this to prevent race conditions (watch out for other issues due to this)
259
- if (loaded) {
260
- callback();
531
+ if (chartType !== "pie") {
532
+ var myAxes = options.scales.yAxes;
533
+ if (chartType === "bar") {
534
+ myAxes = options.scales.xAxes;
261
535
  }
262
- };
263
536
 
264
- // Set chart options
265
- var defaultOptions = {
266
- fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
267
- pointSize: 6,
268
- legend: {
269
- textStyle: {
270
- fontSize: 12,
271
- color: "#444"
272
- },
273
- alignment: "center",
274
- position: "right"
275
- },
276
- curveType: "function",
277
- hAxis: {
278
- textStyle: {
279
- color: "#666",
280
- fontSize: 12
281
- },
282
- gridlines: {
283
- color: "transparent"
284
- },
285
- baselineColor: "#ccc"
286
- },
287
- vAxis: {
288
- textStyle: {
289
- color: "#666",
290
- fontSize: 12
291
- },
292
- baselineColor: "#ccc",
293
- viewWindow: {}
294
- },
295
- tooltip: {
296
- textStyle: {
297
- color: "#666",
298
- fontSize: 12
537
+ if (formatOptions.byteScale) {
538
+ if (!myAxes[0].ticks.stepSize) {
539
+ myAxes[0].ticks.stepSize = formatOptions.byteScale / 2;
540
+ }
541
+ if (!myAxes[0].ticks.maxTicksLimit) {
542
+ myAxes[0].ticks.maxTicksLimit = 4;
299
543
  }
300
544
  }
301
- };
302
545
 
303
- var hideLegend = function(options) {
304
- options.legend.position = "none";
305
- };
546
+ if (!myAxes[0].ticks.callback) {
547
+ myAxes[0].ticks.callback = function (value) {
548
+ return formatValue("", value, formatOptions, true);
549
+ };
550
+ }
551
+ }
306
552
 
307
- var setMin = function(options, min) {
308
- options.vAxis.viewWindow.min = min;
309
- };
553
+ if (!options.tooltips.callbacks.label) {
554
+ if (chartType === "scatter") {
555
+ options.tooltips.callbacks.label = function (item, data) {
556
+ var label = data.datasets[item.datasetIndex].label || '';
557
+ if (label) {
558
+ label += ': ';
559
+ }
560
+ return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
561
+ };
562
+ } else if (chartType === "bubble") {
563
+ options.tooltips.callbacks.label = function (item, data) {
564
+ var label = data.datasets[item.datasetIndex].label || '';
565
+ if (label) {
566
+ label += ': ';
567
+ }
568
+ var dataPoint = data.datasets[item.datasetIndex].data[item.index];
569
+ return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')';
570
+ };
571
+ } else if (chartType === "pie") {
572
+ // need to use separate label for pie charts
573
+ options.tooltips.callbacks.label = function (tooltipItem, data) {
574
+ var dataLabel = data.labels[tooltipItem.index];
575
+ var value = ': ';
576
+
577
+ if (isArray(dataLabel)) {
578
+ // show value on first line of multiline label
579
+ // need to clone because we are changing the value
580
+ dataLabel = dataLabel.slice();
581
+ dataLabel[0] += value;
582
+ } else {
583
+ dataLabel += value;
584
+ }
310
585
 
311
- var setMax = function(options, max) {
312
- options.vAxis.viewWindow.max = max;
313
- };
586
+ return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
587
+ };
588
+ } else {
589
+ var valueLabel = chartType === "bar" ? "xLabel" : "yLabel";
590
+ options.tooltips.callbacks.label = function (tooltipItem, data) {
591
+ var label = data.datasets[tooltipItem.datasetIndex].label || '';
592
+ if (label) {
593
+ label += ': ';
594
+ }
595
+ return formatValue(label, tooltipItem[valueLabel], formatOptions);
596
+ };
597
+ }
598
+ }
599
+ };
600
+
601
+ var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
602
+
603
+ var createDataTable = function (chart, options, chartType, library) {
604
+ var datasets = [];
605
+ var labels = [];
606
+
607
+ var colors = chart.options.colors || defaultColors;
608
+
609
+ var day = true;
610
+ var week = true;
611
+ var dayOfWeek;
612
+ var month = true;
613
+ var year = true;
614
+ var hour = true;
615
+ var minute = true;
616
+
617
+ var series = chart.data;
618
+
619
+ var max = 0;
620
+ if (chartType === "bubble") {
621
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
622
+ var s$1 = series[i$1];
623
+ for (var j$1 = 0; j$1 < s$1.data.length; j$1++) {
624
+ if (s$1.data[j$1][2] > max) {
625
+ max = s$1.data[j$1][2];
626
+ }
627
+ }
628
+ }
629
+ }
314
630
 
315
- var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax);
631
+ var i, j, s, d, key, rows = [], rows2 = [];
316
632
 
317
- // cant use object as key
318
- var createDataTable = function(series, columnType) {
319
- var data = new google.visualization.DataTable();
320
- data.addColumn(columnType, "");
633
+ if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
634
+ var sortedLabels = [];
321
635
 
322
- var i, j, s, d, key, rows = [];
323
636
  for (i = 0; i < series.length; i++) {
324
637
  s = series[i];
325
- data.addColumn("number", s.name);
326
638
 
327
639
  for (j = 0; j < s.data.length; j++) {
328
640
  d = s.data[j];
329
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
641
+ key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
330
642
  if (!rows[key]) {
331
643
  rows[key] = new Array(series.length);
332
644
  }
333
645
  rows[key][i] = toFloat(d[1]);
646
+ if (sortedLabels.indexOf(key) === -1) {
647
+ sortedLabels.push(key);
648
+ }
334
649
  }
335
650
  }
336
651
 
337
- var rows2 = [];
338
- for (i in rows) {
339
- if (rows.hasOwnProperty(i)) {
340
- rows2.push([(columnType === "datetime") ? new Date(toFloat(i)) : i].concat(rows[i]));
652
+ if (chart.xtype === "datetime" || chart.xtype === "number") {
653
+ sortedLabels.sort(sortByNumber);
654
+ }
655
+
656
+ for (j = 0; j < series.length; j++) {
657
+ rows2.push([]);
658
+ }
659
+
660
+ var value;
661
+ var k;
662
+ for (k = 0; k < sortedLabels.length; k++) {
663
+ i = sortedLabels[k];
664
+ if (chart.xtype === "datetime") {
665
+ value = new Date(toFloat(i));
666
+ // TODO make this efficient
667
+ day = day && isDay(value);
668
+ if (!dayOfWeek) {
669
+ dayOfWeek = value.getDay();
670
+ }
671
+ week = week && isWeek(value, dayOfWeek);
672
+ month = month && isMonth(value);
673
+ year = year && isYear(value);
674
+ hour = hour && isHour(value);
675
+ minute = minute && isMinute(value);
676
+ } else {
677
+ value = i;
678
+ }
679
+ labels.push(value);
680
+ for (j = 0; j < series.length; j++) {
681
+ // Chart.js doesn't like undefined
682
+ rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
341
683
  }
342
684
  }
343
- if (columnType === "datetime") {
344
- rows2.sort(sortByTime);
685
+ } else {
686
+ for (var i$2 = 0; i$2 < series.length; i$2++) {
687
+ var s$2 = series[i$2];
688
+ var d$1 = [];
689
+ for (var j$2 = 0; j$2 < s$2.data.length; j$2++) {
690
+ var point = {
691
+ x: toFloat(s$2.data[j$2][0]),
692
+ y: toFloat(s$2.data[j$2][1])
693
+ };
694
+ if (chartType === "bubble") {
695
+ point.r = toFloat(s$2.data[j$2][2]) * 20 / max;
696
+ // custom attribute, for tooltip
697
+ point.v = s$2.data[j$2][2];
698
+ }
699
+ d$1.push(point);
700
+ }
701
+ rows2.push(d$1);
345
702
  }
703
+ }
346
704
 
347
- data.addRows(rows2);
705
+ for (i = 0; i < series.length; i++) {
706
+ s = series[i];
707
+
708
+ var color = s.color || colors[i];
709
+ var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
710
+
711
+ var dataset = {
712
+ label: s.name || "",
713
+ data: rows2[i],
714
+ fill: chartType === "area",
715
+ borderColor: color,
716
+ backgroundColor: backgroundColor,
717
+ pointBackgroundColor: color,
718
+ borderWidth: 2,
719
+ pointHoverBackgroundColor: color
720
+ };
721
+
722
+ if (s.stack) {
723
+ dataset.stack = s.stack;
724
+ }
348
725
 
349
- return data;
350
- };
726
+ var curve = seriesOption(chart, s, "curve");
727
+ if (curve === false) {
728
+ dataset.lineTension = 0;
729
+ }
351
730
 
352
- renderLineChart = function(element, series, opts) {
353
- waitForLoaded(function() {
354
- var options = jsOptions(series, opts);
355
- var data = createDataTable(series, "datetime");
356
- var chart = new google.visualization.LineChart(element);
357
- chart.draw(data, options);
358
- });
359
- };
731
+ var points = seriesOption(chart, s, "points");
732
+ if (points === false) {
733
+ dataset.pointRadius = 0;
734
+ dataset.pointHitRadius = 5;
735
+ }
360
736
 
361
- renderPieChart = function(element, series, opts) {
362
- waitForLoaded(function() {
363
- var options = merge(defaultOptions, opts.library || {});
364
- options.chartArea = {
365
- top: "10%",
366
- height: "80%"
367
- };
737
+ dataset = merge(dataset, chart.options.dataset || {});
738
+ dataset = merge(dataset, s.library || {});
739
+ dataset = merge(dataset, s.dataset || {});
368
740
 
369
- var data = new google.visualization.DataTable();
370
- data.addColumn("string", "");
371
- data.addColumn("number", "Value");
372
- data.addRows(series);
741
+ datasets.push(dataset);
742
+ }
373
743
 
374
- var chart = new google.visualization.PieChart(element);
375
- chart.draw(data, options);
376
- });
377
- };
744
+ var xmin = chart.options.xmin;
745
+ var xmax = chart.options.xmax;
378
746
 
379
- renderColumnChart = function(element, series, opts) {
380
- waitForLoaded(function() {
381
- var options = jsOptions(series, opts);
382
- var data = createDataTable(series, "string");
383
- var chart = new google.visualization.ColumnChart(element);
384
- chart.draw(data, options);
385
- });
386
- };
387
- } else { // no chart library installed
388
- renderLineChart = renderPieChart = renderColumnChart = function() {
389
- throw new Error("Please install Google Charts or Highcharts");
390
- };
391
- }
747
+ if (chart.xtype === "datetime") {
748
+ // hacky check for Chart.js >= 2.9.0
749
+ // https://github.com/chartjs/Chart.js/compare/v2.8.0...v2.9.0
750
+ var gte29 = "math" in library.helpers;
751
+ var ticksKey = gte29 ? "ticks" : "time";
752
+ if (notnull(xmin)) {
753
+ options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime();
754
+ }
755
+ if (notnull(xmax)) {
756
+ options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime();
757
+ }
758
+ } else if (chart.xtype === "number") {
759
+ if (notnull(xmin)) {
760
+ options.scales.xAxes[0].ticks.min = xmin;
761
+ }
762
+ if (notnull(xmax)) {
763
+ options.scales.xAxes[0].ticks.max = xmax;
764
+ }
765
+ }
392
766
 
393
- function setText(element, text) {
394
- if (document.body.innerText) {
395
- element.innerText = text;
396
- } else {
397
- element.textContent = text;
767
+ // for empty datetime chart
768
+ if (chart.xtype === "datetime" && labels.length === 0) {
769
+ if (notnull(xmin)) {
770
+ labels.push(toDate(xmin));
771
+ }
772
+ if (notnull(xmax)) {
773
+ labels.push(toDate(xmax));
774
+ }
775
+ day = false;
776
+ week = false;
777
+ month = false;
778
+ year = false;
779
+ hour = false;
780
+ minute = false;
398
781
  }
399
- }
400
782
 
401
- function chartError(element, message) {
402
- setText(element, "Error Loading Chart: " + message);
403
- element.style.color = "#ff0000";
404
- }
783
+ if (chart.xtype === "datetime" && labels.length > 0) {
784
+ var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
785
+ var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
405
786
 
406
- function getJSON(element, url, success) {
407
- $.ajax({
408
- dataType: "json",
409
- url: url,
410
- success: success,
411
- error: function(jqXHR, textStatus, errorThrown) {
412
- var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
413
- chartError(element, message);
787
+ for (i = 1; i < labels.length; i++) {
788
+ var value$1 = labels[i].getTime();
789
+ if (value$1 < minTime) {
790
+ minTime = value$1;
791
+ }
792
+ if (value$1 > maxTime) {
793
+ maxTime = value$1;
794
+ }
414
795
  }
415
- });
416
- }
417
796
 
418
- function errorCatcher(element, data, opts, callback) {
419
- try {
420
- callback(element, data, opts);
421
- } catch (err) {
422
- chartError(element, err.message);
423
- throw err;
797
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
798
+
799
+ if (!options.scales.xAxes[0].time.unit) {
800
+ var step;
801
+ if (year || timeDiff > 365 * 10) {
802
+ options.scales.xAxes[0].time.unit = "year";
803
+ step = 365;
804
+ } else if (month || timeDiff > 30 * 10) {
805
+ options.scales.xAxes[0].time.unit = "month";
806
+ step = 30;
807
+ } else if (day || timeDiff > 10) {
808
+ options.scales.xAxes[0].time.unit = "day";
809
+ step = 1;
810
+ } else if (hour || timeDiff > 0.5) {
811
+ options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"};
812
+ options.scales.xAxes[0].time.unit = "hour";
813
+ step = 1 / 24.0;
814
+ } else if (minute) {
815
+ options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"};
816
+ options.scales.xAxes[0].time.unit = "minute";
817
+ step = 1 / 24.0 / 60.0;
818
+ }
819
+
820
+ if (step && timeDiff > 0) {
821
+ var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
822
+ if (week && step === 1) {
823
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
824
+ }
825
+ options.scales.xAxes[0].time.unitStepSize = unitStepSize;
826
+ }
827
+ }
828
+
829
+ if (!options.scales.xAxes[0].time.tooltipFormat) {
830
+ if (day) {
831
+ options.scales.xAxes[0].time.tooltipFormat = "ll";
832
+ } else if (hour) {
833
+ options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
834
+ } else if (minute) {
835
+ options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
836
+ }
837
+ }
838
+ }
839
+
840
+ var data = {
841
+ labels: labels,
842
+ datasets: datasets
843
+ };
844
+
845
+ return data;
846
+ };
847
+
848
+ var defaultExport = function defaultExport(library) {
849
+ this.name = "chartjs";
850
+ this.library = library;
851
+ };
852
+
853
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) {
854
+ var chartOptions = {};
855
+ // fix for https://github.com/chartjs/Chart.js/issues/2441
856
+ if (!chart.options.max && allZeros(chart.data)) {
857
+ chartOptions.max = 1;
858
+ }
859
+
860
+ var options = jsOptions(chart, merge(chartOptions, chart.options));
861
+ setFormatOptions(chart, options, chartType);
862
+
863
+ var data = createDataTable(chart, options, chartType || "line", this.library);
864
+
865
+ if (chart.xtype === "number") {
866
+ options.scales.xAxes[0].type = "linear";
867
+ options.scales.xAxes[0].position = "bottom";
868
+ } else {
869
+ options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
870
+ }
871
+
872
+ this.drawChart(chart, "line", data, options);
873
+ };
874
+
875
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
876
+ var options = merge({}, baseOptions);
877
+ if (chart.options.donut) {
878
+ options.cutoutPercentage = 50;
879
+ }
880
+
881
+ if ("legend" in chart.options) {
882
+ hideLegend(options, chart.options.legend);
883
+ }
884
+
885
+ if (chart.options.title) {
886
+ setTitle(options, chart.options.title);
887
+ }
888
+
889
+ options = merge(options, chart.options.library || {});
890
+ setFormatOptions(chart, options, "pie");
891
+
892
+ var labels = [];
893
+ var values = [];
894
+ for (var i = 0; i < chart.data.length; i++) {
895
+ var point = chart.data[i];
896
+ labels.push(point[0]);
897
+ values.push(point[1]);
898
+ }
899
+
900
+ var dataset = {
901
+ data: values,
902
+ backgroundColor: chart.options.colors || defaultColors
903
+ };
904
+ dataset = merge(dataset, chart.options.dataset || {});
905
+
906
+ var data = {
907
+ labels: labels,
908
+ datasets: [dataset]
909
+ };
910
+
911
+ this.drawChart(chart, "pie", data, options);
912
+ };
913
+
914
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
+ var options;
916
+ if (chartType === "bar") {
917
+ var barOptions = merge(baseOptions, defaultOptions);
918
+ delete barOptions.scales.yAxes[0].ticks.maxTicksLimit;
919
+ options = jsOptionsFunc(barOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
920
+ } else {
921
+ options = jsOptions(chart, chart.options);
922
+ }
923
+ setFormatOptions(chart, options, chartType);
924
+ var data = createDataTable(chart, options, "column", this.library);
925
+ if (chartType !== "bar") {
926
+ setLabelSize(chart, data, options);
927
+ }
928
+ this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
929
+ };
930
+
931
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
932
+ this.renderLineChart(chart, "area");
933
+ };
934
+
935
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
936
+ this.renderColumnChart(chart, "bar");
937
+ };
938
+
939
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
+ chartType = chartType || "scatter";
941
+
942
+ var options = jsOptions(chart, chart.options);
943
+ setFormatOptions(chart, options, chartType);
944
+
945
+ if (!("showLines" in options)) {
946
+ options.showLines = false;
947
+ }
948
+
949
+ var data = createDataTable(chart, options, chartType, this.library);
950
+
951
+ options.scales.xAxes[0].type = "linear";
952
+ options.scales.xAxes[0].position = "bottom";
953
+
954
+ this.drawChart(chart, chartType, data, options);
955
+ };
956
+
957
+ defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
+ this.renderScatterChart(chart, "bubble");
959
+ };
960
+
961
+ defaultExport.prototype.destroy = function destroy (chart) {
962
+ if (chart.chart) {
963
+ chart.chart.destroy();
964
+ }
965
+ };
966
+
967
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
968
+ this.destroy(chart);
969
+
970
+ var chartOptions = {
971
+ type: type,
972
+ data: data,
973
+ options: options
974
+ };
975
+
976
+ if (chart.options.code) {
977
+ window.console.log("new Chart(ctx, " + JSON.stringify(chartOptions) + ");");
978
+ }
979
+
980
+ chart.element.innerHTML = "<canvas></canvas>";
981
+ var ctx = chart.element.getElementsByTagName("CANVAS")[0];
982
+ chart.chart = new this.library(ctx, chartOptions);
983
+ };
984
+
985
+ var defaultOptions$1 = {
986
+ chart: {},
987
+ xAxis: {
988
+ title: {
989
+ text: null
990
+ },
991
+ labels: {
992
+ style: {
993
+ fontSize: "12px"
994
+ }
995
+ }
996
+ },
997
+ yAxis: {
998
+ title: {
999
+ text: null
1000
+ },
1001
+ labels: {
1002
+ style: {
1003
+ fontSize: "12px"
1004
+ }
1005
+ }
1006
+ },
1007
+ title: {
1008
+ text: null
1009
+ },
1010
+ credits: {
1011
+ enabled: false
1012
+ },
1013
+ legend: {
1014
+ borderWidth: 0
1015
+ },
1016
+ tooltip: {
1017
+ style: {
1018
+ fontSize: "12px"
1019
+ }
1020
+ },
1021
+ plotOptions: {
1022
+ areaspline: {},
1023
+ area: {},
1024
+ series: {
1025
+ marker: {}
1026
+ }
1027
+ }
1028
+ };
1029
+
1030
+ var hideLegend$1 = function (options, legend, hideLegend) {
1031
+ if (legend !== undefined) {
1032
+ options.legend.enabled = !!legend;
1033
+ if (legend && legend !== true) {
1034
+ if (legend === "top" || legend === "bottom") {
1035
+ options.legend.verticalAlign = legend;
1036
+ } else {
1037
+ options.legend.layout = "vertical";
1038
+ options.legend.verticalAlign = "middle";
1039
+ options.legend.align = legend;
1040
+ }
1041
+ }
1042
+ } else if (hideLegend) {
1043
+ options.legend.enabled = false;
1044
+ }
1045
+ };
1046
+
1047
+ var setTitle$1 = function (options, title) {
1048
+ options.title.text = title;
1049
+ };
1050
+
1051
+ var setMin$1 = function (options, min) {
1052
+ options.yAxis.min = min;
1053
+ };
1054
+
1055
+ var setMax$1 = function (options, max) {
1056
+ options.yAxis.max = max;
1057
+ };
1058
+
1059
+ var setStacked$1 = function (options, stacked) {
1060
+ var stackedValue = stacked ? (stacked === true ? "normal" : stacked) : null;
1061
+ options.plotOptions.series.stacking = stackedValue;
1062
+ options.plotOptions.area.stacking = stackedValue;
1063
+ options.plotOptions.areaspline.stacking = stackedValue;
1064
+ };
1065
+
1066
+ var setXtitle$1 = function (options, title) {
1067
+ options.xAxis.title.text = title;
1068
+ };
1069
+
1070
+ var setYtitle$1 = function (options, title) {
1071
+ options.yAxis.title.text = title;
1072
+ };
1073
+
1074
+ var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
+
1076
+ var setFormatOptions$1 = function(chart, options, chartType) {
1077
+ var formatOptions = {
1078
+ prefix: chart.options.prefix,
1079
+ suffix: chart.options.suffix,
1080
+ thousands: chart.options.thousands,
1081
+ decimal: chart.options.decimal,
1082
+ precision: chart.options.precision,
1083
+ round: chart.options.round,
1084
+ zeros: chart.options.zeros
1085
+ };
1086
+
1087
+ if (chartType !== "pie" && !options.yAxis.labels.formatter) {
1088
+ options.yAxis.labels.formatter = function () {
1089
+ return formatValue("", this.value, formatOptions);
1090
+ };
1091
+ }
1092
+
1093
+ if (!options.tooltip.pointFormatter) {
1094
+ options.tooltip.pointFormatter = function () {
1095
+ return '<span style="color:' + this.color + '">\u25CF</span> ' + formatValue(this.series.name + ': <b>', this.y, formatOptions) + '</b><br/>';
1096
+ };
1097
+ }
1098
+ };
1099
+
1100
+ var defaultExport$1 = function defaultExport(library) {
1101
+ this.name = "highcharts";
1102
+ this.library = library;
1103
+ };
1104
+
1105
+ defaultExport$1.prototype.renderLineChart = function renderLineChart (chart, chartType) {
1106
+ chartType = chartType || "spline";
1107
+ var chartOptions = {};
1108
+ if (chartType === "areaspline") {
1109
+ chartOptions = {
1110
+ plotOptions: {
1111
+ areaspline: {
1112
+ stacking: "normal"
1113
+ },
1114
+ area: {
1115
+ stacking: "normal"
1116
+ },
1117
+ series: {
1118
+ marker: {
1119
+ enabled: false
1120
+ }
1121
+ }
1122
+ }
1123
+ };
1124
+ }
1125
+
1126
+ if (chart.options.curve === false) {
1127
+ if (chartType === "areaspline") {
1128
+ chartType = "area";
1129
+ } else if (chartType === "spline") {
1130
+ chartType = "line";
1131
+ }
1132
+ }
1133
+
1134
+ var options = jsOptions$1(chart, chart.options, chartOptions), data, i, j;
1135
+ options.xAxis.type = chart.xtype === "string" ? "category" : (chart.xtype === "number" ? "linear" : "datetime");
1136
+ if (!options.chart.type) {
1137
+ options.chart.type = chartType;
1138
+ }
1139
+ setFormatOptions$1(chart, options, chartType);
1140
+
1141
+ var series = chart.data;
1142
+ for (i = 0; i < series.length; i++) {
1143
+ series[i].name = series[i].name || "Value";
1144
+ data = series[i].data;
1145
+ if (chart.xtype === "datetime") {
1146
+ for (j = 0; j < data.length; j++) {
1147
+ data[j][0] = data[j][0].getTime();
1148
+ }
1149
+ }
1150
+ series[i].marker = {symbol: "circle"};
1151
+ if (chart.options.points === false) {
1152
+ series[i].marker.enabled = false;
1153
+ }
1154
+ }
1155
+
1156
+ this.drawChart(chart, series, options);
1157
+ };
1158
+
1159
+ defaultExport$1.prototype.renderScatterChart = function renderScatterChart (chart) {
1160
+ var options = jsOptions$1(chart, chart.options, {});
1161
+ options.chart.type = "scatter";
1162
+ this.drawChart(chart, chart.data, options);
1163
+ };
1164
+
1165
+ defaultExport$1.prototype.renderPieChart = function renderPieChart (chart) {
1166
+ var chartOptions = merge(defaultOptions$1, {});
1167
+
1168
+ if (chart.options.colors) {
1169
+ chartOptions.colors = chart.options.colors;
1170
+ }
1171
+ if (chart.options.donut) {
1172
+ chartOptions.plotOptions = {pie: {innerSize: "50%"}};
1173
+ }
1174
+
1175
+ if ("legend" in chart.options) {
1176
+ hideLegend$1(chartOptions, chart.options.legend);
1177
+ }
1178
+
1179
+ if (chart.options.title) {
1180
+ setTitle$1(chartOptions, chart.options.title);
1181
+ }
1182
+
1183
+ var options = merge(chartOptions, chart.options.library || {});
1184
+ setFormatOptions$1(chart, options, "pie");
1185
+ var series = [{
1186
+ type: "pie",
1187
+ name: chart.options.label || "Value",
1188
+ data: chart.data
1189
+ }];
1190
+
1191
+ this.drawChart(chart, series, options);
1192
+ };
1193
+
1194
+ defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
1195
+ chartType = chartType || "column";
1196
+ var series = chart.data;
1197
+ var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1198
+ options.chart.type = chartType;
1199
+ setFormatOptions$1(chart, options, chartType);
1200
+
1201
+ for (i = 0; i < series.length; i++) {
1202
+ s = series[i];
1203
+
1204
+ for (j = 0; j < s.data.length; j++) {
1205
+ d = s.data[j];
1206
+ if (!rows[d[0]]) {
1207
+ rows[d[0]] = new Array(series.length);
1208
+ categories.push(d[0]);
1209
+ }
1210
+ rows[d[0]][i] = d[1];
1211
+ }
1212
+ }
1213
+
1214
+ if (chart.xtype === "number") {
1215
+ categories.sort(sortByNumber);
1216
+ }
1217
+
1218
+ options.xAxis.categories = categories;
1219
+
1220
+ var newSeries = [], d2;
1221
+ for (i = 0; i < series.length; i++) {
1222
+ d = [];
1223
+ for (j = 0; j < categories.length; j++) {
1224
+ d.push(rows[categories[j]][i] || 0);
1225
+ }
1226
+
1227
+ d2 = {
1228
+ name: series[i].name || "Value",
1229
+ data: d
1230
+ };
1231
+ if (series[i].stack) {
1232
+ d2.stack = series[i].stack;
1233
+ }
1234
+
1235
+ newSeries.push(d2);
1236
+ }
1237
+
1238
+ this.drawChart(chart, newSeries, options);
1239
+ };
1240
+
1241
+ defaultExport$1.prototype.renderBarChart = function renderBarChart (chart) {
1242
+ this.renderColumnChart(chart, "bar");
1243
+ };
1244
+
1245
+ defaultExport$1.prototype.renderAreaChart = function renderAreaChart (chart) {
1246
+ this.renderLineChart(chart, "areaspline");
1247
+ };
1248
+
1249
+ defaultExport$1.prototype.destroy = function destroy (chart) {
1250
+ if (chart.chart) {
1251
+ chart.chart.destroy();
1252
+ }
1253
+ };
1254
+
1255
+ defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
+ this.destroy(chart);
1257
+
1258
+ options.chart.renderTo = chart.element.id;
1259
+ options.series = data;
1260
+
1261
+ if (chart.options.code) {
1262
+ window.console.log("new Highcharts.Chart(" + JSON.stringify(options) + ");");
1263
+ }
1264
+
1265
+ chart.chart = new this.library.Chart(options);
1266
+ };
1267
+
1268
+ var loaded = {};
1269
+ var callbacks = [];
1270
+
1271
+ // Set chart options
1272
+ var defaultOptions$2 = {
1273
+ chartArea: {},
1274
+ fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
+ pointSize: 6,
1276
+ legend: {
1277
+ textStyle: {
1278
+ fontSize: 12,
1279
+ color: "#444"
1280
+ },
1281
+ alignment: "center",
1282
+ position: "right"
1283
+ },
1284
+ curveType: "function",
1285
+ hAxis: {
1286
+ textStyle: {
1287
+ color: "#666",
1288
+ fontSize: 12
1289
+ },
1290
+ titleTextStyle: {},
1291
+ gridlines: {
1292
+ color: "transparent"
1293
+ },
1294
+ baselineColor: "#ccc",
1295
+ viewWindow: {}
1296
+ },
1297
+ vAxis: {
1298
+ textStyle: {
1299
+ color: "#666",
1300
+ fontSize: 12
1301
+ },
1302
+ titleTextStyle: {},
1303
+ baselineColor: "#ccc",
1304
+ viewWindow: {}
1305
+ },
1306
+ tooltip: {
1307
+ textStyle: {
1308
+ color: "#666",
1309
+ fontSize: 12
1310
+ }
1311
+ }
1312
+ };
1313
+
1314
+ var hideLegend$2 = function (options, legend, hideLegend) {
1315
+ if (legend !== undefined) {
1316
+ var position;
1317
+ if (!legend) {
1318
+ position = "none";
1319
+ } else if (legend === true) {
1320
+ position = "right";
1321
+ } else {
1322
+ position = legend;
1323
+ }
1324
+ options.legend.position = position;
1325
+ } else if (hideLegend) {
1326
+ options.legend.position = "none";
1327
+ }
1328
+ };
1329
+
1330
+ var setTitle$2 = function (options, title) {
1331
+ options.title = title;
1332
+ options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
+ };
1334
+
1335
+ var setMin$2 = function (options, min) {
1336
+ options.vAxis.viewWindow.min = min;
1337
+ };
1338
+
1339
+ var setMax$2 = function (options, max) {
1340
+ options.vAxis.viewWindow.max = max;
1341
+ };
1342
+
1343
+ var setBarMin$1 = function (options, min) {
1344
+ options.hAxis.viewWindow.min = min;
1345
+ };
1346
+
1347
+ var setBarMax$1 = function (options, max) {
1348
+ options.hAxis.viewWindow.max = max;
1349
+ };
1350
+
1351
+ var setStacked$2 = function (options, stacked) {
1352
+ options.isStacked = stacked ? stacked : false;
1353
+ };
1354
+
1355
+ var setXtitle$2 = function (options, title) {
1356
+ options.hAxis.title = title;
1357
+ options.hAxis.titleTextStyle.italic = false;
1358
+ };
1359
+
1360
+ var setYtitle$2 = function (options, title) {
1361
+ options.vAxis.title = title;
1362
+ options.vAxis.titleTextStyle.italic = false;
1363
+ };
1364
+
1365
+ var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1366
+
1367
+ var resize = function (callback) {
1368
+ if (window.attachEvent) {
1369
+ window.attachEvent("onresize", callback);
1370
+ } else if (window.addEventListener) {
1371
+ window.addEventListener("resize", callback, true);
1372
+ }
1373
+ callback();
1374
+ };
1375
+
1376
+ var defaultExport$2 = function defaultExport(library) {
1377
+ this.name = "google";
1378
+ this.library = library;
1379
+ };
1380
+
1381
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1382
+ var this$1 = this;
1383
+
1384
+ this.waitForLoaded(chart, function () {
1385
+ var chartOptions = {};
1386
+
1387
+ if (chart.options.curve === false) {
1388
+ chartOptions.curveType = "none";
1389
+ }
1390
+
1391
+ if (chart.options.points === false) {
1392
+ chartOptions.pointSize = 0;
1393
+ }
1394
+
1395
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1396
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1397
+
1398
+ this$1.drawChart(chart, "LineChart", data, options);
1399
+ });
1400
+ };
1401
+
1402
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1403
+ var this$1 = this;
1404
+
1405
+ this.waitForLoaded(chart, function () {
1406
+ var chartOptions = {
1407
+ chartArea: {
1408
+ top: "10%",
1409
+ height: "80%"
1410
+ },
1411
+ legend: {}
1412
+ };
1413
+ if (chart.options.colors) {
1414
+ chartOptions.colors = chart.options.colors;
1415
+ }
1416
+ if (chart.options.donut) {
1417
+ chartOptions.pieHole = 0.5;
1418
+ }
1419
+ if ("legend" in chart.options) {
1420
+ hideLegend$2(chartOptions, chart.options.legend);
1421
+ }
1422
+ if (chart.options.title) {
1423
+ setTitle$2(chartOptions, chart.options.title);
1424
+ }
1425
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1426
+
1427
+ var data = new this$1.library.visualization.DataTable();
1428
+ data.addColumn("string", "");
1429
+ data.addColumn("number", "Value");
1430
+ data.addRows(chart.data);
1431
+
1432
+ this$1.drawChart(chart, "PieChart", data, options);
1433
+ });
1434
+ };
1435
+
1436
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
+ var this$1 = this;
1438
+
1439
+ this.waitForLoaded(chart, function () {
1440
+ var options = jsOptions$2(chart, chart.options);
1441
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1442
+
1443
+ this$1.drawChart(chart, "ColumnChart", data, options);
1444
+ });
1445
+ };
1446
+
1447
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1448
+ var this$1 = this;
1449
+
1450
+ this.waitForLoaded(chart, function () {
1451
+ var chartOptions = {
1452
+ hAxis: {
1453
+ gridlines: {
1454
+ color: "#ccc"
1455
+ }
1456
+ }
1457
+ };
1458
+ var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions);
1459
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1460
+
1461
+ this$1.drawChart(chart, "BarChart", data, options);
1462
+ });
1463
+ };
1464
+
1465
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
+ var this$1 = this;
1467
+
1468
+ this.waitForLoaded(chart, function () {
1469
+ var chartOptions = {
1470
+ isStacked: true,
1471
+ pointSize: 0,
1472
+ areaOpacity: 0.5
1473
+ };
1474
+
1475
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1476
+ var data = this$1.createDataTable(chart.data, chart.xtype);
1477
+
1478
+ this$1.drawChart(chart, "AreaChart", data, options);
1479
+ });
1480
+ };
1481
+
1482
+ defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
+ var this$1 = this;
1484
+
1485
+ this.waitForLoaded(chart, "geochart", function () {
1486
+ var chartOptions = {
1487
+ legend: "none",
1488
+ colorAxis: {
1489
+ colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
+ }
1491
+ };
1492
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1493
+
1494
+ var data = new this$1.library.visualization.DataTable();
1495
+ data.addColumn("string", "");
1496
+ data.addColumn("number", chart.options.label || "Value");
1497
+ data.addRows(chart.data);
1498
+
1499
+ this$1.drawChart(chart, "GeoChart", data, options);
1500
+ });
1501
+ };
1502
+
1503
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
+ var this$1 = this;
1505
+
1506
+ this.waitForLoaded(chart, function () {
1507
+ var chartOptions = {};
1508
+ var options = jsOptions$2(chart, chart.options, chartOptions);
1509
+
1510
+ var series = chart.data, rows2 = [], i, j, data, d;
1511
+ for (i = 0; i < series.length; i++) {
1512
+ series[i].name = series[i].name || "Value";
1513
+ d = series[i].data;
1514
+ for (j = 0; j < d.length; j++) {
1515
+ var row = new Array(series.length + 1);
1516
+ row[0] = d[j][0];
1517
+ row[i + 1] = d[j][1];
1518
+ rows2.push(row);
1519
+ }
1520
+ }
1521
+
1522
+ data = new this$1.library.visualization.DataTable();
1523
+ data.addColumn("number", "");
1524
+ for (i = 0; i < series.length; i++) {
1525
+ data.addColumn("number", series[i].name);
1526
+ }
1527
+ data.addRows(rows2);
1528
+
1529
+ this$1.drawChart(chart, "ScatterChart", data, options);
1530
+ });
1531
+ };
1532
+
1533
+ defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1534
+ var this$1 = this;
1535
+
1536
+ this.waitForLoaded(chart, "timeline", function () {
1537
+ var chartOptions = {
1538
+ legend: "none"
1539
+ };
1540
+
1541
+ if (chart.options.colors) {
1542
+ chartOptions.colors = chart.options.colors;
1543
+ }
1544
+ var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1545
+
1546
+ var data = new this$1.library.visualization.DataTable();
1547
+ data.addColumn({type: "string", id: "Name"});
1548
+ data.addColumn({type: "date", id: "Start"});
1549
+ data.addColumn({type: "date", id: "End"});
1550
+ data.addRows(chart.data);
1551
+
1552
+ chart.element.style.lineHeight = "normal";
1553
+
1554
+ this$1.drawChart(chart, "Timeline", data, options);
1555
+ });
1556
+ };
1557
+
1558
+ defaultExport$2.prototype.destroy = function destroy (chart) {
1559
+ if (chart.chart) {
1560
+ chart.chart.clearChart();
1561
+ }
1562
+ };
1563
+
1564
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
+ this.destroy(chart);
1566
+
1567
+ if (chart.options.code) {
1568
+ window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");");
1569
+ }
1570
+
1571
+ chart.chart = new this.library.visualization[type](chart.element);
1572
+ resize(function () {
1573
+ chart.chart.draw(data, options);
1574
+ });
1575
+ };
1576
+
1577
+ defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
+ var this$1 = this;
1579
+
1580
+ if (!callback) {
1581
+ callback = pack;
1582
+ pack = "corechart";
1583
+ }
1584
+
1585
+ callbacks.push({pack: pack, callback: callback});
1586
+
1587
+ if (loaded[pack]) {
1588
+ this.runCallbacks();
1589
+ } else {
1590
+ loaded[pack] = true;
1591
+
1592
+ // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
1593
+ var loadOptions = {
1594
+ packages: [pack],
1595
+ callback: function () { this$1.runCallbacks(); }
1596
+ };
1597
+ var config = chart.__config();
1598
+ if (config.language) {
1599
+ loadOptions.language = config.language;
1600
+ }
1601
+ if (pack === "geochart" && config.mapsApiKey) {
1602
+ loadOptions.mapsApiKey = config.mapsApiKey;
1603
+ }
1604
+
1605
+ this.library.charts.load("current", loadOptions);
1606
+ }
1607
+ };
1608
+
1609
+ defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1610
+ var cb, call;
1611
+ for (var i = 0; i < callbacks.length; i++) {
1612
+ cb = callbacks[i];
1613
+ call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline) || (cb.pack === "geochart" && this.library.visualization.GeoChart));
1614
+ if (call) {
1615
+ cb.callback();
1616
+ callbacks.splice(i, 1);
1617
+ i--;
1618
+ }
1619
+ }
1620
+ };
1621
+
1622
+ // cant use object as key
1623
+ defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) {
1624
+ var i, j, s, d, key, rows = [], sortedLabels = [];
1625
+ for (i = 0; i < series.length; i++) {
1626
+ s = series[i];
1627
+ series[i].name = series[i].name || "Value";
1628
+
1629
+ for (j = 0; j < s.data.length; j++) {
1630
+ d = s.data[j];
1631
+ key = (columnType === "datetime") ? d[0].getTime() : d[0];
1632
+ if (!rows[key]) {
1633
+ rows[key] = new Array(series.length);
1634
+ sortedLabels.push(key);
1635
+ }
1636
+ rows[key][i] = toFloat(d[1]);
1637
+ }
1638
+ }
1639
+
1640
+ var rows2 = [];
1641
+ var day = true;
1642
+ var value;
1643
+ for (j = 0; j < sortedLabels.length; j++) {
1644
+ i = sortedLabels[j];
1645
+ if (columnType === "datetime") {
1646
+ value = new Date(toFloat(i));
1647
+ day = day && isDay(value);
1648
+ } else if (columnType === "number") {
1649
+ value = toFloat(i);
1650
+ } else {
1651
+ value = i;
1652
+ }
1653
+ rows2.push([value].concat(rows[i]));
1654
+ }
1655
+ if (columnType === "datetime") {
1656
+ rows2.sort(sortByTime);
1657
+ } else if (columnType === "number") {
1658
+ rows2.sort(sortByNumberSeries);
1659
+
1660
+ for (i = 0; i < rows2.length; i++) {
1661
+ rows2[i][0] = toStr(rows2[i][0]);
1662
+ }
1663
+
1664
+ columnType = "string";
1665
+ }
1666
+
1667
+ // create datatable
1668
+ var data = new this.library.visualization.DataTable();
1669
+ columnType = columnType === "datetime" && day ? "date" : columnType;
1670
+ data.addColumn(columnType, "");
1671
+ for (i = 0; i < series.length; i++) {
1672
+ data.addColumn("number", series[i].name);
1673
+ }
1674
+ data.addRows(rows2);
1675
+
1676
+ return data;
1677
+ };
1678
+
1679
+ var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1680
+
1681
+ function pushRequest(url, success, error) {
1682
+ pendingRequests.push([url, success, error]);
1683
+ runNext();
1684
+ }
1685
+
1686
+ function runNext() {
1687
+ if (runningRequests < maxRequests) {
1688
+ var request = pendingRequests.shift();
1689
+ if (request) {
1690
+ runningRequests++;
1691
+ getJSON(request[0], request[1], request[2]);
1692
+ runNext();
1693
+ }
1694
+ }
1695
+ }
1696
+
1697
+ function requestComplete() {
1698
+ runningRequests--;
1699
+ runNext();
1700
+ }
1701
+
1702
+ function getJSON(url, success, error) {
1703
+ ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1704
+ var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1705
+ error(message);
1706
+ });
1707
+ }
1708
+
1709
+ function ajaxCall(url, success, error) {
1710
+ var $ = window.jQuery || window.Zepto || window.$;
1711
+
1712
+ if ($ && $.ajax) {
1713
+ $.ajax({
1714
+ dataType: "json",
1715
+ url: url,
1716
+ success: success,
1717
+ error: error,
1718
+ complete: requestComplete
1719
+ });
1720
+ } else {
1721
+ var xhr = new XMLHttpRequest();
1722
+ xhr.open("GET", url, true);
1723
+ xhr.setRequestHeader("Content-Type", "application/json");
1724
+ xhr.onload = function () {
1725
+ requestComplete();
1726
+ if (xhr.status === 200) {
1727
+ success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1728
+ } else {
1729
+ error(xhr, "error", xhr.statusText);
1730
+ }
1731
+ };
1732
+ xhr.send();
1733
+ }
1734
+ }
1735
+
1736
+ var config = {};
1737
+ var adapters = [];
1738
+
1739
+ // helpers
1740
+
1741
+ function setText(element, text) {
1742
+ if (document.body.innerText) {
1743
+ element.innerText = text;
1744
+ } else {
1745
+ element.textContent = text;
1746
+ }
1747
+ }
1748
+
1749
+ // TODO remove prefix for all messages
1750
+ function chartError(element, message, noPrefix) {
1751
+ if (!noPrefix) {
1752
+ message = "Error Loading Chart: " + message;
1753
+ }
1754
+ setText(element, message);
1755
+ element.style.color = "#ff0000";
1756
+ }
1757
+
1758
+ function errorCatcher(chart) {
1759
+ try {
1760
+ chart.__render();
1761
+ } catch (err) {
1762
+ chartError(chart.element, err.message);
1763
+ throw err;
424
1764
  }
425
1765
  }
426
1766
 
427
- function fetchDataSource(element, dataSource, opts, callback) {
1767
+ function fetchDataSource(chart, dataSource) {
428
1768
  if (typeof dataSource === "string") {
429
- getJSON(element, dataSource, function(data, textStatus, jqXHR) {
430
- errorCatcher(element, data, opts, callback);
1769
+ pushRequest(dataSource, function (data) {
1770
+ chart.rawData = data;
1771
+ errorCatcher(chart);
1772
+ }, function (message) {
1773
+ chartError(chart.element, message);
431
1774
  });
1775
+ } else if (typeof dataSource === "function") {
1776
+ try {
1777
+ dataSource(function (data) {
1778
+ chart.rawData = data;
1779
+ errorCatcher(chart);
1780
+ }, function (message) {
1781
+ chartError(chart.element, message, true);
1782
+ });
1783
+ } catch (err) {
1784
+ chartError(chart.element, err, true);
1785
+ }
432
1786
  } else {
433
- errorCatcher(element, dataSource, opts, callback);
1787
+ chart.rawData = dataSource;
1788
+ errorCatcher(chart);
434
1789
  }
435
1790
  }
436
1791
 
437
- // type conversions
1792
+ function addDownloadButton(chart) {
1793
+ var element = chart.element;
1794
+ var link = document.createElement("a");
438
1795
 
439
- function toStr(n) {
440
- return "" + n;
1796
+ var download = chart.options.download;
1797
+ if (download === true) {
1798
+ download = {};
1799
+ } else if (typeof download === "string") {
1800
+ download = {filename: download};
1801
+ }
1802
+ link.download = download.filename || "chart.png"; // https://caniuse.com/download
1803
+
1804
+ link.style.position = "absolute";
1805
+ link.style.top = "20px";
1806
+ link.style.right = "20px";
1807
+ link.style.zIndex = 1000;
1808
+ link.style.lineHeight = "20px";
1809
+ link.target = "_blank"; // for safari
1810
+ var image = document.createElement("img");
1811
+ image.alt = "Download";
1812
+ image.style.border = "none";
1813
+ // icon from font-awesome
1814
+ // http://fa2png.io/
1815
+ image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1816
+ link.appendChild(image);
1817
+ element.style.position = "relative";
1818
+
1819
+ chart.__downloadAttached = true;
1820
+
1821
+ // mouseenter
1822
+ chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1823
+ var related = e.relatedTarget;
1824
+ // check download option again to ensure it wasn't changed
1825
+ if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1826
+ link.href = chart.toImage(download);
1827
+ element.appendChild(link);
1828
+ }
1829
+ });
1830
+
1831
+ // mouseleave
1832
+ chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1833
+ var related = e.relatedTarget;
1834
+ if (!related || (related !== this && !childOf(this, related))) {
1835
+ if (link.parentNode) {
1836
+ link.parentNode.removeChild(link);
1837
+ }
1838
+ }
1839
+ });
441
1840
  }
442
1841
 
443
- function toFloat(n) {
444
- return parseFloat(n);
1842
+ // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1843
+ function addEvent(elem, event, fn) {
1844
+ if (elem.addEventListener) {
1845
+ elem.addEventListener(event, fn, false);
1846
+ return fn;
1847
+ } else {
1848
+ var fn2 = function() {
1849
+ // set the this pointer same as addEventListener when fn is called
1850
+ return(fn.call(elem, window.event));
1851
+ };
1852
+ elem.attachEvent("on" + event, fn2);
1853
+ return fn2;
1854
+ }
445
1855
  }
446
1856
 
447
- function toDate(n) {
448
- if (typeof n !== "object") {
449
- if (typeof n === "number") {
450
- n = new Date(n * 1000); // ms
451
- } else { // str
452
- // try our best to get the str into iso8601
453
- // TODO be smarter about this
454
- var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
455
- n = parseISO8601(str) || new Date(n);
1857
+ function removeEvent(elem, event, fn) {
1858
+ if (elem.removeEventListener) {
1859
+ elem.removeEventListener(event, fn, false);
1860
+ } else {
1861
+ elem.detachEvent("on" + event, fn);
1862
+ }
1863
+ }
1864
+
1865
+ // https://gist.github.com/shawnbot/4166283
1866
+ function childOf(p, c) {
1867
+ if (p === c) { return false; }
1868
+ while (c && c !== p) { c = c.parentNode; }
1869
+ return c === p;
1870
+ }
1871
+
1872
+ function getAdapterType(library) {
1873
+ if (library) {
1874
+ if (library.product === "Highcharts") {
1875
+ return defaultExport$1;
1876
+ } else if (library.charts) {
1877
+ return defaultExport$2;
1878
+ } else if (isFunction(library)) {
1879
+ return defaultExport;
456
1880
  }
457
1881
  }
458
- return n;
1882
+ throw new Error("Unknown adapter");
459
1883
  }
460
1884
 
461
- function toArr(n) {
462
- if (!isArray(n)) {
463
- var arr = [], i;
464
- for (i in n) {
465
- if (n.hasOwnProperty(i)) {
466
- arr.push([i, n[i]]);
1885
+ function addAdapter(library) {
1886
+ var adapterType = getAdapterType(library);
1887
+ var adapter = new adapterType(library);
1888
+
1889
+ if (adapters.indexOf(adapter) === -1) {
1890
+ adapters.push(adapter);
1891
+ }
1892
+ }
1893
+
1894
+ function loadAdapters() {
1895
+ if ("Chart" in window) {
1896
+ addAdapter(window.Chart);
1897
+ }
1898
+
1899
+ if ("Highcharts" in window) {
1900
+ addAdapter(window.Highcharts);
1901
+ }
1902
+
1903
+ if (window.google && window.google.charts) {
1904
+ addAdapter(window.google);
1905
+ }
1906
+ }
1907
+
1908
+ function dataEmpty(data, chartType) {
1909
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1910
+ return data.length === 0;
1911
+ } else {
1912
+ for (var i = 0; i < data.length; i++) {
1913
+ if (data[i].data.length > 0) {
1914
+ return false;
467
1915
  }
468
1916
  }
469
- n = arr;
1917
+ return true;
470
1918
  }
471
- return n;
472
1919
  }
473
1920
 
474
- // process data
1921
+ function renderChart(chartType, chart) {
1922
+ if (chart.options.messages && chart.options.messages.empty && dataEmpty(chart.data, chartType)) {
1923
+ setText(chart.element, chart.options.messages.empty);
1924
+ } else {
1925
+ callAdapter(chartType, chart);
1926
+ if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
1927
+ addDownloadButton(chart);
1928
+ }
1929
+ }
1930
+ }
475
1931
 
476
- function sortByTime(a, b) {
477
- return a[0].getTime() - b[0].getTime();
1932
+ // TODO remove chartType if cross-browser way
1933
+ // to get the name of the chart class
1934
+ function callAdapter(chartType, chart) {
1935
+ var i, adapter, fnName, adapterName;
1936
+ fnName = "render" + chartType;
1937
+ adapterName = chart.options.adapter;
1938
+
1939
+ loadAdapters();
1940
+
1941
+ for (i = 0; i < adapters.length; i++) {
1942
+ adapter = adapters[i];
1943
+ if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
1944
+ chart.adapter = adapter.name;
1945
+ chart.__adapterObject = adapter;
1946
+ return adapter[fnName](chart);
1947
+ }
1948
+ }
1949
+
1950
+ if (adapters.length > 0) {
1951
+ throw new Error("No charting library found for " + chartType);
1952
+ } else {
1953
+ throw new Error("No charting libraries found - be sure to include one before your charts");
1954
+ }
478
1955
  }
479
1956
 
480
- function processSeries(series, opts, time) {
481
- var i, j, data, r, key;
1957
+ // process data
482
1958
 
483
- // see if one series or multiple
484
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
485
- series = [{name: "Value", data: series}];
486
- opts.hideLegend = true;
1959
+ var toFormattedKey = function (key, keyType) {
1960
+ if (keyType === "number") {
1961
+ key = toFloat(key);
1962
+ } else if (keyType === "datetime") {
1963
+ key = toDate(key);
487
1964
  } else {
488
- opts.hideLegend = false;
1965
+ key = toStr(key);
489
1966
  }
1967
+ return key;
1968
+ };
490
1969
 
491
- // right format
492
- for (i = 0; i < series.length; i++) {
493
- data = toArr(series[i].data);
494
- r = [];
495
- for (j = 0; j < data.length; j++) {
496
- key = data[j][0];
497
- key = time ? toDate(key) : toStr(key);
1970
+ var formatSeriesData = function (data, keyType) {
1971
+ var r = [], key, j;
1972
+ for (j = 0; j < data.length; j++) {
1973
+ if (keyType === "bubble") {
1974
+ r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1975
+ } else {
1976
+ key = toFormattedKey(data[j][0], keyType);
498
1977
  r.push([key, toFloat(data[j][1])]);
499
1978
  }
500
- if (time) {
501
- r.sort(sortByTime);
1979
+ }
1980
+ if (keyType === "datetime") {
1981
+ r.sort(sortByTime);
1982
+ } else if (keyType === "number") {
1983
+ r.sort(sortByNumberSeries);
1984
+ }
1985
+ return r;
1986
+ };
1987
+
1988
+ function detectXType(series, noDatetime, options) {
1989
+ if (dataEmpty(series)) {
1990
+ if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1991
+ return "datetime";
1992
+ } else {
1993
+ return "number";
502
1994
  }
503
- series[i].data = r;
1995
+ } else if (detectXTypeWithFunction(series, isNumber)) {
1996
+ return "number";
1997
+ } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1998
+ return "datetime";
1999
+ } else {
2000
+ return "string";
504
2001
  }
2002
+ }
505
2003
 
506
- return series;
2004
+ function detectXTypeWithFunction(series, func) {
2005
+ var i, j, data;
2006
+ for (i = 0; i < series.length; i++) {
2007
+ data = toArr(series[i].data);
2008
+ for (j = 0; j < data.length; j++) {
2009
+ if (!func(data[j][0])) {
2010
+ return false;
2011
+ }
2012
+ }
2013
+ }
2014
+ return true;
507
2015
  }
508
2016
 
509
- function processLineData(element, data, opts) {
510
- renderLineChart(element, processSeries(data, opts, true), opts);
2017
+ // creates a shallow copy of each element of the array
2018
+ // elements are expected to be objects
2019
+ function copySeries(series) {
2020
+ var newSeries = [], i, j;
2021
+ for (i = 0; i < series.length; i++) {
2022
+ var copy = {};
2023
+ for (j in series[i]) {
2024
+ if (series[i].hasOwnProperty(j)) {
2025
+ copy[j] = series[i][j];
2026
+ }
2027
+ }
2028
+ newSeries.push(copy);
2029
+ }
2030
+ return newSeries;
511
2031
  }
512
2032
 
513
- function processColumnData(element, data, opts) {
514
- renderColumnChart(element, processSeries(data, opts, false), opts);
2033
+ function processSeries(chart, keyType, noDatetime) {
2034
+ var i;
2035
+
2036
+ var opts = chart.options;
2037
+ var series = chart.rawData;
2038
+
2039
+ // see if one series or multiple
2040
+ if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
2041
+ series = [{name: opts.label, data: series}];
2042
+ chart.hideLegend = true;
2043
+ } else {
2044
+ chart.hideLegend = false;
2045
+ }
2046
+
2047
+ // convert to array
2048
+ // must come before dataEmpty check
2049
+ series = copySeries(series);
2050
+ for (i = 0; i < series.length; i++) {
2051
+ series[i].data = toArr(series[i].data);
2052
+ }
2053
+
2054
+ chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2055
+
2056
+ // right format
2057
+ for (i = 0; i < series.length; i++) {
2058
+ series[i].data = formatSeriesData(series[i].data, chart.xtype);
2059
+ }
2060
+
2061
+ return series;
515
2062
  }
516
2063
 
517
- function processPieData(element, data, opts) {
518
- var perfectData = toArr(data), i;
2064
+ function processSimple(chart) {
2065
+ var perfectData = toArr(chart.rawData), i;
519
2066
  for (i = 0; i < perfectData.length; i++) {
520
2067
  perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
521
2068
  }
522
- renderPieChart(element, perfectData, opts);
2069
+ return perfectData;
523
2070
  }
524
2071
 
525
- function setElement(element, data, opts, callback) {
2072
+ // define classes
2073
+
2074
+ var Chart = function Chart(element, dataSource, options) {
2075
+ var elementId;
526
2076
  if (typeof element === "string") {
2077
+ elementId = element;
527
2078
  element = document.getElementById(element);
2079
+ if (!element) {
2080
+ throw new Error("No element with id " + elementId);
2081
+ }
528
2082
  }
529
- fetchDataSource(element, data, opts || {}, callback);
530
- }
2083
+ this.element = element;
2084
+ this.options = merge(Chartkick.options, options || {});
2085
+ this.dataSource = dataSource;
531
2086
 
532
- // define classes
2087
+ Chartkick.charts[element.id] = this;
2088
+
2089
+ fetchDataSource(this, dataSource);
2090
+
2091
+ if (this.options.refresh) {
2092
+ this.startRefresh();
2093
+ }
2094
+ };
2095
+
2096
+ Chart.prototype.getElement = function getElement () {
2097
+ return this.element;
2098
+ };
2099
+
2100
+ Chart.prototype.getDataSource = function getDataSource () {
2101
+ return this.dataSource;
2102
+ };
2103
+
2104
+ Chart.prototype.getData = function getData () {
2105
+ return this.data;
2106
+ };
2107
+
2108
+ Chart.prototype.getOptions = function getOptions () {
2109
+ return this.options;
2110
+ };
2111
+
2112
+ Chart.prototype.getChartObject = function getChartObject () {
2113
+ return this.chart;
2114
+ };
2115
+
2116
+ Chart.prototype.getAdapter = function getAdapter () {
2117
+ return this.adapter;
2118
+ };
2119
+
2120
+ Chart.prototype.updateData = function updateData (dataSource, options) {
2121
+ this.dataSource = dataSource;
2122
+ if (options) {
2123
+ this.__updateOptions(options);
2124
+ }
2125
+ fetchDataSource(this, dataSource);
2126
+ };
2127
+
2128
+ Chart.prototype.setOptions = function setOptions (options) {
2129
+ this.__updateOptions(options);
2130
+ this.redraw();
2131
+ };
2132
+
2133
+ Chart.prototype.redraw = function redraw () {
2134
+ fetchDataSource(this, this.rawData);
2135
+ };
2136
+
2137
+ Chart.prototype.refreshData = function refreshData () {
2138
+ if (typeof this.dataSource === "string") {
2139
+ // prevent browser from caching
2140
+ var sep = this.dataSource.indexOf("?") === -1 ? "?" : "&";
2141
+ var url = this.dataSource + sep + "_=" + (new Date()).getTime();
2142
+ fetchDataSource(this, url);
2143
+ } else if (typeof this.dataSource === "function") {
2144
+ fetchDataSource(this, this.dataSource);
2145
+ }
2146
+ };
2147
+
2148
+ Chart.prototype.startRefresh = function startRefresh () {
2149
+ var this$1 = this;
2150
+
2151
+ var refresh = this.options.refresh;
2152
+
2153
+ if (refresh && typeof this.dataSource !== "string" && typeof this.dataSource !== "function") {
2154
+ throw new Error("Data source must be a URL or callback for refresh");
2155
+ }
2156
+
2157
+ if (!this.intervalId) {
2158
+ if (refresh) {
2159
+ this.intervalId = setInterval( function () {
2160
+ this$1.refreshData();
2161
+ }, refresh * 1000);
2162
+ } else {
2163
+ throw new Error("No refresh interval");
2164
+ }
2165
+ }
2166
+ };
2167
+
2168
+ Chart.prototype.stopRefresh = function stopRefresh () {
2169
+ if (this.intervalId) {
2170
+ clearInterval(this.intervalId);
2171
+ this.intervalId = null;
2172
+ }
2173
+ };
2174
+
2175
+ Chart.prototype.toImage = function toImage (download) {
2176
+ if (this.adapter === "chartjs") {
2177
+ if (download && download.background && download.background !== "transparent") {
2178
+ // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2179
+ var canvas = this.chart.chart.canvas;
2180
+ var ctx = this.chart.chart.ctx;
2181
+ var tmpCanvas = document.createElement("canvas");
2182
+ var tmpCtx = tmpCanvas.getContext("2d");
2183
+ tmpCanvas.width = ctx.canvas.width;
2184
+ tmpCanvas.height = ctx.canvas.height;
2185
+ tmpCtx.fillStyle = download.background;
2186
+ tmpCtx.fillRect(0, 0, tmpCanvas.width, tmpCanvas.height);
2187
+ tmpCtx.drawImage(canvas, 0, 0);
2188
+ return tmpCanvas.toDataURL("image/png");
2189
+ } else {
2190
+ return this.chart.toBase64Image();
2191
+ }
2192
+ } else {
2193
+ // TODO throw error in next major version
2194
+ // throw new Error("Feature only available for Chart.js");
2195
+ return null;
2196
+ }
2197
+ };
2198
+
2199
+ Chart.prototype.destroy = function destroy () {
2200
+ if (this.__adapterObject) {
2201
+ this.__adapterObject.destroy(this);
2202
+ }
2203
+
2204
+ if (this.__enterEvent) {
2205
+ removeEvent(this.element, "mouseover", this.__enterEvent);
2206
+ }
2207
+
2208
+ if (this.__leaveEvent) {
2209
+ removeEvent(this.element, "mouseout", this.__leaveEvent);
2210
+ }
2211
+ };
2212
+
2213
+ Chart.prototype.__updateOptions = function __updateOptions (options) {
2214
+ var updateRefresh = options.refresh && options.refresh !== this.options.refresh;
2215
+ this.options = merge(Chartkick.options, options);
2216
+ if (updateRefresh) {
2217
+ this.stopRefresh();
2218
+ this.startRefresh();
2219
+ }
2220
+ };
2221
+
2222
+ Chart.prototype.__render = function __render () {
2223
+ this.data = this.__processData();
2224
+ renderChart(this.__chartName(), this);
2225
+ };
2226
+
2227
+ Chart.prototype.__config = function __config () {
2228
+ return config;
2229
+ };
2230
+
2231
+ var LineChart = /*@__PURE__*/(function (Chart) {
2232
+ function LineChart () {
2233
+ Chart.apply(this, arguments);
2234
+ }
2235
+
2236
+ if ( Chart ) LineChart.__proto__ = Chart;
2237
+ LineChart.prototype = Object.create( Chart && Chart.prototype );
2238
+ LineChart.prototype.constructor = LineChart;
2239
+
2240
+ LineChart.prototype.__processData = function __processData () {
2241
+ return processSeries(this);
2242
+ };
2243
+
2244
+ LineChart.prototype.__chartName = function __chartName () {
2245
+ return "LineChart";
2246
+ };
2247
+
2248
+ return LineChart;
2249
+ }(Chart));
2250
+
2251
+ var PieChart = /*@__PURE__*/(function (Chart) {
2252
+ function PieChart () {
2253
+ Chart.apply(this, arguments);
2254
+ }
2255
+
2256
+ if ( Chart ) PieChart.__proto__ = Chart;
2257
+ PieChart.prototype = Object.create( Chart && Chart.prototype );
2258
+ PieChart.prototype.constructor = PieChart;
2259
+
2260
+ PieChart.prototype.__processData = function __processData () {
2261
+ return processSimple(this);
2262
+ };
2263
+
2264
+ PieChart.prototype.__chartName = function __chartName () {
2265
+ return "PieChart";
2266
+ };
2267
+
2268
+ return PieChart;
2269
+ }(Chart));
2270
+
2271
+ var ColumnChart = /*@__PURE__*/(function (Chart) {
2272
+ function ColumnChart () {
2273
+ Chart.apply(this, arguments);
2274
+ }
2275
+
2276
+ if ( Chart ) ColumnChart.__proto__ = Chart;
2277
+ ColumnChart.prototype = Object.create( Chart && Chart.prototype );
2278
+ ColumnChart.prototype.constructor = ColumnChart;
2279
+
2280
+ ColumnChart.prototype.__processData = function __processData () {
2281
+ return processSeries(this, null, true);
2282
+ };
2283
+
2284
+ ColumnChart.prototype.__chartName = function __chartName () {
2285
+ return "ColumnChart";
2286
+ };
2287
+
2288
+ return ColumnChart;
2289
+ }(Chart));
2290
+
2291
+ var BarChart = /*@__PURE__*/(function (Chart) {
2292
+ function BarChart () {
2293
+ Chart.apply(this, arguments);
2294
+ }
2295
+
2296
+ if ( Chart ) BarChart.__proto__ = Chart;
2297
+ BarChart.prototype = Object.create( Chart && Chart.prototype );
2298
+ BarChart.prototype.constructor = BarChart;
2299
+
2300
+ BarChart.prototype.__processData = function __processData () {
2301
+ return processSeries(this, null, true);
2302
+ };
2303
+
2304
+ BarChart.prototype.__chartName = function __chartName () {
2305
+ return "BarChart";
2306
+ };
2307
+
2308
+ return BarChart;
2309
+ }(Chart));
2310
+
2311
+ var AreaChart = /*@__PURE__*/(function (Chart) {
2312
+ function AreaChart () {
2313
+ Chart.apply(this, arguments);
2314
+ }
2315
+
2316
+ if ( Chart ) AreaChart.__proto__ = Chart;
2317
+ AreaChart.prototype = Object.create( Chart && Chart.prototype );
2318
+ AreaChart.prototype.constructor = AreaChart;
2319
+
2320
+ AreaChart.prototype.__processData = function __processData () {
2321
+ return processSeries(this);
2322
+ };
2323
+
2324
+ AreaChart.prototype.__chartName = function __chartName () {
2325
+ return "AreaChart";
2326
+ };
2327
+
2328
+ return AreaChart;
2329
+ }(Chart));
2330
+
2331
+ var GeoChart = /*@__PURE__*/(function (Chart) {
2332
+ function GeoChart () {
2333
+ Chart.apply(this, arguments);
2334
+ }
2335
+
2336
+ if ( Chart ) GeoChart.__proto__ = Chart;
2337
+ GeoChart.prototype = Object.create( Chart && Chart.prototype );
2338
+ GeoChart.prototype.constructor = GeoChart;
2339
+
2340
+ GeoChart.prototype.__processData = function __processData () {
2341
+ return processSimple(this);
2342
+ };
2343
+
2344
+ GeoChart.prototype.__chartName = function __chartName () {
2345
+ return "GeoChart";
2346
+ };
2347
+
2348
+ return GeoChart;
2349
+ }(Chart));
2350
+
2351
+ var ScatterChart = /*@__PURE__*/(function (Chart) {
2352
+ function ScatterChart () {
2353
+ Chart.apply(this, arguments);
2354
+ }
2355
+
2356
+ if ( Chart ) ScatterChart.__proto__ = Chart;
2357
+ ScatterChart.prototype = Object.create( Chart && Chart.prototype );
2358
+ ScatterChart.prototype.constructor = ScatterChart;
2359
+
2360
+ ScatterChart.prototype.__processData = function __processData () {
2361
+ return processSeries(this, "number");
2362
+ };
2363
+
2364
+ ScatterChart.prototype.__chartName = function __chartName () {
2365
+ return "ScatterChart";
2366
+ };
2367
+
2368
+ return ScatterChart;
2369
+ }(Chart));
2370
+
2371
+ var BubbleChart = /*@__PURE__*/(function (Chart) {
2372
+ function BubbleChart () {
2373
+ Chart.apply(this, arguments);
2374
+ }
2375
+
2376
+ if ( Chart ) BubbleChart.__proto__ = Chart;
2377
+ BubbleChart.prototype = Object.create( Chart && Chart.prototype );
2378
+ BubbleChart.prototype.constructor = BubbleChart;
2379
+
2380
+ BubbleChart.prototype.__processData = function __processData () {
2381
+ return processSeries(this, "bubble");
2382
+ };
2383
+
2384
+ BubbleChart.prototype.__chartName = function __chartName () {
2385
+ return "BubbleChart";
2386
+ };
2387
+
2388
+ return BubbleChart;
2389
+ }(Chart));
2390
+
2391
+ var Timeline = /*@__PURE__*/(function (Chart) {
2392
+ function Timeline () {
2393
+ Chart.apply(this, arguments);
2394
+ }
2395
+
2396
+ if ( Chart ) Timeline.__proto__ = Chart;
2397
+ Timeline.prototype = Object.create( Chart && Chart.prototype );
2398
+ Timeline.prototype.constructor = Timeline;
2399
+
2400
+ Timeline.prototype.__processData = function __processData () {
2401
+ var i, data = this.rawData;
2402
+ for (i = 0; i < data.length; i++) {
2403
+ data[i][1] = toDate(data[i][1]);
2404
+ data[i][2] = toDate(data[i][2]);
2405
+ }
2406
+ return data;
2407
+ };
2408
+
2409
+ Timeline.prototype.__chartName = function __chartName () {
2410
+ return "Timeline";
2411
+ };
2412
+
2413
+ return Timeline;
2414
+ }(Chart));
533
2415
 
534
2416
  var Chartkick = {
535
- LineChart: function(element, dataSource, opts) {
536
- setElement(element, dataSource, opts, processLineData);
2417
+ LineChart: LineChart,
2418
+ PieChart: PieChart,
2419
+ ColumnChart: ColumnChart,
2420
+ BarChart: BarChart,
2421
+ AreaChart: AreaChart,
2422
+ GeoChart: GeoChart,
2423
+ ScatterChart: ScatterChart,
2424
+ BubbleChart: BubbleChart,
2425
+ Timeline: Timeline,
2426
+ charts: {},
2427
+ configure: function (options) {
2428
+ for (var key in options) {
2429
+ if (options.hasOwnProperty(key)) {
2430
+ config[key] = options[key];
2431
+ }
2432
+ }
2433
+ },
2434
+ setDefaultOptions: function (opts) {
2435
+ Chartkick.options = opts;
537
2436
  },
538
- ColumnChart: function(element, dataSource, opts) {
539
- setElement(element, dataSource, opts, processColumnData);
2437
+ eachChart: function (callback) {
2438
+ for (var chartId in Chartkick.charts) {
2439
+ if (Chartkick.charts.hasOwnProperty(chartId)) {
2440
+ callback(Chartkick.charts[chartId]);
2441
+ }
2442
+ }
540
2443
  },
541
- PieChart: function(element, dataSource, opts) {
542
- setElement(element, dataSource, opts, processPieData);
2444
+ config: config,
2445
+ options: {},
2446
+ adapters: adapters,
2447
+ addAdapter: addAdapter,
2448
+ use: function(adapter) {
2449
+ addAdapter(adapter);
2450
+ return Chartkick;
543
2451
  }
544
2452
  };
545
2453
 
546
- window.Chartkick = Chartkick;
547
- })();
2454
+ // not ideal, but allows for simpler integration
2455
+ if (typeof window !== "undefined" && !window.Chartkick) {
2456
+ window.Chartkick = Chartkick;
2457
+ }
2458
+
2459
+ // backwards compatibility for esm require
2460
+ Chartkick.default = Chartkick;
2461
+
2462
+ return Chartkick;
2463
+
2464
+ })));