blazer 2.6.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +13 -28
  5. data/app/assets/javascripts/blazer/ace/ace.js +7235 -8906
  6. data/app/assets/javascripts/blazer/ace/ext-language_tools.js +762 -774
  7. data/app/assets/javascripts/blazer/ace/mode-sql.js +177 -72
  8. data/app/assets/javascripts/blazer/ace/snippets/sql.js +5 -29
  9. data/app/assets/javascripts/blazer/ace/snippets/text.js +1 -6
  10. data/app/assets/javascripts/blazer/ace/theme-twilight.js +8 -106
  11. data/app/assets/javascripts/blazer/application.js +9 -6
  12. data/app/assets/javascripts/blazer/chart.umd.js +13 -0
  13. data/app/assets/javascripts/blazer/chartjs-adapter-date-fns.bundle.js +6322 -0
  14. data/app/assets/javascripts/blazer/chartkick.js +1020 -914
  15. data/app/assets/javascripts/blazer/highlight.min.js +466 -3
  16. data/app/assets/javascripts/blazer/mapkick.bundle.js +1029 -0
  17. data/app/assets/javascripts/blazer/moment-timezone-with-data.js +39 -38
  18. data/app/assets/javascripts/blazer/moment.js +105 -88
  19. data/app/assets/javascripts/blazer/queries.js +10 -1
  20. data/app/assets/javascripts/blazer/rails-ujs.js +746 -0
  21. data/app/assets/javascripts/blazer/vue.global.prod.js +1 -0
  22. data/app/assets/stylesheets/blazer/bootstrap.css +1 -1
  23. data/app/assets/stylesheets/blazer/selectize.css +1 -1
  24. data/app/controllers/blazer/base_controller.rb +85 -84
  25. data/app/controllers/blazer/checks_controller.rb +6 -6
  26. data/app/controllers/blazer/dashboards_controller.rb +24 -24
  27. data/app/controllers/blazer/queries_controller.rb +208 -186
  28. data/app/controllers/blazer/uploads_controller.rb +49 -49
  29. data/app/helpers/blazer/base_helper.rb +0 -4
  30. data/app/models/blazer/query.rb +1 -12
  31. data/app/views/blazer/checks/index.html.erb +1 -1
  32. data/app/views/blazer/dashboards/_form.html.erb +11 -5
  33. data/app/views/blazer/queries/_form.html.erb +19 -14
  34. data/app/views/blazer/queries/docs.html.erb +11 -1
  35. data/app/views/blazer/queries/home.html.erb +9 -6
  36. data/app/views/blazer/queries/run.html.erb +17 -32
  37. data/app/views/blazer/queries/show.html.erb +12 -20
  38. data/app/views/layouts/blazer/application.html.erb +1 -5
  39. data/lib/blazer/adapters/sql_adapter.rb +1 -1
  40. data/lib/blazer/adapters.rb +17 -0
  41. data/lib/blazer/anomaly_detectors.rb +22 -0
  42. data/lib/blazer/data_source.rb +29 -40
  43. data/lib/blazer/engine.rb +11 -9
  44. data/lib/blazer/forecasters.rb +7 -0
  45. data/lib/blazer/result.rb +13 -71
  46. data/lib/blazer/result_cache.rb +71 -0
  47. data/lib/blazer/run_statement.rb +1 -1
  48. data/lib/blazer/run_statement_job.rb +2 -2
  49. data/lib/blazer/statement.rb +3 -1
  50. data/lib/blazer/version.rb +1 -1
  51. data/lib/blazer.rb +51 -53
  52. data/licenses/LICENSE-chart.js.txt +1 -1
  53. data/licenses/LICENSE-chartjs-adapter-date-fns.txt +9 -0
  54. data/licenses/LICENSE-chartkick.js.txt +1 -1
  55. data/licenses/LICENSE-date-fns.txt +21 -0
  56. data/licenses/LICENSE-kurkle-color.txt +9 -0
  57. data/licenses/LICENSE-mapkick-bundle.txt +1029 -0
  58. data/licenses/{LICENSE-jquery-ujs.txt → LICENSE-rails-ujs.txt} +1 -1
  59. data/licenses/LICENSE-vue.txt +1 -1
  60. metadata +26 -18
  61. data/app/assets/javascripts/blazer/Chart.js +0 -16172
  62. data/app/assets/javascripts/blazer/jquery-ujs.js +0 -555
  63. data/app/assets/javascripts/blazer/vue.js +0 -12014
  64. data/lib/blazer/adapters/mongodb_adapter.rb +0 -43
  65. data/lib/blazer/detect_anomalies.R +0 -19
@@ -1,16 +1,15 @@
1
- /*
2
- * Chartkick.js
1
+ /*!
2
+ * Chartkick.js v5.0.1
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v3.2.1
6
5
  * MIT License
7
6
  */
8
7
 
9
8
  (function (global, factory) {
10
9
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
10
  typeof define === 'function' && define.amd ? define(factory) :
12
- (global = global || self, global.Chartkick = factory());
13
- }(this, (function () { 'use strict';
11
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chartkick = factory());
12
+ })(this, (function () { 'use strict';
14
13
 
15
14
  function isArray(variable) {
16
15
  return Object.prototype.toString.call(variable) === "[object Array]";
@@ -27,8 +26,7 @@
27
26
 
28
27
  // https://github.com/madrobby/zepto/blob/master/src/zepto.js
29
28
  function extend(target, source) {
30
- var key;
31
- for (key in source) {
29
+ for (var key in source) {
32
30
  // protect against prototype pollution, defense 1
33
31
  if (key === "__proto__") { continue; }
34
32
 
@@ -53,49 +51,12 @@
53
51
  return target;
54
52
  }
55
53
 
56
- var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
57
-
58
- // https://github.com/Do/iso8601.js
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;
60
- var DECIMAL_SEPARATOR = String(1.5).charAt(1);
61
-
62
- function parseISO8601(input) {
63
- var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
64
- type = Object.prototype.toString.call(input);
65
- if (type === "[object Date]") {
66
- return input;
67
- }
68
- if (type !== "[object String]") {
69
- return;
70
- }
71
- matches = input.match(ISO8601_PATTERN);
72
- if (matches) {
73
- year = parseInt(matches[1], 10);
74
- month = parseInt(matches[3], 10) - 1;
75
- day = parseInt(matches[5], 10);
76
- hour = parseInt(matches[7], 10);
77
- minutes = matches[9] ? parseInt(matches[9], 10) : 0;
78
- seconds = matches[11] ? parseInt(matches[11], 10) : 0;
79
- milliseconds = matches[12] ? parseFloat(DECIMAL_SEPARATOR + matches[12].slice(1)) * 1000 : 0;
80
- result = Date.UTC(year, month, day, hour, minutes, seconds, milliseconds);
81
- if (matches[13] && matches[14]) {
82
- offset = matches[15] * 60;
83
- if (matches[17]) {
84
- offset += parseInt(matches[17], 10);
85
- }
86
- offset *= matches[14] === "-" ? -1 : 1;
87
- result -= offset * 60 * 1000;
88
- }
89
- return new Date(result);
90
- }
91
- }
92
- // end iso8601.js
54
+ var DATE_PATTERN = /^(\d\d\d\d)(?:-)?(\d\d)(?:-)?(\d\d)$/i;
93
55
 
94
56
  function negativeValues(series) {
95
- var i, j, data;
96
- for (i = 0; i < series.length; i++) {
97
- data = series[i].data;
98
- for (j = 0; j < data.length; j++) {
57
+ for (var i = 0; i < series.length; i++) {
58
+ var data = series[i].data;
59
+ for (var j = 0; j < data.length; j++) {
99
60
  if (data[j][1] < 0) {
100
61
  return true;
101
62
  }
@@ -104,48 +65,49 @@
104
65
  return false;
105
66
  }
106
67
 
107
- function toStr(n) {
108
- return "" + n;
68
+ function toStr(obj) {
69
+ return "" + obj;
109
70
  }
110
71
 
111
- function toFloat(n) {
112
- return parseFloat(n);
72
+ function toFloat(obj) {
73
+ return parseFloat(obj);
113
74
  }
114
75
 
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);
76
+ function toDate(obj) {
77
+ if (obj instanceof Date) {
78
+ return obj;
79
+ } else if (typeof obj === "number") {
80
+ return new Date(obj * 1000); // ms
81
+ } else {
82
+ var s = toStr(obj);
83
+ var matches = s.match(DATE_PATTERN);
84
+ if (matches) {
85
+ var year = parseInt(matches[1], 10);
86
+ var month = parseInt(matches[2], 10) - 1;
87
+ var day = parseInt(matches[3], 10);
126
88
  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
- }
89
+ } else {
90
+ // try our best to get the str into iso8601
91
+ // TODO be smarter about this
92
+ var str = s.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
93
+ // Date.parse returns milliseconds if valid and NaN if invalid
94
+ return new Date(Date.parse(str) || s);
133
95
  }
134
96
  }
135
- return n;
136
97
  }
137
98
 
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]]);
99
+ function toArr(obj) {
100
+ if (isArray(obj)) {
101
+ return obj;
102
+ } else {
103
+ var arr = [];
104
+ for (var i in obj) {
105
+ if (Object.prototype.hasOwnProperty.call(obj, i)) {
106
+ arr.push([i, obj[i]]);
144
107
  }
145
108
  }
146
- n = arr;
109
+ return arr;
147
110
  }
148
- return n;
149
111
  }
150
112
 
151
113
  function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
@@ -154,8 +116,8 @@
154
116
  var options = merge({}, defaultOptions);
155
117
  options = merge(options, chartOptions || {});
156
118
 
157
- if (chart.hideLegend || "legend" in opts) {
158
- hideLegend(options, opts.legend, chart.hideLegend);
119
+ if (chart.singleSeriesFormat || "legend" in opts) {
120
+ hideLegend(options, opts.legend, chart.singleSeriesFormat);
159
121
  }
160
122
 
161
123
  if (opts.title) {
@@ -205,32 +167,63 @@
205
167
  return a[0] - b[0];
206
168
  }
207
169
 
170
+ // needed since sort() without arguments does string comparison
208
171
  function sortByNumber(a, b) {
209
172
  return a - b;
210
173
  }
211
174
 
212
- function isMinute(d) {
213
- return d.getMilliseconds() === 0 && d.getSeconds() === 0;
175
+ function every(values, fn) {
176
+ for (var i = 0; i < values.length; i++) {
177
+ if (!fn(values[i])) {
178
+ return false;
179
+ }
180
+ }
181
+ return true;
214
182
  }
215
183
 
216
- function isHour(d) {
217
- return isMinute(d) && d.getMinutes() === 0;
184
+ function isDay(timeUnit) {
185
+ return timeUnit === "day" || timeUnit === "week" || timeUnit === "month" || timeUnit === "year";
218
186
  }
219
187
 
220
- function isDay(d) {
221
- return isHour(d) && d.getHours() === 0;
222
- }
188
+ function calculateTimeUnit(values, maxDay) {
189
+ if ( maxDay === void 0 ) maxDay = false;
223
190
 
224
- function isWeek(d, dayOfWeek) {
225
- return isDay(d) && d.getDay() === dayOfWeek;
226
- }
191
+ if (values.length === 0) {
192
+ return null;
193
+ }
227
194
 
228
- function isMonth(d) {
229
- return isDay(d) && d.getDate() === 1;
230
- }
195
+ var minute = every(values, function (d) { return d.getMilliseconds() === 0 && d.getSeconds() === 0; });
196
+ if (!minute) {
197
+ return null;
198
+ }
199
+
200
+ var hour = every(values, function (d) { return d.getMinutes() === 0; });
201
+ if (!hour) {
202
+ return "minute";
203
+ }
204
+
205
+ var day = every(values, function (d) { return d.getHours() === 0; });
206
+ if (!day) {
207
+ return "hour";
208
+ }
209
+
210
+ if (maxDay) {
211
+ return "day";
212
+ }
213
+
214
+ var month = every(values, function (d) { return d.getDate() === 1; });
215
+ if (!month) {
216
+ var dayOfWeek = values[0].getDay();
217
+ var week = every(values, function (d) { return d.getDay() === dayOfWeek; });
218
+ return (week ? "week" : "day");
219
+ }
220
+
221
+ var year = every(values, function (d) { return d.getMonth() === 0; });
222
+ if (!year) {
223
+ return "month";
224
+ }
231
225
 
232
- function isYear(d) {
233
- return isMonth(d) && d.getMonth() === 0;
226
+ return "year";
234
227
  }
235
228
 
236
229
  function isDate(obj) {
@@ -258,9 +251,14 @@
258
251
  var round = options.round;
259
252
 
260
253
  if (options.byteScale) {
261
- var suffixIdx;
254
+ var positive = value >= 0;
255
+ if (!positive) {
256
+ value *= -1;
257
+ }
258
+
262
259
  var baseValue = axis ? options.byteScale : value;
263
260
 
261
+ var suffixIdx;
264
262
  if (baseValue >= 1152921504606846976) {
265
263
  value /= 1152921504606846976;
266
264
  suffixIdx = 6;
@@ -294,6 +292,11 @@
294
292
  precision = value >= 1000 ? 4 : 3;
295
293
  }
296
294
  suffix = " " + byteSuffixes[suffixIdx];
295
+
296
+ // flip value back
297
+ if (!positive) {
298
+ value *= -1;
299
+ }
297
300
  }
298
301
 
299
302
  if (precision !== undefined && round !== undefined) {
@@ -345,58 +348,52 @@
345
348
  return null;
346
349
  }
347
350
 
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
- }
360
-
361
351
  var baseOptions = {
362
352
  maintainAspectRatio: false,
363
353
  animation: false,
364
- tooltips: {
365
- displayColors: false,
366
- callbacks: {}
354
+ plugins: {
355
+ legend: {},
356
+ tooltip: {
357
+ displayColors: false,
358
+ callbacks: {}
359
+ },
360
+ title: {
361
+ font: {
362
+ size: 20
363
+ },
364
+ color: "#333"
365
+ }
367
366
  },
368
- legend: {},
369
- title: {fontSize: 20, fontColor: "#333"}
367
+ interaction: {}
370
368
  };
371
369
 
372
- var defaultOptions = {
370
+ var defaultOptions$2 = {
373
371
  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
372
+ y: {
373
+ ticks: {
374
+ maxTicksLimit: 4
375
+ },
376
+ title: {
377
+ font: {
378
+ size: 16
390
379
  },
391
- scaleLabel: {
392
- fontSize: 16,
393
- // fontStyle: "bold",
394
- fontColor: "#333"
380
+ color: "#333"
381
+ },
382
+ grid: {}
383
+ },
384
+ x: {
385
+ grid: {
386
+ drawOnChartArea: false
387
+ },
388
+ title: {
389
+ font: {
390
+ size: 16
395
391
  },
396
- time: {},
397
- ticks: {}
398
- }
399
- ]
392
+ color: "#333"
393
+ },
394
+ time: {},
395
+ ticks: {}
396
+ }
400
397
  }
401
398
  };
402
399
 
@@ -407,79 +404,77 @@
407
404
  "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
408
405
  ];
409
406
 
410
- var hideLegend = function (options, legend, hideLegend) {
407
+ function hideLegend$2(options, legend, hideLegend) {
411
408
  if (legend !== undefined) {
412
- options.legend.display = !!legend;
409
+ options.plugins.legend.display = !!legend;
413
410
  if (legend && legend !== true) {
414
- options.legend.position = legend;
411
+ options.plugins.legend.position = legend;
415
412
  }
416
413
  } else if (hideLegend) {
417
- options.legend.display = false;
414
+ options.plugins.legend.display = false;
418
415
  }
419
- };
416
+ }
420
417
 
421
- var setTitle = function (options, title) {
422
- options.title.display = true;
423
- options.title.text = title;
424
- };
418
+ function setTitle$2(options, title) {
419
+ options.plugins.title.display = true;
420
+ options.plugins.title.text = title;
421
+ }
425
422
 
426
- var setMin = function (options, min) {
423
+ function setMin$2(options, min) {
427
424
  if (min !== null) {
428
- options.scales.yAxes[0].ticks.min = toFloat(min);
425
+ options.scales.y.min = toFloat(min);
429
426
  }
430
- };
427
+ }
431
428
 
432
- var setMax = function (options, max) {
433
- options.scales.yAxes[0].ticks.max = toFloat(max);
434
- };
429
+ function setMax$2(options, max) {
430
+ options.scales.y.max = toFloat(max);
431
+ }
435
432
 
436
- var setBarMin = function (options, min) {
433
+ function setBarMin$1(options, min) {
437
434
  if (min !== null) {
438
- options.scales.xAxes[0].ticks.min = toFloat(min);
435
+ options.scales.x.min = toFloat(min);
439
436
  }
440
- };
437
+ }
441
438
 
442
- var setBarMax = function (options, max) {
443
- options.scales.xAxes[0].ticks.max = toFloat(max);
444
- };
439
+ function setBarMax$1(options, max) {
440
+ options.scales.x.max = toFloat(max);
441
+ }
445
442
 
446
- var setStacked = function (options, stacked) {
447
- options.scales.xAxes[0].stacked = !!stacked;
448
- options.scales.yAxes[0].stacked = !!stacked;
449
- };
443
+ function setStacked$2(options, stacked) {
444
+ options.scales.x.stacked = !!stacked;
445
+ options.scales.y.stacked = !!stacked;
446
+ }
450
447
 
451
- var setXtitle = function (options, title) {
452
- options.scales.xAxes[0].scaleLabel.display = true;
453
- options.scales.xAxes[0].scaleLabel.labelString = title;
454
- };
448
+ function setXtitle$2(options, title) {
449
+ options.scales.x.title.display = true;
450
+ options.scales.x.title.text = title;
451
+ }
455
452
 
456
- var setYtitle = function (options, title) {
457
- options.scales.yAxes[0].scaleLabel.display = true;
458
- options.scales.yAxes[0].scaleLabel.labelString = title;
459
- };
453
+ function setYtitle$2(options, title) {
454
+ options.scales.y.title.display = true;
455
+ options.scales.y.title.text = title;
456
+ }
460
457
 
461
458
  // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
462
- var addOpacity = function(hex, opacity) {
459
+ function addOpacity(hex, opacity) {
463
460
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
464
461
  return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
465
- };
462
+ }
466
463
 
467
- // check if not null or undefined
468
- // https://stackoverflow.com/a/27757708/1177228
469
- var notnull = function(x) {
470
- return x != null;
471
- };
464
+ function notnull(x) {
465
+ return x !== null && x !== undefined;
466
+ }
472
467
 
473
- var setLabelSize = function (chart, data, options) {
468
+ function setLabelSize(chart, data, options) {
474
469
  var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
475
470
  if (maxLabelSize > 25) {
476
471
  maxLabelSize = 25;
477
472
  } else if (maxLabelSize < 10) {
478
473
  maxLabelSize = 10;
479
474
  }
480
- if (!options.scales.xAxes[0].ticks.callback) {
481
- options.scales.xAxes[0].ticks.callback = function (value) {
482
- value = toStr(value);
475
+ if (!options.scales.x.ticks.callback) {
476
+ options.scales.x.ticks.callback = function (value) {
477
+ value = toStr(this.getLabelForValue(value));
483
478
  if (value.length > maxLabelSize) {
484
479
  return value.substring(0, maxLabelSize - 2) + "...";
485
480
  } else {
@@ -487,18 +482,33 @@
487
482
  }
488
483
  };
489
484
  }
490
- };
485
+ }
491
486
 
492
- var setFormatOptions = function(chart, options, chartType) {
493
- var formatOptions = {
487
+ function calculateScale(series) {
488
+ var scale = 1;
489
+ var max = maxAbsY(series);
490
+ while (max >= 1024) {
491
+ scale *= 1024;
492
+ max /= 1024;
493
+ }
494
+ return scale;
495
+ }
496
+
497
+ function setFormatOptions$1(chart, options, chartType) {
498
+ // options to apply to x and r values for scatter and bubble
499
+ var numericOptions = {
500
+ thousands: chart.options.thousands,
501
+ decimal: chart.options.decimal
502
+ };
503
+
504
+ // options to apply to y value
505
+ var formatOptions = merge({
494
506
  prefix: chart.options.prefix,
495
507
  suffix: chart.options.suffix,
496
- thousands: chart.options.thousands,
497
- decimal: chart.options.decimal,
498
508
  precision: chart.options.precision,
499
509
  round: chart.options.round,
500
510
  zeros: chart.options.zeros
501
- };
511
+ }, numericOptions);
502
512
 
503
513
  if (chart.options.bytes) {
504
514
  var series = chart.data;
@@ -506,232 +516,303 @@
506
516
  series = [{data: series}];
507
517
  }
508
518
 
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
- }
517
- }
518
- }
519
-
520
- // calculate scale
521
- var scale = 1;
522
- while (max >= 1024) {
523
- scale *= 1024;
524
- max /= 1024;
525
- }
526
-
527
519
  // set step size
528
- formatOptions.byteScale = scale;
520
+ formatOptions.byteScale = calculateScale(series);
529
521
  }
530
522
 
531
523
  if (chartType !== "pie") {
532
- var myAxes = options.scales.yAxes;
524
+ var axis = options.scales.y;
533
525
  if (chartType === "bar") {
534
- myAxes = options.scales.xAxes;
526
+ axis = options.scales.x;
535
527
  }
536
528
 
537
529
  if (formatOptions.byteScale) {
538
- if (!myAxes[0].ticks.stepSize) {
539
- myAxes[0].ticks.stepSize = formatOptions.byteScale / 2;
530
+ if (!axis.ticks.stepSize) {
531
+ axis.ticks.stepSize = formatOptions.byteScale / 2;
540
532
  }
541
- if (!myAxes[0].ticks.maxTicksLimit) {
542
- myAxes[0].ticks.maxTicksLimit = 4;
533
+ if (!axis.ticks.maxTicksLimit) {
534
+ axis.ticks.maxTicksLimit = 4;
543
535
  }
544
536
  }
545
537
 
546
- if (!myAxes[0].ticks.callback) {
547
- myAxes[0].ticks.callback = function (value) {
538
+ if (!axis.ticks.callback) {
539
+ axis.ticks.callback = function (value) {
548
540
  return formatValue("", value, formatOptions, true);
549
541
  };
550
542
  }
543
+
544
+ if ((chartType === "scatter" || chartType === "bubble") && !options.scales.x.ticks.callback) {
545
+ options.scales.x.ticks.callback = function (value) {
546
+ return formatValue("", value, numericOptions, true);
547
+ };
548
+ }
551
549
  }
552
550
 
553
- if (!options.tooltips.callbacks.label) {
551
+ if (!options.plugins.tooltip.callbacks.label) {
554
552
  if (chartType === "scatter") {
555
- options.tooltips.callbacks.label = function (item, data) {
556
- var label = data.datasets[item.datasetIndex].label || '';
553
+ options.plugins.tooltip.callbacks.label = function (context) {
554
+ var label = context.dataset.label || '';
557
555
  if (label) {
558
556
  label += ': ';
559
557
  }
560
- return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
558
+
559
+ var dataPoint = context.parsed;
560
+ return label + '(' + formatValue('', dataPoint.x, numericOptions) + ', ' + formatValue('', dataPoint.y, formatOptions) + ')';
561
561
  };
562
562
  } else if (chartType === "bubble") {
563
- options.tooltips.callbacks.label = function (item, data) {
564
- var label = data.datasets[item.datasetIndex].label || '';
563
+ options.plugins.tooltip.callbacks.label = function (context) {
564
+ var label = context.dataset.label || '';
565
565
  if (label) {
566
566
  label += ': ';
567
567
  }
568
- var dataPoint = data.datasets[item.datasetIndex].data[item.index];
569
- return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')';
568
+ var dataPoint = context.raw;
569
+ return label + '(' + formatValue('', dataPoint.x, numericOptions) + ', ' + formatValue('', dataPoint.y, formatOptions) + ', ' + formatValue('', dataPoint.v, numericOptions) + ')';
570
570
  };
571
571
  } else if (chartType === "pie") {
572
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
- }
585
-
586
- return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
573
+ options.plugins.tooltip.callbacks.label = function (context) {
574
+ return formatValue('', context.parsed, formatOptions);
587
575
  };
588
576
  } else {
589
- var valueLabel = chartType === "bar" ? "xLabel" : "yLabel";
590
- options.tooltips.callbacks.label = function (tooltipItem, data) {
591
- var label = data.datasets[tooltipItem.datasetIndex].label || '';
577
+ var valueLabel = chartType === "bar" ? "x" : "y";
578
+ options.plugins.tooltip.callbacks.label = function (context) {
579
+ // don't show null values for stacked charts
580
+ if (context.parsed[valueLabel] === null) {
581
+ return;
582
+ }
583
+
584
+ var label = context.dataset.label || '';
592
585
  if (label) {
593
586
  label += ': ';
594
587
  }
595
- return formatValue(label, tooltipItem[valueLabel], formatOptions);
588
+ return formatValue(label, context.parsed[valueLabel], formatOptions);
596
589
  };
597
590
  }
598
591
  }
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
592
 
607
- var colors = chart.options.colors || defaultColors;
593
+ // avoid formatting x-axis labels
594
+ // by default, Chart.js applies locale
595
+ if ((chartType === "line" || chartType === "area") && chart.xtype === "number") {
596
+ if (!options.scales.x.ticks.callback) {
597
+ options.scales.x.ticks.callback = function (value) {
598
+ return toStr(value);
599
+ };
600
+ }
608
601
 
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;
602
+ if (!options.plugins.tooltip.callbacks.title) {
603
+ options.plugins.tooltip.callbacks.title = function (context) {
604
+ return toStr(context[0].parsed.x);
605
+ };
606
+ }
607
+ }
608
+ }
616
609
 
617
- var series = chart.data;
610
+ function maxAbsY(series) {
611
+ var max = 0;
612
+ for (var i = 0; i < series.length; i++) {
613
+ var data = series[i].data;
614
+ for (var j = 0; j < data.length; j++) {
615
+ var v = Math.abs(data[j][1]);
616
+ if (v > max) {
617
+ max = v;
618
+ }
619
+ }
620
+ }
621
+ return max;
622
+ }
618
623
 
624
+ function maxR(series) {
625
+ // start at zero since radius must be positive
619
626
  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
+ for (var i = 0; i < series.length; i++) {
628
+ var data = series[i].data;
629
+ for (var j = 0; j < data.length; j++) {
630
+ var v = data[j][2];
631
+ if (v > max) {
632
+ max = v;
627
633
  }
628
634
  }
629
635
  }
636
+ return max;
637
+ }
630
638
 
631
- var i, j, s, d, key, rows = [], rows2 = [];
639
+ var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
632
640
 
633
- if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
634
- var sortedLabels = [];
641
+ function prepareDefaultData(chart) {
642
+ var series = chart.data;
643
+ var rows = {};
644
+ var keys = [];
645
+ var labels = [];
646
+ var values = [];
635
647
 
636
- for (i = 0; i < series.length; i++) {
637
- s = series[i];
648
+ for (var i = 0; i < series.length; i++) {
649
+ var data = series[i].data;
638
650
 
639
- for (j = 0; j < s.data.length; j++) {
640
- d = s.data[j];
641
- key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
642
- if (!rows[key]) {
643
- rows[key] = new Array(series.length);
644
- }
645
- rows[key][i] = toFloat(d[1]);
646
- if (sortedLabels.indexOf(key) === -1) {
647
- sortedLabels.push(key);
648
- }
651
+ for (var j = 0; j < data.length; j++) {
652
+ var d = data[j];
653
+ var key = chart.xtype === "datetime" ? d[0].getTime() : d[0];
654
+ if (!rows[key]) {
655
+ rows[key] = new Array(series.length);
656
+ keys.push(key);
649
657
  }
658
+ rows[key][i] = d[1];
650
659
  }
660
+ }
661
+
662
+ if (chart.xtype === "datetime" || chart.xtype === "number") {
663
+ keys.sort(sortByNumber);
664
+ }
665
+
666
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
667
+ values.push([]);
668
+ }
669
+
670
+ for (var i$2 = 0; i$2 < keys.length; i$2++) {
671
+ var key$1 = keys[i$2];
651
672
 
652
- if (chart.xtype === "datetime" || chart.xtype === "number") {
653
- sortedLabels.sort(sortByNumber);
673
+ var label = chart.xtype === "datetime" ? new Date(key$1) : key$1;
674
+ labels.push(label);
675
+
676
+ var row = rows[key$1];
677
+ for (var j$1 = 0; j$1 < series.length; j$1++) {
678
+ var v = row[j$1];
679
+ // Chart.js doesn't like undefined
680
+ values[j$1].push(v === undefined ? null : v);
654
681
  }
682
+ }
683
+
684
+ return {
685
+ labels: labels,
686
+ values: values
687
+ };
688
+ }
655
689
 
656
- for (j = 0; j < series.length; j++) {
657
- rows2.push([]);
690
+ function prepareBubbleData(chart) {
691
+ var series = chart.data;
692
+ var values = [];
693
+ var max = maxR(series);
694
+
695
+ for (var i = 0; i < series.length; i++) {
696
+ var data = series[i].data;
697
+ var points = [];
698
+ for (var j = 0; j < data.length; j++) {
699
+ var v = data[j];
700
+ points.push({
701
+ x: v[0],
702
+ y: v[1],
703
+ r: v[2] * 20 / max,
704
+ // custom attribute, for tooltip
705
+ v: v[2]
706
+ });
658
707
  }
708
+ values.push(points);
709
+ }
659
710
 
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]);
683
- }
711
+ return {
712
+ labels: [],
713
+ values: values
714
+ };
715
+ }
716
+
717
+ // scatter or numeric line/area
718
+ function prepareNumberData(chart) {
719
+ var series = chart.data;
720
+ var values = [];
721
+
722
+ for (var i = 0; i < series.length; i++) {
723
+ var data = series[i].data;
724
+
725
+ data.sort(sortByNumberSeries);
726
+
727
+ var points = [];
728
+ for (var j = 0; j < data.length; j++) {
729
+ var v = data[j];
730
+ points.push({
731
+ x: v[0],
732
+ y: v[1]
733
+ });
684
734
  }
735
+ values.push(points);
736
+ }
737
+
738
+ return {
739
+ labels: [],
740
+ values: values
741
+ };
742
+ }
743
+
744
+ function prepareData(chart, chartType) {
745
+ if (chartType === "bubble") {
746
+ return prepareBubbleData(chart);
747
+ } else if (chart.xtype === "number" && chartType !== "bar" && chartType !== "column") {
748
+ return prepareNumberData(chart);
685
749
  } 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);
702
- }
750
+ return prepareDefaultData(chart);
703
751
  }
752
+ }
704
753
 
705
- for (i = 0; i < series.length; i++) {
706
- s = series[i];
754
+ function createDataTable(chart, options, chartType) {
755
+ var ref = prepareData(chart, chartType);
756
+ var labels = ref.labels;
757
+ var values = ref.values;
707
758
 
708
- var color = s.color || colors[i];
709
- var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
759
+ var series = chart.data;
760
+ var datasets = [];
761
+ var colors = chart.options.colors || defaultColors;
762
+ for (var i = 0; i < series.length; i++) {
763
+ var s = series[i];
764
+
765
+ // use colors for each bar for single series format
766
+ var color = (void 0);
767
+ var backgroundColor = (void 0);
768
+ if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
769
+ color = colors;
770
+ backgroundColor = [];
771
+ for (var j = 0; j < colors.length; j++) {
772
+ backgroundColor[j] = addOpacity(color[j], 0.5);
773
+ }
774
+ } else {
775
+ color = s.color || colors[i];
776
+ backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
777
+ }
710
778
 
711
779
  var dataset = {
712
780
  label: s.name || "",
713
- data: rows2[i],
781
+ data: values[i],
714
782
  fill: chartType === "area",
715
783
  borderColor: color,
716
784
  backgroundColor: backgroundColor,
717
- pointBackgroundColor: color,
718
- borderWidth: 2,
719
- pointHoverBackgroundColor: color
785
+ borderWidth: 2
720
786
  };
721
787
 
788
+ var pointChart = chartType === "line" || chartType === "area" || chartType === "scatter" || chartType === "bubble";
789
+ if (pointChart) {
790
+ dataset.pointBackgroundColor = color;
791
+ dataset.pointHoverBackgroundColor = color;
792
+ dataset.pointHitRadius = 50;
793
+ }
794
+
795
+ if (chartType === "bubble") {
796
+ dataset.pointBackgroundColor = backgroundColor;
797
+ dataset.pointHoverBackgroundColor = backgroundColor;
798
+ dataset.pointHoverBorderWidth = 2;
799
+ }
800
+
722
801
  if (s.stack) {
723
802
  dataset.stack = s.stack;
724
803
  }
725
804
 
726
805
  var curve = seriesOption(chart, s, "curve");
727
806
  if (curve === false) {
728
- dataset.lineTension = 0;
807
+ dataset.tension = 0;
808
+ } else if (pointChart) {
809
+ dataset.tension = 0.4;
729
810
  }
730
811
 
731
812
  var points = seriesOption(chart, s, "points");
732
813
  if (points === false) {
733
814
  dataset.pointRadius = 0;
734
- dataset.pointHitRadius = 5;
815
+ dataset.pointHoverRadius = 0;
735
816
  }
736
817
 
737
818
  dataset = merge(dataset, chart.options.dataset || {});
@@ -745,149 +826,149 @@
745
826
  var xmax = chart.options.xmax;
746
827
 
747
828
  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
829
  if (notnull(xmin)) {
753
- options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime();
830
+ options.scales.x.min = toDate(xmin).getTime();
754
831
  }
755
832
  if (notnull(xmax)) {
756
- options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime();
833
+ options.scales.x.max = toDate(xmax).getTime();
757
834
  }
758
835
  } else if (chart.xtype === "number") {
759
836
  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
- }
766
-
767
- // for empty datetime chart
768
- if (chart.xtype === "datetime" && labels.length === 0) {
769
- if (notnull(xmin)) {
770
- labels.push(toDate(xmin));
837
+ options.scales.x.min = xmin;
771
838
  }
772
839
  if (notnull(xmax)) {
773
- labels.push(toDate(xmax));
840
+ options.scales.x.max = xmax;
774
841
  }
775
- day = false;
776
- week = false;
777
- month = false;
778
- year = false;
779
- hour = false;
780
- minute = false;
781
842
  }
782
843
 
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();
844
+ if (chart.xtype === "datetime") {
845
+ var timeUnit = calculateTimeUnit(labels);
786
846
 
787
- for (i = 1; i < labels.length; i++) {
788
- var value$1 = labels[i].getTime();
789
- if (value$1 < minTime) {
790
- minTime = value$1;
847
+ // for empty datetime chart
848
+ if (labels.length === 0) {
849
+ if (notnull(xmin)) {
850
+ labels.push(toDate(xmin));
791
851
  }
792
- if (value$1 > maxTime) {
793
- maxTime = value$1;
852
+ if (notnull(xmax)) {
853
+ labels.push(toDate(xmax));
794
854
  }
795
855
  }
796
856
 
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;
857
+ if (labels.length > 0) {
858
+ var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
859
+ var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
860
+
861
+ for (var i$1 = 1; i$1 < labels.length; i$1++) {
862
+ var value = labels[i$1].getTime();
863
+ if (value < minTime) {
864
+ minTime = value;
865
+ }
866
+ if (value > maxTime) {
867
+ maxTime = value;
868
+ }
818
869
  }
819
870
 
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;
871
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
872
+
873
+ if (!options.scales.x.time.unit) {
874
+ var step;
875
+ if (timeUnit === "year" || timeDiff > 365 * 10) {
876
+ options.scales.x.time.unit = "year";
877
+ step = 365;
878
+ } else if (timeUnit === "month" || timeDiff > 30 * 10) {
879
+ options.scales.x.time.unit = "month";
880
+ step = 30;
881
+ } else if (timeUnit === "week" || timeUnit === "day" || timeDiff > 10) {
882
+ options.scales.x.time.unit = "day";
883
+ step = 1;
884
+ } else if (timeUnit === "hour" || timeDiff > 0.5) {
885
+ options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
886
+ options.scales.x.time.unit = "hour";
887
+ step = 1 / 24.0;
888
+ } else if (timeUnit === "minute") {
889
+ options.scales.x.time.displayFormats = {minute: "h:mm a"};
890
+ options.scales.x.time.unit = "minute";
891
+ step = 1 / 24.0 / 60.0;
892
+ }
893
+
894
+ if (step && timeDiff > 0) {
895
+ // width not available for hidden elements
896
+ var width = chart.element.offsetWidth;
897
+ if (width > 0) {
898
+ var unitStepSize = Math.ceil(timeDiff / step / (width / 100.0));
899
+ if (timeUnit === "week" && step === 1) {
900
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
901
+ }
902
+ options.scales.x.ticks.stepSize = unitStepSize;
903
+ }
824
904
  }
825
- options.scales.xAxes[0].time.unitStepSize = unitStepSize;
826
905
  }
827
- }
828
906
 
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";
907
+ if (!options.scales.x.time.tooltipFormat) {
908
+ if (timeUnit === "year") {
909
+ options.scales.x.time.tooltipFormat = "yyyy";
910
+ } else if (timeUnit === "month") {
911
+ options.scales.x.time.tooltipFormat = "MMM yyyy";
912
+ } else if (timeUnit === "week" || timeUnit === "day") {
913
+ options.scales.x.time.tooltipFormat = "PP";
914
+ } else if (timeUnit === "hour") {
915
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
916
+ } else if (timeUnit === "minute") {
917
+ options.scales.x.time.tooltipFormat = "h:mm a";
918
+ }
836
919
  }
837
920
  }
838
921
  }
839
922
 
840
- var data = {
923
+ return {
841
924
  labels: labels,
842
925
  datasets: datasets
843
926
  };
927
+ }
844
928
 
845
- return data;
846
- };
847
-
848
- var defaultExport = function defaultExport(library) {
929
+ var defaultExport$2 = function defaultExport(library) {
849
930
  this.name = "chartjs";
850
931
  this.library = library;
851
932
  };
852
933
 
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;
934
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
935
+ if (!chartType) {
936
+ chartType = "line";
858
937
  }
859
938
 
860
- var options = jsOptions(chart, merge(chartOptions, chart.options));
861
- setFormatOptions(chart, options, chartType);
939
+ var chartOptions = {};
862
940
 
863
- var data = createDataTable(chart, options, chartType || "line", this.library);
941
+ var options = jsOptions$2(chart, merge(chartOptions, chart.options));
942
+ setFormatOptions$1(chart, options, chartType);
943
+
944
+ var data = createDataTable(chart, options, chartType);
864
945
 
865
946
  if (chart.xtype === "number") {
866
- options.scales.xAxes[0].type = "linear";
867
- options.scales.xAxes[0].position = "bottom";
947
+ options.scales.x.type = options.scales.x.type || "linear";
948
+ options.scales.x.position = options.scales.x.position || "bottom";
868
949
  } else {
869
- options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
950
+ options.scales.x.type = chart.xtype === "string" ? "category" : "time";
870
951
  }
871
952
 
872
953
  this.drawChart(chart, "line", data, options);
873
954
  };
874
955
 
875
- defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
956
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
876
957
  var options = merge({}, baseOptions);
877
958
  if (chart.options.donut) {
878
- options.cutoutPercentage = 50;
959
+ options.cutout = "50%";
879
960
  }
880
961
 
881
962
  if ("legend" in chart.options) {
882
- hideLegend(options, chart.options.legend);
963
+ hideLegend$2(options, chart.options.legend);
883
964
  }
884
965
 
885
966
  if (chart.options.title) {
886
- setTitle(options, chart.options.title);
967
+ setTitle$2(options, chart.options.title);
887
968
  }
888
969
 
889
970
  options = merge(options, chart.options.library || {});
890
- setFormatOptions(chart, options, "pie");
971
+ setFormatOptions$1(chart, options, "pie");
891
972
 
892
973
  var labels = [];
893
974
  var values = [];
@@ -911,61 +992,76 @@
911
992
  this.drawChart(chart, "pie", data, options);
912
993
  };
913
994
 
914
- defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
995
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
996
  var options;
916
997
  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);
998
+ var barOptions = merge(baseOptions, defaultOptions$2);
999
+ barOptions.indexAxis = "y";
1000
+
1001
+ // ensure gridlines have proper orientation
1002
+ barOptions.scales.x.grid.drawOnChartArea = true;
1003
+ barOptions.scales.y.grid.drawOnChartArea = false;
1004
+ delete barOptions.scales.y.ticks.maxTicksLimit;
1005
+
1006
+ options = jsOptionsFunc(barOptions, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options);
920
1007
  } else {
921
- options = jsOptions(chart, chart.options);
1008
+ options = jsOptions$2(chart, chart.options);
922
1009
  }
923
- setFormatOptions(chart, options, chartType);
924
- var data = createDataTable(chart, options, "column", this.library);
1010
+ setFormatOptions$1(chart, options, chartType);
1011
+ var data = createDataTable(chart, options, "column");
925
1012
  if (chartType !== "bar") {
926
1013
  setLabelSize(chart, data, options);
927
1014
  }
928
- this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
1015
+ if (!("mode" in options.interaction)) {
1016
+ options.interaction.mode = "index";
1017
+ }
1018
+ this.drawChart(chart, "bar", data, options);
929
1019
  };
930
1020
 
931
- defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1021
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
932
1022
  this.renderLineChart(chart, "area");
933
1023
  };
934
1024
 
935
- defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1025
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
936
1026
  this.renderColumnChart(chart, "bar");
937
1027
  };
938
1028
 
939
- defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
1029
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
1030
  chartType = chartType || "scatter";
941
1031
 
942
- var options = jsOptions(chart, chart.options);
943
- setFormatOptions(chart, options, chartType);
1032
+ var options = jsOptions$2(chart, chart.options);
1033
+ setFormatOptions$1(chart, options, chartType);
944
1034
 
945
- if (!("showLines" in options)) {
946
- options.showLines = false;
1035
+ if (!("showLine" in options)) {
1036
+ options.showLine = false;
947
1037
  }
948
1038
 
949
- var data = createDataTable(chart, options, chartType, this.library);
1039
+ var data = createDataTable(chart, options, chartType);
1040
+
1041
+ options.scales.x.type = options.scales.x.type || "linear";
1042
+ options.scales.x.position = options.scales.x.position || "bottom";
950
1043
 
951
- options.scales.xAxes[0].type = "linear";
952
- options.scales.xAxes[0].position = "bottom";
1044
+ // prevent grouping hover and tooltips
1045
+ if (!("mode" in options.interaction)) {
1046
+ options.interaction.mode = "nearest";
1047
+ }
953
1048
 
954
1049
  this.drawChart(chart, chartType, data, options);
955
1050
  };
956
1051
 
957
- defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
1052
+ defaultExport$2.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
1053
  this.renderScatterChart(chart, "bubble");
959
1054
  };
960
1055
 
961
- defaultExport.prototype.destroy = function destroy (chart) {
1056
+ defaultExport$2.prototype.destroy = function destroy (chart) {
962
1057
  if (chart.chart) {
963
1058
  chart.chart.destroy();
964
1059
  }
965
1060
  };
966
1061
 
967
- defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
1062
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
968
1063
  this.destroy(chart);
1064
+ if (chart.destroyed) { return; }
969
1065
 
970
1066
  var chartOptions = {
971
1067
  type: type,
@@ -1024,10 +1120,13 @@
1024
1120
  series: {
1025
1121
  marker: {}
1026
1122
  }
1123
+ },
1124
+ time: {
1125
+ useUTC: false
1027
1126
  }
1028
1127
  };
1029
1128
 
1030
- var hideLegend$1 = function (options, legend, hideLegend) {
1129
+ function hideLegend$1(options, legend, hideLegend) {
1031
1130
  if (legend !== undefined) {
1032
1131
  options.legend.enabled = !!legend;
1033
1132
  if (legend && legend !== true) {
@@ -1042,38 +1141,38 @@
1042
1141
  } else if (hideLegend) {
1043
1142
  options.legend.enabled = false;
1044
1143
  }
1045
- };
1144
+ }
1046
1145
 
1047
- var setTitle$1 = function (options, title) {
1146
+ function setTitle$1(options, title) {
1048
1147
  options.title.text = title;
1049
- };
1148
+ }
1050
1149
 
1051
- var setMin$1 = function (options, min) {
1150
+ function setMin$1(options, min) {
1052
1151
  options.yAxis.min = min;
1053
- };
1152
+ }
1054
1153
 
1055
- var setMax$1 = function (options, max) {
1154
+ function setMax$1(options, max) {
1056
1155
  options.yAxis.max = max;
1057
- };
1156
+ }
1058
1157
 
1059
- var setStacked$1 = function (options, stacked) {
1158
+ function setStacked$1(options, stacked) {
1060
1159
  var stackedValue = stacked ? (stacked === true ? "normal" : stacked) : null;
1061
1160
  options.plotOptions.series.stacking = stackedValue;
1062
1161
  options.plotOptions.area.stacking = stackedValue;
1063
1162
  options.plotOptions.areaspline.stacking = stackedValue;
1064
- };
1163
+ }
1065
1164
 
1066
- var setXtitle$1 = function (options, title) {
1165
+ function setXtitle$1(options, title) {
1067
1166
  options.xAxis.title.text = title;
1068
- };
1167
+ }
1069
1168
 
1070
- var setYtitle$1 = function (options, title) {
1169
+ function setYtitle$1(options, title) {
1071
1170
  options.yAxis.title.text = title;
1072
- };
1171
+ }
1073
1172
 
1074
1173
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
1174
 
1076
- var setFormatOptions$1 = function(chart, options, chartType) {
1175
+ function setFormatOptions(chart, options, chartType) {
1077
1176
  var formatOptions = {
1078
1177
  prefix: chart.options.prefix,
1079
1178
  suffix: chart.options.suffix,
@@ -1084,18 +1183,19 @@
1084
1183
  zeros: chart.options.zeros
1085
1184
  };
1086
1185
 
1087
- if (chartType !== "pie" && !options.yAxis.labels.formatter) {
1186
+ // skip when axis is an array (like with min/max)
1187
+ if (chartType !== "pie" && !isArray(options.yAxis) && !options.yAxis.labels.formatter) {
1088
1188
  options.yAxis.labels.formatter = function () {
1089
1189
  return formatValue("", this.value, formatOptions);
1090
1190
  };
1091
1191
  }
1092
1192
 
1093
- if (!options.tooltip.pointFormatter) {
1193
+ if (!options.tooltip.pointFormatter && !options.tooltip.pointFormat) {
1094
1194
  options.tooltip.pointFormatter = function () {
1095
1195
  return '<span style="color:' + this.color + '">\u25CF</span> ' + formatValue(this.series.name + ': <b>', this.y, formatOptions) + '</b><br/>';
1096
1196
  };
1097
1197
  }
1098
- };
1198
+ }
1099
1199
 
1100
1200
  var defaultExport$1 = function defaultExport(library) {
1101
1201
  this.name = "highcharts";
@@ -1131,21 +1231,27 @@
1131
1231
  }
1132
1232
  }
1133
1233
 
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");
1234
+ var options = jsOptions$1(chart, chart.options, chartOptions);
1235
+ if (chart.xtype === "number") {
1236
+ options.xAxis.type = options.xAxis.type || "linear";
1237
+ } else {
1238
+ options.xAxis.type = chart.xtype === "string" ? "category" : "datetime";
1239
+ }
1136
1240
  if (!options.chart.type) {
1137
1241
  options.chart.type = chartType;
1138
1242
  }
1139
- setFormatOptions$1(chart, options, chartType);
1243
+ setFormatOptions(chart, options, chartType);
1140
1244
 
1141
1245
  var series = chart.data;
1142
- for (i = 0; i < series.length; i++) {
1246
+ for (var i = 0; i < series.length; i++) {
1143
1247
  series[i].name = series[i].name || "Value";
1144
- data = series[i].data;
1248
+ var data = series[i].data;
1145
1249
  if (chart.xtype === "datetime") {
1146
- for (j = 0; j < data.length; j++) {
1250
+ for (var j = 0; j < data.length; j++) {
1147
1251
  data[j][0] = data[j][0].getTime();
1148
1252
  }
1253
+ } else if (chart.xtype === "number") {
1254
+ data.sort(sortByNumberSeries);
1149
1255
  }
1150
1256
  series[i].marker = {symbol: "circle"};
1151
1257
  if (chart.options.points === false) {
@@ -1181,7 +1287,7 @@
1181
1287
  }
1182
1288
 
1183
1289
  var options = merge(chartOptions, chart.options.library || {});
1184
- setFormatOptions$1(chart, options, "pie");
1290
+ setFormatOptions(chart, options, "pie");
1185
1291
  var series = [{
1186
1292
  type: "pie",
1187
1293
  name: chart.options.label || "Value",
@@ -1194,15 +1300,17 @@
1194
1300
  defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
1195
1301
  chartType = chartType || "column";
1196
1302
  var series = chart.data;
1197
- var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1303
+ var options = jsOptions$1(chart, chart.options);
1304
+ var rows = [];
1305
+ var categories = [];
1198
1306
  options.chart.type = chartType;
1199
- setFormatOptions$1(chart, options, chartType);
1307
+ setFormatOptions(chart, options, chartType);
1200
1308
 
1201
- for (i = 0; i < series.length; i++) {
1202
- s = series[i];
1309
+ for (var i = 0; i < series.length; i++) {
1310
+ var s = series[i];
1203
1311
 
1204
- for (j = 0; j < s.data.length; j++) {
1205
- d = s.data[j];
1312
+ for (var j = 0; j < s.data.length; j++) {
1313
+ var d = s.data[j];
1206
1314
  if (!rows[d[0]]) {
1207
1315
  rows[d[0]] = new Array(series.length);
1208
1316
  categories.push(d[0]);
@@ -1217,19 +1325,19 @@
1217
1325
 
1218
1326
  options.xAxis.categories = categories;
1219
1327
 
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);
1328
+ var newSeries = [];
1329
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1330
+ var d$1 = [];
1331
+ for (var j$1 = 0; j$1 < categories.length; j$1++) {
1332
+ d$1.push(rows[categories[j$1]][i$1] || 0);
1225
1333
  }
1226
1334
 
1227
- d2 = {
1228
- name: series[i].name || "Value",
1229
- data: d
1335
+ var d2 = {
1336
+ name: series[i$1].name || "Value",
1337
+ data: d$1
1230
1338
  };
1231
- if (series[i].stack) {
1232
- d2.stack = series[i].stack;
1339
+ if (series[i$1].stack) {
1340
+ d2.stack = series[i$1].stack;
1233
1341
  }
1234
1342
 
1235
1343
  newSeries.push(d2);
@@ -1254,6 +1362,7 @@
1254
1362
 
1255
1363
  defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
1364
  this.destroy(chart);
1365
+ if (chart.destroyed) { return; }
1257
1366
 
1258
1367
  options.chart.renderTo = chart.element.id;
1259
1368
  options.series = data;
@@ -1269,7 +1378,7 @@
1269
1378
  var callbacks = [];
1270
1379
 
1271
1380
  // Set chart options
1272
- var defaultOptions$2 = {
1381
+ var defaultOptions = {
1273
1382
  chartArea: {},
1274
1383
  fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
1384
  pointSize: 6,
@@ -1311,7 +1420,7 @@
1311
1420
  }
1312
1421
  };
1313
1422
 
1314
- var hideLegend$2 = function (options, legend, hideLegend) {
1423
+ function hideLegend(options, legend, hideLegend) {
1315
1424
  if (legend !== undefined) {
1316
1425
  var position;
1317
1426
  if (!legend) {
@@ -1325,61 +1434,61 @@
1325
1434
  } else if (hideLegend) {
1326
1435
  options.legend.position = "none";
1327
1436
  }
1328
- };
1437
+ }
1329
1438
 
1330
- var setTitle$2 = function (options, title) {
1439
+ function setTitle(options, title) {
1331
1440
  options.title = title;
1332
1441
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
- };
1442
+ }
1334
1443
 
1335
- var setMin$2 = function (options, min) {
1444
+ function setMin(options, min) {
1336
1445
  options.vAxis.viewWindow.min = min;
1337
- };
1446
+ }
1338
1447
 
1339
- var setMax$2 = function (options, max) {
1448
+ function setMax(options, max) {
1340
1449
  options.vAxis.viewWindow.max = max;
1341
- };
1450
+ }
1342
1451
 
1343
- var setBarMin$1 = function (options, min) {
1452
+ function setBarMin(options, min) {
1344
1453
  options.hAxis.viewWindow.min = min;
1345
- };
1454
+ }
1346
1455
 
1347
- var setBarMax$1 = function (options, max) {
1456
+ function setBarMax(options, max) {
1348
1457
  options.hAxis.viewWindow.max = max;
1349
- };
1458
+ }
1350
1459
 
1351
- var setStacked$2 = function (options, stacked) {
1352
- options.isStacked = stacked ? stacked : false;
1353
- };
1460
+ function setStacked(options, stacked) {
1461
+ options.isStacked = stacked || false;
1462
+ }
1354
1463
 
1355
- var setXtitle$2 = function (options, title) {
1464
+ function setXtitle(options, title) {
1356
1465
  options.hAxis.title = title;
1357
1466
  options.hAxis.titleTextStyle.italic = false;
1358
- };
1467
+ }
1359
1468
 
1360
- var setYtitle$2 = function (options, title) {
1469
+ function setYtitle(options, title) {
1361
1470
  options.vAxis.title = title;
1362
1471
  options.vAxis.titleTextStyle.italic = false;
1363
- };
1472
+ }
1364
1473
 
1365
- var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1474
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1366
1475
 
1367
- var resize = function (callback) {
1476
+ function resize(callback) {
1368
1477
  if (window.attachEvent) {
1369
1478
  window.attachEvent("onresize", callback);
1370
1479
  } else if (window.addEventListener) {
1371
1480
  window.addEventListener("resize", callback, true);
1372
1481
  }
1373
1482
  callback();
1374
- };
1483
+ }
1375
1484
 
1376
- var defaultExport$2 = function defaultExport(library) {
1485
+ var defaultExport = function defaultExport(library) {
1377
1486
  this.name = "google";
1378
1487
  this.library = library;
1379
1488
  };
1380
1489
 
1381
- defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1382
- var this$1 = this;
1490
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart) {
1491
+ var this$1$1 = this;
1383
1492
 
1384
1493
  this.waitForLoaded(chart, function () {
1385
1494
  var chartOptions = {};
@@ -1392,15 +1501,15 @@
1392
1501
  chartOptions.pointSize = 0;
1393
1502
  }
1394
1503
 
1395
- var options = jsOptions$2(chart, chart.options, chartOptions);
1396
- var data = this$1.createDataTable(chart.data, chart.xtype);
1504
+ var options = jsOptions(chart, chart.options, chartOptions);
1505
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1397
1506
 
1398
- this$1.drawChart(chart, "LineChart", data, options);
1507
+ this$1$1.drawChart(chart, "LineChart", data, options);
1399
1508
  });
1400
1509
  };
1401
1510
 
1402
- defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1403
- var this$1 = this;
1511
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
1512
+ var this$1$1 = this;
1404
1513
 
1405
1514
  this.waitForLoaded(chart, function () {
1406
1515
  var chartOptions = {
@@ -1417,35 +1526,35 @@
1417
1526
  chartOptions.pieHole = 0.5;
1418
1527
  }
1419
1528
  if ("legend" in chart.options) {
1420
- hideLegend$2(chartOptions, chart.options.legend);
1529
+ hideLegend(chartOptions, chart.options.legend);
1421
1530
  }
1422
1531
  if (chart.options.title) {
1423
- setTitle$2(chartOptions, chart.options.title);
1532
+ setTitle(chartOptions, chart.options.title);
1424
1533
  }
1425
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1534
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1426
1535
 
1427
- var data = new this$1.library.visualization.DataTable();
1536
+ var data = new this$1$1.library.visualization.DataTable();
1428
1537
  data.addColumn("string", "");
1429
1538
  data.addColumn("number", "Value");
1430
1539
  data.addRows(chart.data);
1431
1540
 
1432
- this$1.drawChart(chart, "PieChart", data, options);
1541
+ this$1$1.drawChart(chart, "PieChart", data, options);
1433
1542
  });
1434
1543
  };
1435
1544
 
1436
- defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
- var this$1 = this;
1545
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) {
1546
+ var this$1$1 = this;
1438
1547
 
1439
1548
  this.waitForLoaded(chart, function () {
1440
- var options = jsOptions$2(chart, chart.options);
1441
- var data = this$1.createDataTable(chart.data, chart.xtype);
1549
+ var options = jsOptions(chart, chart.options);
1550
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1442
1551
 
1443
- this$1.drawChart(chart, "ColumnChart", data, options);
1552
+ this$1$1.drawChart(chart, "ColumnChart", data, options);
1444
1553
  });
1445
1554
  };
1446
1555
 
1447
- defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1448
- var this$1 = this;
1556
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1557
+ var this$1$1 = this;
1449
1558
 
1450
1559
  this.waitForLoaded(chart, function () {
1451
1560
  var chartOptions = {
@@ -1455,15 +1564,15 @@
1455
1564
  }
1456
1565
  }
1457
1566
  };
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);
1567
+ var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
1568
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1460
1569
 
1461
- this$1.drawChart(chart, "BarChart", data, options);
1570
+ this$1$1.drawChart(chart, "BarChart", data, options);
1462
1571
  });
1463
1572
  };
1464
1573
 
1465
- defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
- var this$1 = this;
1574
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1575
+ var this$1$1 = this;
1467
1576
 
1468
1577
  this.waitForLoaded(chart, function () {
1469
1578
  var chartOptions = {
@@ -1472,15 +1581,15 @@
1472
1581
  areaOpacity: 0.5
1473
1582
  };
1474
1583
 
1475
- var options = jsOptions$2(chart, chart.options, chartOptions);
1476
- var data = this$1.createDataTable(chart.data, chart.xtype);
1584
+ var options = jsOptions(chart, chart.options, chartOptions);
1585
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1477
1586
 
1478
- this$1.drawChart(chart, "AreaChart", data, options);
1587
+ this$1$1.drawChart(chart, "AreaChart", data, options);
1479
1588
  });
1480
1589
  };
1481
1590
 
1482
- defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
- var this$1 = this;
1591
+ defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) {
1592
+ var this$1$1 = this;
1484
1593
 
1485
1594
  this.waitForLoaded(chart, "geochart", function () {
1486
1595
  var chartOptions = {
@@ -1489,29 +1598,30 @@
1489
1598
  colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
1599
  }
1491
1600
  };
1492
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1601
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1493
1602
 
1494
- var data = new this$1.library.visualization.DataTable();
1603
+ var data = new this$1$1.library.visualization.DataTable();
1495
1604
  data.addColumn("string", "");
1496
1605
  data.addColumn("number", chart.options.label || "Value");
1497
1606
  data.addRows(chart.data);
1498
1607
 
1499
- this$1.drawChart(chart, "GeoChart", data, options);
1608
+ this$1$1.drawChart(chart, "GeoChart", data, options);
1500
1609
  });
1501
1610
  };
1502
1611
 
1503
- defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
- var this$1 = this;
1612
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) {
1613
+ var this$1$1 = this;
1505
1614
 
1506
1615
  this.waitForLoaded(chart, function () {
1507
1616
  var chartOptions = {};
1508
- var options = jsOptions$2(chart, chart.options, chartOptions);
1617
+ var options = jsOptions(chart, chart.options, chartOptions);
1509
1618
 
1510
- var series = chart.data, rows2 = [], i, j, data, d;
1511
- for (i = 0; i < series.length; i++) {
1619
+ var series = chart.data;
1620
+ var rows2 = [];
1621
+ for (var i = 0; i < series.length; i++) {
1512
1622
  series[i].name = series[i].name || "Value";
1513
- d = series[i].data;
1514
- for (j = 0; j < d.length; j++) {
1623
+ var d = series[i].data;
1624
+ for (var j = 0; j < d.length; j++) {
1515
1625
  var row = new Array(series.length + 1);
1516
1626
  row[0] = d[j][0];
1517
1627
  row[i + 1] = d[j][1];
@@ -1519,19 +1629,19 @@
1519
1629
  }
1520
1630
  }
1521
1631
 
1522
- data = new this$1.library.visualization.DataTable();
1632
+ var data = new this$1$1.library.visualization.DataTable();
1523
1633
  data.addColumn("number", "");
1524
- for (i = 0; i < series.length; i++) {
1525
- data.addColumn("number", series[i].name);
1634
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1635
+ data.addColumn("number", series[i$1].name);
1526
1636
  }
1527
1637
  data.addRows(rows2);
1528
1638
 
1529
- this$1.drawChart(chart, "ScatterChart", data, options);
1639
+ this$1$1.drawChart(chart, "ScatterChart", data, options);
1530
1640
  });
1531
1641
  };
1532
1642
 
1533
- defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1534
- var this$1 = this;
1643
+ defaultExport.prototype.renderTimeline = function renderTimeline (chart) {
1644
+ var this$1$1 = this;
1535
1645
 
1536
1646
  this.waitForLoaded(chart, "timeline", function () {
1537
1647
  var chartOptions = {
@@ -1541,9 +1651,9 @@
1541
1651
  if (chart.options.colors) {
1542
1652
  chartOptions.colors = chart.options.colors;
1543
1653
  }
1544
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1654
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1545
1655
 
1546
- var data = new this$1.library.visualization.DataTable();
1656
+ var data = new this$1$1.library.visualization.DataTable();
1547
1657
  data.addColumn({type: "string", id: "Name"});
1548
1658
  data.addColumn({type: "date", id: "Start"});
1549
1659
  data.addColumn({type: "date", id: "End"});
@@ -1551,18 +1661,20 @@
1551
1661
 
1552
1662
  chart.element.style.lineHeight = "normal";
1553
1663
 
1554
- this$1.drawChart(chart, "Timeline", data, options);
1664
+ this$1$1.drawChart(chart, "Timeline", data, options);
1555
1665
  });
1556
1666
  };
1557
1667
 
1558
- defaultExport$2.prototype.destroy = function destroy (chart) {
1668
+ // TODO remove resize events
1669
+ defaultExport.prototype.destroy = function destroy (chart) {
1559
1670
  if (chart.chart) {
1560
1671
  chart.chart.clearChart();
1561
1672
  }
1562
1673
  };
1563
1674
 
1564
- defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1675
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
1676
  this.destroy(chart);
1677
+ if (chart.destroyed) { return; }
1566
1678
 
1567
1679
  if (chart.options.code) {
1568
1680
  window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");");
@@ -1574,8 +1686,8 @@
1574
1686
  });
1575
1687
  };
1576
1688
 
1577
- defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
- var this$1 = this;
1689
+ defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1690
+ var this$1$1 = this;
1579
1691
 
1580
1692
  if (!callback) {
1581
1693
  callback = pack;
@@ -1592,7 +1704,7 @@
1592
1704
  // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
1593
1705
  var loadOptions = {
1594
1706
  packages: [pack],
1595
- callback: function () { this$1.runCallbacks(); }
1707
+ callback: function () { this$1$1.runCallbacks(); }
1596
1708
  };
1597
1709
  var config = chart.__config();
1598
1710
  if (config.language) {
@@ -1606,11 +1718,10 @@
1606
1718
  }
1607
1719
  };
1608
1720
 
1609
- defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1610
- var cb, call;
1721
+ defaultExport.prototype.runCallbacks = function runCallbacks () {
1611
1722
  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));
1723
+ var cb = callbacks[i];
1724
+ var 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
1725
  if (call) {
1615
1726
  cb.callback();
1616
1727
  callbacks.splice(i, 1);
@@ -1620,45 +1731,49 @@
1620
1731
  };
1621
1732
 
1622
1733
  // 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];
1734
+ defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1735
+ var rows = [];
1736
+ var sortedLabels = [];
1737
+ for (var i = 0; i < series.length; i++) {
1738
+ var s = series[i];
1627
1739
  series[i].name = series[i].name || "Value";
1628
1740
 
1629
- for (j = 0; j < s.data.length; j++) {
1630
- d = s.data[j];
1631
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
1741
+ for (var j = 0; j < s.data.length; j++) {
1742
+ var d = s.data[j];
1743
+ var key = columnType === "datetime" ? d[0].getTime() : d[0];
1632
1744
  if (!rows[key]) {
1633
1745
  rows[key] = new Array(series.length);
1634
1746
  sortedLabels.push(key);
1635
1747
  }
1636
- rows[key][i] = toFloat(d[1]);
1748
+ rows[key][i] = d[1];
1637
1749
  }
1638
1750
  }
1639
1751
 
1640
1752
  var rows2 = [];
1641
- var day = true;
1642
- var value;
1643
- for (j = 0; j < sortedLabels.length; j++) {
1644
- i = sortedLabels[j];
1753
+ var values = [];
1754
+ for (var j$1 = 0; j$1 < sortedLabels.length; j$1++) {
1755
+ var i$1 = sortedLabels[j$1];
1756
+ var value = (void 0);
1645
1757
  if (columnType === "datetime") {
1646
- value = new Date(toFloat(i));
1647
- day = day && isDay(value);
1648
- } else if (columnType === "number") {
1649
- value = toFloat(i);
1758
+ value = new Date(i$1);
1759
+ values.push(value);
1650
1760
  } else {
1651
- value = i;
1761
+ value = i$1;
1652
1762
  }
1653
- rows2.push([value].concat(rows[i]));
1763
+ rows2.push([value].concat(rows[i$1]));
1654
1764
  }
1765
+
1766
+ var day = true;
1655
1767
  if (columnType === "datetime") {
1656
1768
  rows2.sort(sortByTime);
1769
+
1770
+ var timeUnit = calculateTimeUnit(values, true);
1771
+ day = isDay(timeUnit);
1657
1772
  } else if (columnType === "number") {
1658
1773
  rows2.sort(sortByNumberSeries);
1659
1774
 
1660
- for (i = 0; i < rows2.length; i++) {
1661
- rows2[i][0] = toStr(rows2[i][0]);
1775
+ for (var i$2 = 0; i$2 < rows2.length; i$2++) {
1776
+ rows2[i$2][0] = toStr(rows2[i$2][0]);
1662
1777
  }
1663
1778
 
1664
1779
  columnType = "string";
@@ -1668,215 +1783,24 @@
1668
1783
  var data = new this.library.visualization.DataTable();
1669
1784
  columnType = columnType === "datetime" && day ? "date" : columnType;
1670
1785
  data.addColumn(columnType, "");
1671
- for (i = 0; i < series.length; i++) {
1672
- data.addColumn("number", series[i].name);
1786
+ for (var i$3 = 0; i$3 < series.length; i$3++) {
1787
+ data.addColumn("number", series[i$3].name);
1673
1788
  }
1674
1789
  data.addRows(rows2);
1675
1790
 
1676
1791
  return data;
1677
1792
  };
1678
1793
 
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
1794
  var adapters = [];
1738
1795
 
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;
1764
- }
1765
- }
1766
-
1767
- function fetchDataSource(chart, dataSource) {
1768
- if (typeof dataSource === "string") {
1769
- pushRequest(dataSource, function (data) {
1770
- chart.rawData = data;
1771
- errorCatcher(chart);
1772
- }, function (message) {
1773
- chartError(chart.element, message);
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
- }
1786
- } else {
1787
- chart.rawData = dataSource;
1788
- errorCatcher(chart);
1789
- }
1790
- }
1791
-
1792
- function addDownloadButton(chart) {
1793
- var element = chart.element;
1794
- var link = document.createElement("a");
1795
-
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
- });
1840
- }
1841
-
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
- }
1855
- }
1856
-
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
1796
  function getAdapterType(library) {
1873
1797
  if (library) {
1874
1798
  if (library.product === "Highcharts") {
1875
1799
  return defaultExport$1;
1876
1800
  } else if (library.charts) {
1877
- return defaultExport$2;
1878
- } else if (isFunction(library)) {
1879
1801
  return defaultExport;
1802
+ } else if (isFunction(library)) {
1803
+ return defaultExport$2;
1880
1804
  }
1881
1805
  }
1882
1806
  throw new Error("Unknown adapter");
@@ -1884,11 +1808,14 @@
1884
1808
 
1885
1809
  function addAdapter(library) {
1886
1810
  var adapterType = getAdapterType(library);
1887
- var adapter = new adapterType(library);
1888
1811
 
1889
- if (adapters.indexOf(adapter) === -1) {
1890
- adapters.push(adapter);
1812
+ for (var i = 0; i < adapters.length; i++) {
1813
+ if (adapters[i].library === library) {
1814
+ return;
1815
+ }
1891
1816
  }
1817
+
1818
+ adapters.push(new adapterType(library));
1892
1819
  }
1893
1820
 
1894
1821
  function loadAdapters() {
@@ -1905,41 +1832,16 @@
1905
1832
  }
1906
1833
  }
1907
1834
 
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;
1915
- }
1916
- }
1917
- return true;
1918
- }
1919
- }
1920
-
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
- }
1931
-
1932
1835
  // TODO remove chartType if cross-browser way
1933
1836
  // to get the name of the chart class
1934
1837
  function callAdapter(chartType, chart) {
1935
- var i, adapter, fnName, adapterName;
1936
- fnName = "render" + chartType;
1937
- adapterName = chart.options.adapter;
1838
+ var fnName = "render" + chartType;
1839
+ var adapterName = chart.options.adapter;
1938
1840
 
1939
1841
  loadAdapters();
1940
1842
 
1941
- for (i = 0; i < adapters.length; i++) {
1942
- adapter = adapters[i];
1843
+ for (var i = 0; i < adapters.length; i++) {
1844
+ var adapter = adapters[i];
1943
1845
  if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
1944
1846
  chart.adapter = adapter.name;
1945
1847
  chart.__adapterObject = adapter;
@@ -1954,36 +1856,73 @@
1954
1856
  }
1955
1857
  }
1956
1858
 
1957
- // process data
1859
+ var Chartkick = {
1860
+ charts: {},
1861
+ configure: function (options) {
1862
+ for (var key in options) {
1863
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
1864
+ Chartkick.config[key] = options[key];
1865
+ }
1866
+ }
1867
+ },
1868
+ setDefaultOptions: function (opts) {
1869
+ Chartkick.options = opts;
1870
+ },
1871
+ eachChart: function (callback) {
1872
+ for (var chartId in Chartkick.charts) {
1873
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1874
+ callback(Chartkick.charts[chartId]);
1875
+ }
1876
+ }
1877
+ },
1878
+ destroyAll: function () {
1879
+ for (var chartId in Chartkick.charts) {
1880
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1881
+ Chartkick.charts[chartId].destroy();
1882
+ delete Chartkick.charts[chartId];
1883
+ }
1884
+ }
1885
+ },
1886
+ config: {},
1887
+ options: {},
1888
+ adapters: adapters,
1889
+ addAdapter: addAdapter,
1890
+ use: function (adapter) {
1891
+ addAdapter(adapter);
1892
+ return Chartkick;
1893
+ }
1894
+ };
1958
1895
 
1959
- var toFormattedKey = function (key, keyType) {
1896
+ function formatSeriesBubble(data) {
1897
+ var r = [];
1898
+ for (var i = 0; i < data.length; i++) {
1899
+ r.push([toFloat(data[i][0]), toFloat(data[i][1]), toFloat(data[i][2])]);
1900
+ }
1901
+ return r;
1902
+ }
1903
+
1904
+ // casts data to proper type
1905
+ // sorting is left to adapters
1906
+ function formatSeriesData(data, keyType) {
1907
+ if (keyType === "bubble") {
1908
+ return formatSeriesBubble(data);
1909
+ }
1910
+
1911
+ var keyFunc;
1960
1912
  if (keyType === "number") {
1961
- key = toFloat(key);
1913
+ keyFunc = toFloat;
1962
1914
  } else if (keyType === "datetime") {
1963
- key = toDate(key);
1915
+ keyFunc = toDate;
1964
1916
  } else {
1965
- key = toStr(key);
1917
+ keyFunc = toStr;
1966
1918
  }
1967
- return key;
1968
- };
1969
1919
 
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);
1977
- r.push([key, toFloat(data[j][1])]);
1978
- }
1979
- }
1980
- if (keyType === "datetime") {
1981
- r.sort(sortByTime);
1982
- } else if (keyType === "number") {
1983
- r.sort(sortByNumberSeries);
1920
+ var r = [];
1921
+ for (var i = 0; i < data.length; i++) {
1922
+ r.push([keyFunc(data[i][0]), toFloat(data[i][1])]);
1984
1923
  }
1985
1924
  return r;
1986
- };
1925
+ }
1987
1926
 
1988
1927
  function detectXType(series, noDatetime, options) {
1989
1928
  if (dataEmpty(series)) {
@@ -2002,10 +1941,9 @@
2002
1941
  }
2003
1942
 
2004
1943
  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++) {
1944
+ for (var i = 0; i < series.length; i++) {
1945
+ var data = toArr(series[i].data);
1946
+ for (var j = 0; j < data.length; j++) {
2009
1947
  if (!func(data[j][0])) {
2010
1948
  return false;
2011
1949
  }
@@ -2017,11 +1955,11 @@
2017
1955
  // creates a shallow copy of each element of the array
2018
1956
  // elements are expected to be objects
2019
1957
  function copySeries(series) {
2020
- var newSeries = [], i, j;
2021
- for (i = 0; i < series.length; i++) {
1958
+ var newSeries = [];
1959
+ for (var i = 0; i < series.length; i++) {
2022
1960
  var copy = {};
2023
- for (j in series[i]) {
2024
- if (series[i].hasOwnProperty(j)) {
1961
+ for (var j in series[i]) {
1962
+ if (Object.prototype.hasOwnProperty.call(series[i], j)) {
2025
1963
  copy[j] = series[i][j];
2026
1964
  }
2027
1965
  }
@@ -2031,62 +1969,237 @@
2031
1969
  }
2032
1970
 
2033
1971
  function processSeries(chart, keyType, noDatetime) {
2034
- var i;
2035
-
2036
1972
  var opts = chart.options;
2037
1973
  var series = chart.rawData;
2038
1974
 
2039
1975
  // see if one series or multiple
2040
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
1976
+ chart.singleSeriesFormat = !isArray(series) || !isPlainObject(series[0]);
1977
+ if (chart.singleSeriesFormat) {
2041
1978
  series = [{name: opts.label, data: series}];
2042
- chart.hideLegend = true;
2043
- } else {
2044
- chart.hideLegend = false;
2045
1979
  }
2046
1980
 
2047
1981
  // convert to array
2048
1982
  // must come before dataEmpty check
2049
1983
  series = copySeries(series);
2050
- for (i = 0; i < series.length; i++) {
1984
+ for (var i = 0; i < series.length; i++) {
2051
1985
  series[i].data = toArr(series[i].data);
2052
1986
  }
2053
1987
 
2054
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1988
+ chart.xtype = keyType || (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2055
1989
 
2056
1990
  // right format
2057
- for (i = 0; i < series.length; i++) {
2058
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
1991
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1992
+ series[i$1].data = formatSeriesData(series[i$1].data, chart.xtype);
2059
1993
  }
2060
1994
 
2061
1995
  return series;
2062
1996
  }
2063
1997
 
2064
1998
  function processSimple(chart) {
2065
- var perfectData = toArr(chart.rawData), i;
2066
- for (i = 0; i < perfectData.length; i++) {
1999
+ var perfectData = toArr(chart.rawData);
2000
+ for (var i = 0; i < perfectData.length; i++) {
2067
2001
  perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
2068
2002
  }
2069
2003
  return perfectData;
2070
2004
  }
2071
2005
 
2072
- // define classes
2006
+ function dataEmpty(data, chartType) {
2007
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
2008
+ return data.length === 0;
2009
+ } else {
2010
+ for (var i = 0; i < data.length; i++) {
2011
+ if (data[i].data.length > 0) {
2012
+ return false;
2013
+ }
2014
+ }
2015
+ return true;
2016
+ }
2017
+ }
2073
2018
 
2074
- var Chart = function Chart(element, dataSource, options) {
2075
- var elementId;
2019
+ function addDownloadButton(chart) {
2020
+ var download = chart.options.download;
2021
+ if (download === true) {
2022
+ download = {};
2023
+ } else if (typeof download === "string") {
2024
+ download = {filename: download};
2025
+ }
2026
+
2027
+ var link = document.createElement("a");
2028
+ link.download = download.filename || "chart.png";
2029
+ link.style.position = "absolute";
2030
+ link.style.top = "20px";
2031
+ link.style.right = "20px";
2032
+ link.style.zIndex = 1000;
2033
+ link.style.lineHeight = "20px";
2034
+ link.target = "_blank"; // for safari
2035
+
2036
+ var image = document.createElement("img");
2037
+ // icon from Font Awesome, modified to set fill color
2038
+ var svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path fill=\"#CCCCCC\" d=\"M344 240h-56L287.1 152c0-13.25-10.75-24-24-24h-16C234.7 128 223.1 138.8 223.1 152L224 240h-56c-9.531 0-18.16 5.656-22 14.38C142.2 263.1 143.9 273.3 150.4 280.3l88.75 96C243.7 381.2 250.1 384 256.8 384c7.781-.3125 13.25-2.875 17.75-7.844l87.25-96c6.406-7.031 8.031-17.19 4.188-25.88S353.5 240 344 240zM256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464z\"/></svg>";
2039
+ image.src = "data:image/svg+xml;utf8," + (encodeURIComponent(svg));
2040
+ image.alt = "Download";
2041
+ image.style.width = "20px";
2042
+ image.style.height = "20px";
2043
+ image.style.border = "none";
2044
+ link.appendChild(image);
2045
+
2046
+ var element = chart.element;
2047
+ element.style.position = "relative";
2048
+
2049
+ chart.__downloadAttached = true;
2050
+
2051
+ // mouseenter
2052
+ chart.__enterEvent = element.addEventListener("mouseover", function (e) {
2053
+ var related = e.relatedTarget;
2054
+ // check download option again to ensure it wasn't changed
2055
+ if ((!related || (related !== this && !this.contains(related))) && chart.options.download) {
2056
+ link.href = chart.toImage(download);
2057
+ element.appendChild(link);
2058
+ }
2059
+ });
2060
+
2061
+ // mouseleave
2062
+ chart.__leaveEvent = element.addEventListener("mouseout", function (e) {
2063
+ var related = e.relatedTarget;
2064
+ if (!related || (related !== this && !this.contains(related))) {
2065
+ if (link.parentNode) {
2066
+ link.parentNode.removeChild(link);
2067
+ }
2068
+ }
2069
+ });
2070
+ }
2071
+
2072
+ var pendingRequests = [];
2073
+ var runningRequests = 0;
2074
+ var maxRequests = 4;
2075
+
2076
+ function pushRequest(url, success, error) {
2077
+ pendingRequests.push([url, success, error]);
2078
+ runNext();
2079
+ }
2080
+
2081
+ function runNext() {
2082
+ if (runningRequests < maxRequests) {
2083
+ var request = pendingRequests.shift();
2084
+ if (request) {
2085
+ runningRequests++;
2086
+ getJSON(request[0], request[1], request[2]);
2087
+ runNext();
2088
+ }
2089
+ }
2090
+ }
2091
+
2092
+ function requestComplete() {
2093
+ runningRequests--;
2094
+ runNext();
2095
+ }
2096
+
2097
+ function getJSON(url, success, error) {
2098
+ var xhr = new XMLHttpRequest();
2099
+ xhr.open("GET", url, true);
2100
+ xhr.setRequestHeader("Content-Type", "application/json");
2101
+ xhr.onload = function () {
2102
+ requestComplete();
2103
+ if (xhr.status === 200) {
2104
+ success(JSON.parse(xhr.responseText));
2105
+ } else {
2106
+ error(xhr.statusText);
2107
+ }
2108
+ };
2109
+ xhr.send();
2110
+ }
2111
+
2112
+ // helpers
2113
+
2114
+ function setText(element, text) {
2115
+ element.textContent = text;
2116
+ }
2117
+
2118
+ // TODO remove prefix for all messages
2119
+ function chartError(element, message, noPrefix) {
2120
+ if (!noPrefix) {
2121
+ message = "Error Loading Chart: " + message;
2122
+ }
2123
+ setText(element, message);
2124
+ element.style.color = "#ff0000";
2125
+ }
2126
+
2127
+ function errorCatcher(chart) {
2128
+ try {
2129
+ chart.__render();
2130
+ } catch (err) {
2131
+ chartError(chart.element, err.message);
2132
+ throw err;
2133
+ }
2134
+ }
2135
+
2136
+ function fetchDataSource(chart, dataSource, showLoading) {
2137
+ // only show loading message for urls and callbacks
2138
+ if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
2139
+ setText(chart.element, chart.options.loading);
2140
+ }
2141
+
2142
+ if (typeof dataSource === "string") {
2143
+ pushRequest(dataSource, function (data) {
2144
+ chart.rawData = data;
2145
+ errorCatcher(chart);
2146
+ }, function (message) {
2147
+ chartError(chart.element, message);
2148
+ });
2149
+ } else if (typeof dataSource === "function") {
2150
+ try {
2151
+ dataSource(function (data) {
2152
+ chart.rawData = data;
2153
+ errorCatcher(chart);
2154
+ }, function (message) {
2155
+ chartError(chart.element, message, true);
2156
+ });
2157
+ } catch (err) {
2158
+ chartError(chart.element, err, true);
2159
+ }
2160
+ } else {
2161
+ chart.rawData = dataSource;
2162
+ errorCatcher(chart);
2163
+ }
2164
+ }
2165
+
2166
+ function renderChart(chartType, chart) {
2167
+ if (dataEmpty(chart.data, chartType)) {
2168
+ var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2169
+ setText(chart.element, message);
2170
+ } else {
2171
+ callAdapter(chartType, chart);
2172
+ // TODO add downloadSupported method to adapter
2173
+ if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
2174
+ addDownloadButton(chart);
2175
+ }
2176
+ }
2177
+ }
2178
+
2179
+ function getElement(element) {
2076
2180
  if (typeof element === "string") {
2077
- elementId = element;
2181
+ var elementId = element;
2078
2182
  element = document.getElementById(element);
2079
2183
  if (!element) {
2080
2184
  throw new Error("No element with id " + elementId);
2081
2185
  }
2082
2186
  }
2083
- this.element = element;
2187
+ return element;
2188
+ }
2189
+
2190
+ // define classes
2191
+
2192
+ var Chart = function Chart(element, dataSource, options) {
2193
+ this.element = getElement(element);
2084
2194
  this.options = merge(Chartkick.options, options || {});
2085
2195
  this.dataSource = dataSource;
2086
2196
 
2087
- Chartkick.charts[element.id] = this;
2197
+ // TODO handle charts without an id for eachChart and destroyAll
2198
+ if (this.element.id) {
2199
+ Chartkick.charts[this.element.id] = this;
2200
+ }
2088
2201
 
2089
- fetchDataSource(this, dataSource);
2202
+ fetchDataSource(this, dataSource, true);
2090
2203
 
2091
2204
  if (this.options.refresh) {
2092
2205
  this.startRefresh();
@@ -2122,7 +2235,7 @@
2122
2235
  if (options) {
2123
2236
  this.__updateOptions(options);
2124
2237
  }
2125
- fetchDataSource(this, dataSource);
2238
+ fetchDataSource(this, dataSource, true);
2126
2239
  };
2127
2240
 
2128
2241
  Chart.prototype.setOptions = function setOptions (options) {
@@ -2146,7 +2259,7 @@
2146
2259
  };
2147
2260
 
2148
2261
  Chart.prototype.startRefresh = function startRefresh () {
2149
- var this$1 = this;
2262
+ var this$1$1 = this;
2150
2263
 
2151
2264
  var refresh = this.options.refresh;
2152
2265
 
@@ -2156,8 +2269,8 @@
2156
2269
 
2157
2270
  if (!this.intervalId) {
2158
2271
  if (refresh) {
2159
- this.intervalId = setInterval( function () {
2160
- this$1.refreshData();
2272
+ this.intervalId = setInterval(function () {
2273
+ this$1$1.refreshData();
2161
2274
  }, refresh * 1000);
2162
2275
  } else {
2163
2276
  throw new Error("No refresh interval");
@@ -2173,11 +2286,12 @@
2173
2286
  };
2174
2287
 
2175
2288
  Chart.prototype.toImage = function toImage (download) {
2289
+ // TODO move logic to adapter
2176
2290
  if (this.adapter === "chartjs") {
2177
2291
  if (download && download.background && download.background !== "transparent") {
2178
2292
  // 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;
2293
+ var canvas = this.chart.canvas;
2294
+ var ctx = this.chart.ctx;
2181
2295
  var tmpCanvas = document.createElement("canvas");
2182
2296
  var tmpCtx = tmpCanvas.getContext("2d");
2183
2297
  tmpCanvas.width = ctx.canvas.width;
@@ -2190,23 +2304,24 @@
2190
2304
  return this.chart.toBase64Image();
2191
2305
  }
2192
2306
  } else {
2193
- // TODO throw error in next major version
2194
- // throw new Error("Feature only available for Chart.js");
2195
- return null;
2307
+ throw new Error("Feature only available for Chart.js");
2196
2308
  }
2197
2309
  };
2198
2310
 
2199
2311
  Chart.prototype.destroy = function destroy () {
2312
+ this.destroyed = true;
2313
+ this.stopRefresh();
2314
+
2200
2315
  if (this.__adapterObject) {
2201
2316
  this.__adapterObject.destroy(this);
2202
2317
  }
2203
2318
 
2204
2319
  if (this.__enterEvent) {
2205
- removeEvent(this.element, "mouseover", this.__enterEvent);
2320
+ this.element.removeEventListener("mouseover", this.__enterEvent);
2206
2321
  }
2207
2322
 
2208
2323
  if (this.__leaveEvent) {
2209
- removeEvent(this.element, "mouseout", this.__leaveEvent);
2324
+ this.element.removeEventListener("mouseout", this.__leaveEvent);
2210
2325
  }
2211
2326
  };
2212
2327
 
@@ -2225,7 +2340,7 @@
2225
2340
  };
2226
2341
 
2227
2342
  Chart.prototype.__config = function __config () {
2228
- return config;
2343
+ return Chartkick.config;
2229
2344
  };
2230
2345
 
2231
2346
  var LineChart = /*@__PURE__*/(function (Chart) {
@@ -2398,8 +2513,8 @@
2398
2513
  Timeline.prototype.constructor = Timeline;
2399
2514
 
2400
2515
  Timeline.prototype.__processData = function __processData () {
2401
- var i, data = this.rawData;
2402
- for (i = 0; i < data.length; i++) {
2516
+ var data = this.rawData;
2517
+ for (var i = 0; i < data.length; i++) {
2403
2518
  data[i][1] = toDate(data[i][1]);
2404
2519
  data[i][2] = toDate(data[i][2]);
2405
2520
  }
@@ -2413,47 +2528,38 @@
2413
2528
  return Timeline;
2414
2529
  }(Chart));
2415
2530
 
2416
- var Chartkick = {
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;
2436
- },
2437
- eachChart: function (callback) {
2438
- for (var chartId in Chartkick.charts) {
2439
- if (Chartkick.charts.hasOwnProperty(chartId)) {
2440
- callback(Chartkick.charts[chartId]);
2441
- }
2442
- }
2443
- },
2444
- config: config,
2445
- options: {},
2446
- adapters: adapters,
2447
- addAdapter: addAdapter,
2448
- use: function(adapter) {
2449
- addAdapter(adapter);
2450
- return Chartkick;
2451
- }
2452
- };
2531
+ Chartkick.LineChart = LineChart;
2532
+ Chartkick.PieChart = PieChart;
2533
+ Chartkick.ColumnChart = ColumnChart;
2534
+ Chartkick.BarChart = BarChart;
2535
+ Chartkick.AreaChart = AreaChart;
2536
+ Chartkick.GeoChart = GeoChart;
2537
+ Chartkick.ScatterChart = ScatterChart;
2538
+ Chartkick.BubbleChart = BubbleChart;
2539
+ Chartkick.Timeline = Timeline;
2453
2540
 
2454
2541
  // not ideal, but allows for simpler integration
2455
2542
  if (typeof window !== "undefined" && !window.Chartkick) {
2456
2543
  window.Chartkick = Chartkick;
2544
+
2545
+ // clean up previous charts before Turbolinks loads new page
2546
+ document.addEventListener("turbolinks:before-render", function () {
2547
+ if (Chartkick.config.autoDestroy !== false) {
2548
+ Chartkick.destroyAll();
2549
+ }
2550
+ });
2551
+
2552
+ // clean up previous charts before Turbo loads new page
2553
+ document.addEventListener("turbo:before-render", function () {
2554
+ if (Chartkick.config.autoDestroy !== false) {
2555
+ Chartkick.destroyAll();
2556
+ }
2557
+ });
2558
+
2559
+ // use setTimeout so charting library can come later in same JS file
2560
+ setTimeout(function () {
2561
+ window.dispatchEvent(new Event("chartkick:load"));
2562
+ }, 0);
2457
2563
  }
2458
2564
 
2459
2565
  // backwards compatibility for esm require
@@ -2461,4 +2567,4 @@
2461
2567
 
2462
2568
  return Chartkick;
2463
2569
 
2464
- })));
2570
+ }));