chartkick 4.2.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,7 @@
1
1
  /*!
2
- * Chartkick.js
2
+ * Chartkick.js v5.0.0
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v4.2.0
6
5
  * MIT License
7
6
  */
8
7
 
@@ -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,13 +51,12 @@
53
51
  return target;
54
52
  }
55
53
 
56
- var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
54
+ var DATE_PATTERN = /^(\d\d\d\d)(?:-)?(\d\d)(?:-)?(\d\d)$/i;
57
55
 
58
56
  function negativeValues(series) {
59
- var i, j, data;
60
- for (i = 0; i < series.length; i++) {
61
- data = series[i].data;
62
- 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++) {
63
60
  if (data[j][1] < 0) {
64
61
  return true;
65
62
  }
@@ -68,49 +65,49 @@
68
65
  return false;
69
66
  }
70
67
 
71
- function toStr(n) {
72
- return "" + n;
68
+ function toStr(obj) {
69
+ return "" + obj;
73
70
  }
74
71
 
75
- function toFloat(n) {
76
- return parseFloat(n);
72
+ function toFloat(obj) {
73
+ return parseFloat(obj);
77
74
  }
78
75
 
79
- function toDate(n) {
80
- var matches, year, month, day;
81
- if (typeof n !== "object") {
82
- if (typeof n === "number") {
83
- n = new Date(n * 1000); // ms
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);
88
+ return new Date(year, month, day);
84
89
  } else {
85
- n = toStr(n);
86
- if ((matches = n.match(DATE_PATTERN))) {
87
- year = parseInt(matches[1], 10);
88
- month = parseInt(matches[3], 10) - 1;
89
- day = parseInt(matches[5], 10);
90
- return new Date(year, month, day);
91
- } else {
92
- // try our best to get the str into iso8601
93
- // TODO be smarter about this
94
- var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
95
- // Date.parse returns milliseconds if valid and NaN if invalid
96
- n = new Date(Date.parse(str) || n);
97
- }
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);
98
95
  }
99
96
  }
100
- return n;
101
97
  }
102
98
 
103
- function toArr(n) {
104
- if (!isArray(n)) {
105
- var arr = [], i;
106
- for (i in n) {
107
- if (n.hasOwnProperty(i)) {
108
- 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]]);
109
107
  }
110
108
  }
111
- n = arr;
109
+ return arr;
112
110
  }
113
- return n;
114
111
  }
115
112
 
116
113
  function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
@@ -170,32 +167,67 @@
170
167
  return a[0] - b[0];
171
168
  }
172
169
 
170
+ // needed since sort() without arguments does string comparison
173
171
  function sortByNumber(a, b) {
174
172
  return a - b;
175
173
  }
176
174
 
177
- function isMinute(d) {
178
- 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;
179
182
  }
180
183
 
181
- function isHour(d) {
182
- return isMinute(d) && d.getMinutes() === 0;
184
+ function isDay(timeUnit) {
185
+ return timeUnit === "day" || timeUnit === "week" || timeUnit === "month" || timeUnit === "year";
183
186
  }
184
187
 
185
- function isDay(d) {
186
- return isHour(d) && d.getHours() === 0;
187
- }
188
+ function calculateTimeUnit(values, maxDay) {
189
+ if ( maxDay === void 0 ) maxDay = false;
188
190
 
189
- function isWeek(d, dayOfWeek) {
190
- return isDay(d) && d.getDay() === dayOfWeek;
191
- }
191
+ if (values.length === 0) {
192
+ return null;
193
+ }
192
194
 
193
- function isMonth(d) {
194
- return isDay(d) && d.getDate() === 1;
195
- }
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
+ }
196
204
 
197
- function isYear(d) {
198
- return isMonth(d) && d.getMonth() === 0;
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 dayOfWeek = values[0].getDay();
215
+ var week = every(values, function (d) { return d.getDay() === dayOfWeek; });
216
+ if (!week) {
217
+ return "day";
218
+ }
219
+
220
+ var month = every(values, function (d) { return d.getDate() === 1; });
221
+ if (!month) {
222
+ return "week";
223
+ }
224
+
225
+ var year = every(values, function (d) { return d.getMonth() === 0; });
226
+ if (!year) {
227
+ return "month";
228
+ }
229
+
230
+ return "year";
199
231
  }
200
232
 
201
233
  function isDate(obj) {
@@ -223,9 +255,14 @@
223
255
  var round = options.round;
224
256
 
225
257
  if (options.byteScale) {
226
- var suffixIdx;
258
+ var positive = value >= 0;
259
+ if (!positive) {
260
+ value *= -1;
261
+ }
262
+
227
263
  var baseValue = axis ? options.byteScale : value;
228
264
 
265
+ var suffixIdx;
229
266
  if (baseValue >= 1152921504606846976) {
230
267
  value /= 1152921504606846976;
231
268
  suffixIdx = 6;
@@ -259,6 +296,11 @@
259
296
  precision = value >= 1000 ? 4 : 3;
260
297
  }
261
298
  suffix = " " + byteSuffixes[suffixIdx];
299
+
300
+ // flip value back
301
+ if (!positive) {
302
+ value *= -1;
303
+ }
262
304
  }
263
305
 
264
306
  if (precision !== undefined && round !== undefined) {
@@ -310,19 +352,6 @@
310
352
  return null;
311
353
  }
312
354
 
313
- function allZeros(data) {
314
- var i, j, d;
315
- for (i = 0; i < data.length; i++) {
316
- d = data[i].data;
317
- for (j = 0; j < d.length; j++) {
318
- if (d[j][1] != 0) {
319
- return false;
320
- }
321
- }
322
- }
323
- return true;
324
- }
325
-
326
355
  var baseOptions = {
327
356
  maintainAspectRatio: false,
328
357
  animation: false,
@@ -379,7 +408,7 @@
379
408
  "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
380
409
  ];
381
410
 
382
- var hideLegend$2 = function (options, legend, hideLegend) {
411
+ function hideLegend$2(options, legend, hideLegend) {
383
412
  if (legend !== undefined) {
384
413
  options.plugins.legend.display = !!legend;
385
414
  if (legend && legend !== true) {
@@ -388,61 +417,59 @@
388
417
  } else if (hideLegend) {
389
418
  options.plugins.legend.display = false;
390
419
  }
391
- };
420
+ }
392
421
 
393
- var setTitle$2 = function (options, title) {
422
+ function setTitle$2(options, title) {
394
423
  options.plugins.title.display = true;
395
424
  options.plugins.title.text = title;
396
- };
425
+ }
397
426
 
398
- var setMin$2 = function (options, min) {
427
+ function setMin$2(options, min) {
399
428
  if (min !== null) {
400
429
  options.scales.y.min = toFloat(min);
401
430
  }
402
- };
431
+ }
403
432
 
404
- var setMax$2 = function (options, max) {
433
+ function setMax$2(options, max) {
405
434
  options.scales.y.max = toFloat(max);
406
- };
435
+ }
407
436
 
408
- var setBarMin$1 = function (options, min) {
437
+ function setBarMin$1(options, min) {
409
438
  if (min !== null) {
410
439
  options.scales.x.min = toFloat(min);
411
440
  }
412
- };
441
+ }
413
442
 
414
- var setBarMax$1 = function (options, max) {
443
+ function setBarMax$1(options, max) {
415
444
  options.scales.x.max = toFloat(max);
416
- };
445
+ }
417
446
 
418
- var setStacked$2 = function (options, stacked) {
447
+ function setStacked$2(options, stacked) {
419
448
  options.scales.x.stacked = !!stacked;
420
449
  options.scales.y.stacked = !!stacked;
421
- };
450
+ }
422
451
 
423
- var setXtitle$2 = function (options, title) {
452
+ function setXtitle$2(options, title) {
424
453
  options.scales.x.title.display = true;
425
454
  options.scales.x.title.text = title;
426
- };
455
+ }
427
456
 
428
- var setYtitle$2 = function (options, title) {
457
+ function setYtitle$2(options, title) {
429
458
  options.scales.y.title.display = true;
430
459
  options.scales.y.title.text = title;
431
- };
460
+ }
432
461
 
433
462
  // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
434
- var addOpacity = function (hex, opacity) {
463
+ function addOpacity(hex, opacity) {
435
464
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
436
465
  return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
437
- };
466
+ }
438
467
 
439
- // check if not null or undefined
440
- // https://stackoverflow.com/a/27757708/1177228
441
- var notnull = function (x) {
442
- return x != null;
443
- };
468
+ function notnull(x) {
469
+ return x !== null && x !== undefined;
470
+ }
444
471
 
445
- var setLabelSize = function (chart, data, options) {
472
+ function setLabelSize(chart, data, options) {
446
473
  var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
447
474
  if (maxLabelSize > 25) {
448
475
  maxLabelSize = 25;
@@ -459,9 +486,19 @@
459
486
  }
460
487
  };
461
488
  }
462
- };
489
+ }
490
+
491
+ function calculateScale(series) {
492
+ var scale = 1;
493
+ var max = maxAbsY(series);
494
+ while (max >= 1024) {
495
+ scale *= 1024;
496
+ max /= 1024;
497
+ }
498
+ return scale;
499
+ }
463
500
 
464
- var setFormatOptions$1 = function (chart, options, chartType) {
501
+ function setFormatOptions$1(chart, options, chartType) {
465
502
  var formatOptions = {
466
503
  prefix: chart.options.prefix,
467
504
  suffix: chart.options.suffix,
@@ -478,26 +515,8 @@
478
515
  series = [{data: series}];
479
516
  }
480
517
 
481
- // calculate max
482
- var max = 0;
483
- for (var i = 0; i < series.length; i++) {
484
- var s = series[i];
485
- for (var j = 0; j < s.data.length; j++) {
486
- if (s.data[j][1] > max) {
487
- max = s.data[j][1];
488
- }
489
- }
490
- }
491
-
492
- // calculate scale
493
- var scale = 1;
494
- while (max >= 1024) {
495
- scale *= 1024;
496
- max /= 1024;
497
- }
498
-
499
518
  // set step size
500
- formatOptions.byteScale = scale;
519
+ formatOptions.byteScale = calculateScale(series);
501
520
  }
502
521
 
503
522
  if (chartType !== "pie") {
@@ -529,7 +548,8 @@
529
548
  if (label) {
530
549
  label += ': ';
531
550
  }
532
- return label + '(' + context.label + ', ' + context.formattedValue + ')';
551
+
552
+ return label + context.formattedValue;
533
553
  };
534
554
  } else if (chartType === "bubble") {
535
555
  options.plugins.tooltip.callbacks.label = function (context) {
@@ -543,19 +563,7 @@
543
563
  } else if (chartType === "pie") {
544
564
  // need to use separate label for pie charts
545
565
  options.plugins.tooltip.callbacks.label = function (context) {
546
- var dataLabel = context.label;
547
- var value = ': ';
548
-
549
- if (isArray(dataLabel)) {
550
- // show value on first line of multiline label
551
- // need to clone because we are changing the value
552
- dataLabel = dataLabel.slice();
553
- dataLabel[0] += value;
554
- } else {
555
- dataLabel += value;
556
- }
557
-
558
- return formatValue(dataLabel, context.parsed, formatOptions);
566
+ return formatValue('', context.parsed, formatOptions);
559
567
  };
560
568
  } else {
561
569
  var valueLabel = chartType === "bar" ? "x" : "y";
@@ -573,124 +581,171 @@
573
581
  };
574
582
  }
575
583
  }
576
- };
577
-
578
- var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
584
+ }
579
585
 
580
- var createDataTable = function (chart, options, chartType) {
581
- var datasets = [];
582
- var labels = [];
586
+ function maxAbsY(series) {
587
+ var max = 0;
588
+ for (var i = 0; i < series.length; i++) {
589
+ var data = series[i].data;
590
+ for (var j = 0; j < data.length; j++) {
591
+ var v = Math.abs(data[j][1]);
592
+ if (v > max) {
593
+ max = v;
594
+ }
595
+ }
596
+ }
597
+ return max;
598
+ }
583
599
 
584
- var colors = chart.options.colors || defaultColors;
600
+ function maxR(series) {
601
+ // start at zero since radius must be positive
602
+ var max = 0;
603
+ for (var i = 0; i < series.length; i++) {
604
+ var data = series[i].data;
605
+ for (var j = 0; j < data.length; j++) {
606
+ var v = data[j][2];
607
+ if (v > max) {
608
+ max = v;
609
+ }
610
+ }
611
+ }
612
+ return max;
613
+ }
585
614
 
586
- var day = true;
587
- var week = true;
588
- var dayOfWeek;
589
- var month = true;
590
- var year = true;
591
- var hour = true;
592
- var minute = true;
615
+ var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
593
616
 
617
+ function prepareDefaultData(chart) {
594
618
  var series = chart.data;
619
+ var rows = {};
620
+ var keys = [];
621
+ var labels = [];
622
+ var values = [];
595
623
 
596
- var max = 0;
597
- if (chartType === "bubble") {
598
- for (var i$1 = 0; i$1 < series.length; i$1++) {
599
- var s$1 = series[i$1];
600
- for (var j$1 = 0; j$1 < s$1.data.length; j$1++) {
601
- if (s$1.data[j$1][2] > max) {
602
- max = s$1.data[j$1][2];
603
- }
624
+ for (var i = 0; i < series.length; i++) {
625
+ var data = series[i].data;
626
+
627
+ for (var j = 0; j < data.length; j++) {
628
+ var d = data[j];
629
+ var key = chart.xtype === "datetime" ? d[0].getTime() : d[0];
630
+ if (!rows[key]) {
631
+ rows[key] = new Array(series.length);
632
+ keys.push(key);
604
633
  }
634
+ rows[key][i] = d[1];
605
635
  }
606
636
  }
607
637
 
608
- var i, j, s, d, key, rows = [], rows2 = [];
638
+ if (chart.xtype === "datetime" || chart.xtype === "number") {
639
+ keys.sort(sortByNumber);
640
+ }
609
641
 
610
- if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
611
- var sortedLabels = [];
642
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
643
+ values.push([]);
644
+ }
612
645
 
613
- for (i = 0; i < series.length; i++) {
614
- s = series[i];
646
+ for (var i$2 = 0; i$2 < keys.length; i$2++) {
647
+ var key$1 = keys[i$2];
615
648
 
616
- for (j = 0; j < s.data.length; j++) {
617
- d = s.data[j];
618
- key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
619
- if (!rows[key]) {
620
- rows[key] = new Array(series.length);
621
- }
622
- rows[key][i] = toFloat(d[1]);
623
- if (sortedLabels.indexOf(key) === -1) {
624
- sortedLabels.push(key);
625
- }
626
- }
627
- }
649
+ var label = chart.xtype === "datetime" ? new Date(key$1) : key$1;
650
+ labels.push(label);
628
651
 
629
- if (chart.xtype === "datetime" || chart.xtype === "number") {
630
- sortedLabels.sort(sortByNumber);
652
+ var row = rows[key$1];
653
+ for (var j$1 = 0; j$1 < series.length; j$1++) {
654
+ var v = row[j$1];
655
+ // Chart.js doesn't like undefined
656
+ values[j$1].push(v === undefined ? null : v);
631
657
  }
658
+ }
632
659
 
633
- for (j = 0; j < series.length; j++) {
634
- rows2.push([]);
660
+ return {
661
+ labels: labels,
662
+ values: values
663
+ };
664
+ }
665
+
666
+ function prepareBubbleData(chart) {
667
+ var series = chart.data;
668
+ var values = [];
669
+ var max = maxR(series);
670
+
671
+ for (var i = 0; i < series.length; i++) {
672
+ var data = series[i].data;
673
+ var points = [];
674
+ for (var j = 0; j < data.length; j++) {
675
+ var v = data[j];
676
+ points.push({
677
+ x: v[0],
678
+ y: v[1],
679
+ r: v[2] * 20 / max,
680
+ // custom attribute, for tooltip
681
+ v: v[2]
682
+ });
635
683
  }
684
+ values.push(points);
685
+ }
636
686
 
637
- var value;
638
- var k;
639
- for (k = 0; k < sortedLabels.length; k++) {
640
- i = sortedLabels[k];
641
- if (chart.xtype === "datetime") {
642
- value = new Date(toFloat(i));
643
- // TODO make this efficient
644
- day = day && isDay(value);
645
- if (!dayOfWeek) {
646
- dayOfWeek = value.getDay();
647
- }
648
- week = week && isWeek(value, dayOfWeek);
649
- month = month && isMonth(value);
650
- year = year && isYear(value);
651
- hour = hour && isHour(value);
652
- minute = minute && isMinute(value);
653
- } else {
654
- value = i;
655
- }
656
- labels.push(value);
657
- for (j = 0; j < series.length; j++) {
658
- // Chart.js doesn't like undefined
659
- rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
660
- }
687
+ return {
688
+ labels: [],
689
+ values: values
690
+ };
691
+ }
692
+
693
+ // scatter or numeric line/area
694
+ function prepareNumberData(chart) {
695
+ var series = chart.data;
696
+ var values = [];
697
+
698
+ for (var i = 0; i < series.length; i++) {
699
+ var data = series[i].data;
700
+
701
+ data.sort(sortByNumberSeries);
702
+
703
+ var points = [];
704
+ for (var j = 0; j < data.length; j++) {
705
+ var v = data[j];
706
+ points.push({
707
+ x: v[0],
708
+ y: v[1]
709
+ });
661
710
  }
711
+ values.push(points);
712
+ }
713
+
714
+ return {
715
+ labels: [],
716
+ values: values
717
+ };
718
+ }
719
+
720
+ function prepareData(chart, chartType) {
721
+ if (chartType === "bubble") {
722
+ return prepareBubbleData(chart);
723
+ } else if (chart.xtype === "number" && chartType !== "bar" && chartType !== "column") {
724
+ return prepareNumberData(chart);
662
725
  } else {
663
- for (var i$2 = 0; i$2 < series.length; i$2++) {
664
- var s$2 = series[i$2];
665
- var d$1 = [];
666
- for (var j$2 = 0; j$2 < s$2.data.length; j$2++) {
667
- var point = {
668
- x: toFloat(s$2.data[j$2][0]),
669
- y: toFloat(s$2.data[j$2][1])
670
- };
671
- if (chartType === "bubble") {
672
- point.r = toFloat(s$2.data[j$2][2]) * 20 / max;
673
- // custom attribute, for tooltip
674
- point.v = s$2.data[j$2][2];
675
- }
676
- d$1.push(point);
677
- }
678
- rows2.push(d$1);
679
- }
726
+ return prepareDefaultData(chart);
680
727
  }
728
+ }
681
729
 
682
- var color;
683
- var backgroundColor;
730
+ function createDataTable(chart, options, chartType) {
731
+ var ref = prepareData(chart, chartType);
732
+ var labels = ref.labels;
733
+ var values = ref.values;
684
734
 
685
- for (i = 0; i < series.length; i++) {
686
- s = series[i];
735
+ var series = chart.data;
736
+ var datasets = [];
737
+ var colors = chart.options.colors || defaultColors;
738
+ for (var i = 0; i < series.length; i++) {
739
+ var s = series[i];
687
740
 
688
741
  // use colors for each bar for single series format
742
+ var color = (void 0);
743
+ var backgroundColor = (void 0);
689
744
  if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
690
745
  color = colors;
691
746
  backgroundColor = [];
692
- for (var j$3 = 0; j$3 < colors.length; j$3++) {
693
- backgroundColor[j$3] = addOpacity(color[j$3], 0.5);
747
+ for (var j = 0; j < colors.length; j++) {
748
+ backgroundColor[j] = addOpacity(color[j], 0.5);
694
749
  }
695
750
  } else {
696
751
  color = s.color || colors[i];
@@ -699,7 +754,7 @@
699
754
 
700
755
  var dataset = {
701
756
  label: s.name || "",
702
- data: rows2[i],
757
+ data: values[i],
703
758
  fill: chartType === "area",
704
759
  borderColor: color,
705
760
  backgroundColor: backgroundColor,
@@ -762,90 +817,86 @@
762
817
  }
763
818
  }
764
819
 
765
- // for empty datetime chart
766
- if (chart.xtype === "datetime" && labels.length === 0) {
767
- if (notnull(xmin)) {
768
- labels.push(toDate(xmin));
769
- }
770
- if (notnull(xmax)) {
771
- labels.push(toDate(xmax));
772
- }
773
- day = false;
774
- week = false;
775
- month = false;
776
- year = false;
777
- hour = false;
778
- minute = false;
779
- }
780
-
781
- if (chart.xtype === "datetime" && labels.length > 0) {
782
- var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
783
- var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
820
+ if (chart.xtype === "datetime") {
821
+ var timeUnit = calculateTimeUnit(labels);
784
822
 
785
- for (i = 1; i < labels.length; i++) {
786
- var value$1 = labels[i].getTime();
787
- if (value$1 < minTime) {
788
- minTime = value$1;
823
+ // for empty datetime chart
824
+ if (labels.length === 0) {
825
+ if (notnull(xmin)) {
826
+ labels.push(toDate(xmin));
789
827
  }
790
- if (value$1 > maxTime) {
791
- maxTime = value$1;
828
+ if (notnull(xmax)) {
829
+ labels.push(toDate(xmax));
792
830
  }
793
831
  }
794
832
 
795
- var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
796
-
797
- if (!options.scales.x.time.unit) {
798
- var step;
799
- if (year || timeDiff > 365 * 10) {
800
- options.scales.x.time.unit = "year";
801
- step = 365;
802
- } else if (month || timeDiff > 30 * 10) {
803
- options.scales.x.time.unit = "month";
804
- step = 30;
805
- } else if (day || timeDiff > 10) {
806
- options.scales.x.time.unit = "day";
807
- step = 1;
808
- } else if (hour || timeDiff > 0.5) {
809
- options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
810
- options.scales.x.time.unit = "hour";
811
- step = 1 / 24.0;
812
- } else if (minute) {
813
- options.scales.x.time.displayFormats = {minute: "h:mm a"};
814
- options.scales.x.time.unit = "minute";
815
- step = 1 / 24.0 / 60.0;
833
+ if (labels.length > 0) {
834
+ var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
835
+ var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
836
+
837
+ for (var i$1 = 1; i$1 < labels.length; i$1++) {
838
+ var value = labels[i$1].getTime();
839
+ if (value < minTime) {
840
+ minTime = value;
841
+ }
842
+ if (value > maxTime) {
843
+ maxTime = value;
844
+ }
816
845
  }
817
846
 
818
- if (step && timeDiff > 0) {
819
- // width not available for hidden elements
820
- var width = chart.element.offsetWidth;
821
- if (width > 0) {
822
- var unitStepSize = Math.ceil(timeDiff / step / (width / 100.0));
823
- if (week && step === 1) {
824
- unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
847
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
848
+
849
+ if (!options.scales.x.time.unit) {
850
+ var step;
851
+ if (timeUnit === "year" || timeDiff > 365 * 10) {
852
+ options.scales.x.time.unit = "year";
853
+ step = 365;
854
+ } else if (timeUnit === "month" || timeDiff > 30 * 10) {
855
+ options.scales.x.time.unit = "month";
856
+ step = 30;
857
+ } else if (timeUnit === "week" || timeUnit === "day" || timeDiff > 10) {
858
+ options.scales.x.time.unit = "day";
859
+ step = 1;
860
+ } else if (timeUnit === "hour" || timeDiff > 0.5) {
861
+ options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
862
+ options.scales.x.time.unit = "hour";
863
+ step = 1 / 24.0;
864
+ } else if (timeUnit === "minute") {
865
+ options.scales.x.time.displayFormats = {minute: "h:mm a"};
866
+ options.scales.x.time.unit = "minute";
867
+ step = 1 / 24.0 / 60.0;
868
+ }
869
+
870
+ if (step && timeDiff > 0) {
871
+ // width not available for hidden elements
872
+ var width = chart.element.offsetWidth;
873
+ if (width > 0) {
874
+ var unitStepSize = Math.ceil(timeDiff / step / (width / 100.0));
875
+ if (timeUnit === "week" && step === 1) {
876
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
877
+ }
878
+ options.scales.x.ticks.stepSize = unitStepSize;
825
879
  }
826
- options.scales.x.time.stepSize = unitStepSize;
827
880
  }
828
881
  }
829
- }
830
882
 
831
- if (!options.scales.x.time.tooltipFormat) {
832
- if (day) {
833
- options.scales.x.time.tooltipFormat = "PP";
834
- } else if (hour) {
835
- options.scales.x.time.tooltipFormat = "MMM d, h a";
836
- } else if (minute) {
837
- options.scales.x.time.tooltipFormat = "h:mm a";
883
+ if (!options.scales.x.time.tooltipFormat) {
884
+ if (isDay(timeUnit)) {
885
+ options.scales.x.time.tooltipFormat = "PP";
886
+ } else if (timeUnit === "hour") {
887
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
888
+ } else if (timeUnit === "minute") {
889
+ options.scales.x.time.tooltipFormat = "h:mm a";
890
+ }
838
891
  }
839
892
  }
840
893
  }
841
894
 
842
- var data = {
895
+ return {
843
896
  labels: labels,
844
897
  datasets: datasets
845
898
  };
846
-
847
- return data;
848
- };
899
+ }
849
900
 
850
901
  var defaultExport$2 = function defaultExport(library) {
851
902
  this.name = "chartjs";
@@ -854,10 +905,6 @@
854
905
 
855
906
  defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
856
907
  var chartOptions = {};
857
- // fix for https://github.com/chartjs/Chart.js/issues/2441
858
- if (!chart.options.max && allZeros(chart.data)) {
859
- chartOptions.max = 1;
860
- }
861
908
 
862
909
  var options = jsOptions$2(chart, merge(chartOptions, chart.options));
863
910
  setFormatOptions$1(chart, options, chartType);
@@ -866,7 +913,7 @@
866
913
 
867
914
  if (chart.xtype === "number") {
868
915
  options.scales.x.type = options.scales.x.type || "linear";
869
- options.scales.x.position = options.scales.x.position ||"bottom";
916
+ options.scales.x.position = options.scales.x.position || "bottom";
870
917
  } else {
871
918
  options.scales.x.type = chart.xtype === "string" ? "category" : "time";
872
919
  }
@@ -933,6 +980,9 @@
933
980
  if (chartType !== "bar") {
934
981
  setLabelSize(chart, data, options);
935
982
  }
983
+ if (!("mode" in options.interaction)) {
984
+ options.interaction.mode = "index";
985
+ }
936
986
  this.drawChart(chart, "bar", data, options);
937
987
  };
938
988
 
@@ -1044,7 +1094,7 @@
1044
1094
  }
1045
1095
  };
1046
1096
 
1047
- var hideLegend$1 = function (options, legend, hideLegend) {
1097
+ function hideLegend$1(options, legend, hideLegend) {
1048
1098
  if (legend !== undefined) {
1049
1099
  options.legend.enabled = !!legend;
1050
1100
  if (legend && legend !== true) {
@@ -1059,38 +1109,38 @@
1059
1109
  } else if (hideLegend) {
1060
1110
  options.legend.enabled = false;
1061
1111
  }
1062
- };
1112
+ }
1063
1113
 
1064
- var setTitle$1 = function (options, title) {
1114
+ function setTitle$1(options, title) {
1065
1115
  options.title.text = title;
1066
- };
1116
+ }
1067
1117
 
1068
- var setMin$1 = function (options, min) {
1118
+ function setMin$1(options, min) {
1069
1119
  options.yAxis.min = min;
1070
- };
1120
+ }
1071
1121
 
1072
- var setMax$1 = function (options, max) {
1122
+ function setMax$1(options, max) {
1073
1123
  options.yAxis.max = max;
1074
- };
1124
+ }
1075
1125
 
1076
- var setStacked$1 = function (options, stacked) {
1126
+ function setStacked$1(options, stacked) {
1077
1127
  var stackedValue = stacked ? (stacked === true ? "normal" : stacked) : null;
1078
1128
  options.plotOptions.series.stacking = stackedValue;
1079
1129
  options.plotOptions.area.stacking = stackedValue;
1080
1130
  options.plotOptions.areaspline.stacking = stackedValue;
1081
- };
1131
+ }
1082
1132
 
1083
- var setXtitle$1 = function (options, title) {
1133
+ function setXtitle$1(options, title) {
1084
1134
  options.xAxis.title.text = title;
1085
- };
1135
+ }
1086
1136
 
1087
- var setYtitle$1 = function (options, title) {
1137
+ function setYtitle$1(options, title) {
1088
1138
  options.yAxis.title.text = title;
1089
- };
1139
+ }
1090
1140
 
1091
1141
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1092
1142
 
1093
- var setFormatOptions = function(chart, options, chartType) {
1143
+ function setFormatOptions(chart, options, chartType) {
1094
1144
  var formatOptions = {
1095
1145
  prefix: chart.options.prefix,
1096
1146
  suffix: chart.options.suffix,
@@ -1113,7 +1163,7 @@
1113
1163
  return '<span style="color:' + this.color + '">\u25CF</span> ' + formatValue(this.series.name + ': <b>', this.y, formatOptions) + '</b><br/>';
1114
1164
  };
1115
1165
  }
1116
- };
1166
+ }
1117
1167
 
1118
1168
  var defaultExport$1 = function defaultExport(library) {
1119
1169
  this.name = "highcharts";
@@ -1149,7 +1199,7 @@
1149
1199
  }
1150
1200
  }
1151
1201
 
1152
- var options = jsOptions$1(chart, chart.options, chartOptions), data, i, j;
1202
+ var options = jsOptions$1(chart, chart.options, chartOptions);
1153
1203
  if (chart.xtype === "number") {
1154
1204
  options.xAxis.type = options.xAxis.type || "linear";
1155
1205
  } else {
@@ -1161,13 +1211,15 @@
1161
1211
  setFormatOptions(chart, options, chartType);
1162
1212
 
1163
1213
  var series = chart.data;
1164
- for (i = 0; i < series.length; i++) {
1214
+ for (var i = 0; i < series.length; i++) {
1165
1215
  series[i].name = series[i].name || "Value";
1166
- data = series[i].data;
1216
+ var data = series[i].data;
1167
1217
  if (chart.xtype === "datetime") {
1168
- for (j = 0; j < data.length; j++) {
1218
+ for (var j = 0; j < data.length; j++) {
1169
1219
  data[j][0] = data[j][0].getTime();
1170
1220
  }
1221
+ } else if (chart.xtype === "number") {
1222
+ data.sort(sortByNumberSeries);
1171
1223
  }
1172
1224
  series[i].marker = {symbol: "circle"};
1173
1225
  if (chart.options.points === false) {
@@ -1216,15 +1268,17 @@
1216
1268
  defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
1217
1269
  chartType = chartType || "column";
1218
1270
  var series = chart.data;
1219
- var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1271
+ var options = jsOptions$1(chart, chart.options);
1272
+ var rows = [];
1273
+ var categories = [];
1220
1274
  options.chart.type = chartType;
1221
1275
  setFormatOptions(chart, options, chartType);
1222
1276
 
1223
- for (i = 0; i < series.length; i++) {
1224
- s = series[i];
1277
+ for (var i = 0; i < series.length; i++) {
1278
+ var s = series[i];
1225
1279
 
1226
- for (j = 0; j < s.data.length; j++) {
1227
- d = s.data[j];
1280
+ for (var j = 0; j < s.data.length; j++) {
1281
+ var d = s.data[j];
1228
1282
  if (!rows[d[0]]) {
1229
1283
  rows[d[0]] = new Array(series.length);
1230
1284
  categories.push(d[0]);
@@ -1239,19 +1293,19 @@
1239
1293
 
1240
1294
  options.xAxis.categories = categories;
1241
1295
 
1242
- var newSeries = [], d2;
1243
- for (i = 0; i < series.length; i++) {
1244
- d = [];
1245
- for (j = 0; j < categories.length; j++) {
1246
- d.push(rows[categories[j]][i] || 0);
1296
+ var newSeries = [];
1297
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1298
+ var d$1 = [];
1299
+ for (var j$1 = 0; j$1 < categories.length; j$1++) {
1300
+ d$1.push(rows[categories[j$1]][i$1] || 0);
1247
1301
  }
1248
1302
 
1249
- d2 = {
1250
- name: series[i].name || "Value",
1251
- data: d
1303
+ var d2 = {
1304
+ name: series[i$1].name || "Value",
1305
+ data: d$1
1252
1306
  };
1253
- if (series[i].stack) {
1254
- d2.stack = series[i].stack;
1307
+ if (series[i$1].stack) {
1308
+ d2.stack = series[i$1].stack;
1255
1309
  }
1256
1310
 
1257
1311
  newSeries.push(d2);
@@ -1334,7 +1388,7 @@
1334
1388
  }
1335
1389
  };
1336
1390
 
1337
- var hideLegend = function (options, legend, hideLegend) {
1391
+ function hideLegend(options, legend, hideLegend) {
1338
1392
  if (legend !== undefined) {
1339
1393
  var position;
1340
1394
  if (!legend) {
@@ -1348,53 +1402,53 @@
1348
1402
  } else if (hideLegend) {
1349
1403
  options.legend.position = "none";
1350
1404
  }
1351
- };
1405
+ }
1352
1406
 
1353
- var setTitle = function (options, title) {
1407
+ function setTitle(options, title) {
1354
1408
  options.title = title;
1355
1409
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1356
- };
1410
+ }
1357
1411
 
1358
- var setMin = function (options, min) {
1412
+ function setMin(options, min) {
1359
1413
  options.vAxis.viewWindow.min = min;
1360
- };
1414
+ }
1361
1415
 
1362
- var setMax = function (options, max) {
1416
+ function setMax(options, max) {
1363
1417
  options.vAxis.viewWindow.max = max;
1364
- };
1418
+ }
1365
1419
 
1366
- var setBarMin = function (options, min) {
1420
+ function setBarMin(options, min) {
1367
1421
  options.hAxis.viewWindow.min = min;
1368
- };
1422
+ }
1369
1423
 
1370
- var setBarMax = function (options, max) {
1424
+ function setBarMax(options, max) {
1371
1425
  options.hAxis.viewWindow.max = max;
1372
- };
1426
+ }
1373
1427
 
1374
- var setStacked = function (options, stacked) {
1375
- options.isStacked = stacked ? stacked : false;
1376
- };
1428
+ function setStacked(options, stacked) {
1429
+ options.isStacked = stacked || false;
1430
+ }
1377
1431
 
1378
- var setXtitle = function (options, title) {
1432
+ function setXtitle(options, title) {
1379
1433
  options.hAxis.title = title;
1380
1434
  options.hAxis.titleTextStyle.italic = false;
1381
- };
1435
+ }
1382
1436
 
1383
- var setYtitle = function (options, title) {
1437
+ function setYtitle(options, title) {
1384
1438
  options.vAxis.title = title;
1385
1439
  options.vAxis.titleTextStyle.italic = false;
1386
- };
1440
+ }
1387
1441
 
1388
1442
  var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1389
1443
 
1390
- var resize = function (callback) {
1444
+ function resize(callback) {
1391
1445
  if (window.attachEvent) {
1392
1446
  window.attachEvent("onresize", callback);
1393
1447
  } else if (window.addEventListener) {
1394
1448
  window.addEventListener("resize", callback, true);
1395
1449
  }
1396
1450
  callback();
1397
- };
1451
+ }
1398
1452
 
1399
1453
  var defaultExport = function defaultExport(library) {
1400
1454
  this.name = "google";
@@ -1530,11 +1584,12 @@
1530
1584
  var chartOptions = {};
1531
1585
  var options = jsOptions(chart, chart.options, chartOptions);
1532
1586
 
1533
- var series = chart.data, rows2 = [], i, j, data, d;
1534
- for (i = 0; i < series.length; i++) {
1587
+ var series = chart.data;
1588
+ var rows2 = [];
1589
+ for (var i = 0; i < series.length; i++) {
1535
1590
  series[i].name = series[i].name || "Value";
1536
- d = series[i].data;
1537
- for (j = 0; j < d.length; j++) {
1591
+ var d = series[i].data;
1592
+ for (var j = 0; j < d.length; j++) {
1538
1593
  var row = new Array(series.length + 1);
1539
1594
  row[0] = d[j][0];
1540
1595
  row[i + 1] = d[j][1];
@@ -1542,10 +1597,10 @@
1542
1597
  }
1543
1598
  }
1544
1599
 
1545
- data = new this$1$1.library.visualization.DataTable();
1600
+ var data = new this$1$1.library.visualization.DataTable();
1546
1601
  data.addColumn("number", "");
1547
- for (i = 0; i < series.length; i++) {
1548
- data.addColumn("number", series[i].name);
1602
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1603
+ data.addColumn("number", series[i$1].name);
1549
1604
  }
1550
1605
  data.addRows(rows2);
1551
1606
 
@@ -1632,10 +1687,9 @@
1632
1687
  };
1633
1688
 
1634
1689
  defaultExport.prototype.runCallbacks = function runCallbacks () {
1635
- var cb, call;
1636
1690
  for (var i = 0; i < callbacks.length; i++) {
1637
- cb = callbacks[i];
1638
- 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));
1691
+ var cb = callbacks[i];
1692
+ 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));
1639
1693
  if (call) {
1640
1694
  cb.callback();
1641
1695
  callbacks.splice(i, 1);
@@ -1646,44 +1700,48 @@
1646
1700
 
1647
1701
  // cant use object as key
1648
1702
  defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1649
- var i, j, s, d, key, rows = [], sortedLabels = [];
1650
- for (i = 0; i < series.length; i++) {
1651
- s = series[i];
1703
+ var rows = [];
1704
+ var sortedLabels = [];
1705
+ for (var i = 0; i < series.length; i++) {
1706
+ var s = series[i];
1652
1707
  series[i].name = series[i].name || "Value";
1653
1708
 
1654
- for (j = 0; j < s.data.length; j++) {
1655
- d = s.data[j];
1656
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
1709
+ for (var j = 0; j < s.data.length; j++) {
1710
+ var d = s.data[j];
1711
+ var key = columnType === "datetime" ? d[0].getTime() : d[0];
1657
1712
  if (!rows[key]) {
1658
1713
  rows[key] = new Array(series.length);
1659
1714
  sortedLabels.push(key);
1660
1715
  }
1661
- rows[key][i] = toFloat(d[1]);
1716
+ rows[key][i] = d[1];
1662
1717
  }
1663
1718
  }
1664
1719
 
1665
1720
  var rows2 = [];
1666
- var day = true;
1667
- var value;
1668
- for (j = 0; j < sortedLabels.length; j++) {
1669
- i = sortedLabels[j];
1721
+ var values = [];
1722
+ for (var j$1 = 0; j$1 < sortedLabels.length; j$1++) {
1723
+ var i$1 = sortedLabels[j$1];
1724
+ var value = (void 0);
1670
1725
  if (columnType === "datetime") {
1671
- value = new Date(toFloat(i));
1672
- day = day && isDay(value);
1673
- } else if (columnType === "number") {
1674
- value = toFloat(i);
1726
+ value = new Date(i$1);
1727
+ values.push(value);
1675
1728
  } else {
1676
- value = i;
1729
+ value = i$1;
1677
1730
  }
1678
- rows2.push([value].concat(rows[i]));
1731
+ rows2.push([value].concat(rows[i$1]));
1679
1732
  }
1733
+
1734
+ var day = true;
1680
1735
  if (columnType === "datetime") {
1681
1736
  rows2.sort(sortByTime);
1737
+
1738
+ var timeUnit = calculateTimeUnit(values, true);
1739
+ day = isDay(timeUnit);
1682
1740
  } else if (columnType === "number") {
1683
1741
  rows2.sort(sortByNumberSeries);
1684
1742
 
1685
- for (i = 0; i < rows2.length; i++) {
1686
- rows2[i][0] = toStr(rows2[i][0]);
1743
+ for (var i$2 = 0; i$2 < rows2.length; i$2++) {
1744
+ rows2[i$2][0] = toStr(rows2[i$2][0]);
1687
1745
  }
1688
1746
 
1689
1747
  columnType = "string";
@@ -1693,17 +1751,132 @@
1693
1751
  var data = new this.library.visualization.DataTable();
1694
1752
  columnType = columnType === "datetime" && day ? "date" : columnType;
1695
1753
  data.addColumn(columnType, "");
1696
- for (i = 0; i < series.length; i++) {
1697
- data.addColumn("number", series[i].name);
1754
+ for (var i$3 = 0; i$3 < series.length; i$3++) {
1755
+ data.addColumn("number", series[i$3].name);
1698
1756
  }
1699
1757
  data.addRows(rows2);
1700
1758
 
1701
1759
  return data;
1702
1760
  };
1703
1761
 
1762
+ var adapters = [];
1763
+
1764
+ function getAdapterType(library) {
1765
+ if (library) {
1766
+ if (library.product === "Highcharts") {
1767
+ return defaultExport$1;
1768
+ } else if (library.charts) {
1769
+ return defaultExport;
1770
+ } else if (isFunction(library)) {
1771
+ return defaultExport$2;
1772
+ }
1773
+ }
1774
+ throw new Error("Unknown adapter");
1775
+ }
1776
+
1777
+ function addAdapter(library) {
1778
+ var adapterType = getAdapterType(library);
1779
+
1780
+ for (var i = 0; i < adapters.length; i++) {
1781
+ if (adapters[i].library === library) {
1782
+ return;
1783
+ }
1784
+ }
1785
+
1786
+ adapters.push(new adapterType(library));
1787
+ }
1788
+
1789
+ function loadAdapters() {
1790
+ if ("Chart" in window) {
1791
+ addAdapter(window.Chart);
1792
+ }
1793
+
1794
+ if ("Highcharts" in window) {
1795
+ addAdapter(window.Highcharts);
1796
+ }
1797
+
1798
+ if (window.google && window.google.charts) {
1799
+ addAdapter(window.google);
1800
+ }
1801
+ }
1802
+
1803
+ // TODO remove chartType if cross-browser way
1804
+ // to get the name of the chart class
1805
+ function callAdapter(chartType, chart) {
1806
+ var fnName = "render" + chartType;
1807
+ var adapterName = chart.options.adapter;
1808
+
1809
+ loadAdapters();
1810
+
1811
+ for (var i = 0; i < adapters.length; i++) {
1812
+ var adapter = adapters[i];
1813
+ if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
1814
+ chart.adapter = adapter.name;
1815
+ chart.__adapterObject = adapter;
1816
+ return adapter[fnName](chart);
1817
+ }
1818
+ }
1819
+
1820
+ if (adapters.length > 0) {
1821
+ throw new Error("No charting library found for " + chartType);
1822
+ } else {
1823
+ throw new Error("No charting libraries found - be sure to include one before your charts");
1824
+ }
1825
+ }
1826
+
1827
+ var Chartkick = {
1828
+ charts: {},
1829
+ configure: function (options) {
1830
+ for (var key in options) {
1831
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
1832
+ Chartkick.config[key] = options[key];
1833
+ }
1834
+ }
1835
+ },
1836
+ setDefaultOptions: function (opts) {
1837
+ Chartkick.options = opts;
1838
+ },
1839
+ eachChart: function (callback) {
1840
+ for (var chartId in Chartkick.charts) {
1841
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1842
+ callback(Chartkick.charts[chartId]);
1843
+ }
1844
+ }
1845
+ },
1846
+ destroyAll: function () {
1847
+ for (var chartId in Chartkick.charts) {
1848
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1849
+ Chartkick.charts[chartId].destroy();
1850
+ delete Chartkick.charts[chartId];
1851
+ }
1852
+ }
1853
+ },
1854
+ config: {},
1855
+ options: {},
1856
+ adapters: adapters,
1857
+ addAdapter: addAdapter,
1858
+ use: function (adapter) {
1859
+ addAdapter(adapter);
1860
+ return Chartkick;
1861
+ }
1862
+ };
1863
+
1864
+ function formatSeriesBubble(data) {
1865
+ var r = [];
1866
+ for (var i = 0; i < data.length; i++) {
1867
+ r.push([toFloat(data[i][0]), toFloat(data[i][1]), toFloat(data[i][2])]);
1868
+ }
1869
+ return r;
1870
+ }
1871
+
1872
+ // casts data to proper type
1873
+ // sorting is left to adapters
1704
1874
  function formatSeriesData(data, keyType) {
1705
- var r = [], j, keyFunc;
1875
+ if (keyType === "bubble") {
1876
+ return formatSeriesBubble(data);
1877
+ }
1706
1878
 
1879
+ var keyFunc;
1707
1880
  if (keyType === "number") {
1708
1881
  keyFunc = toFloat;
1709
1882
  } else if (keyType === "datetime") {
@@ -1712,22 +1885,10 @@
1712
1885
  keyFunc = toStr;
1713
1886
  }
1714
1887
 
1715
- if (keyType === "bubble") {
1716
- for (j = 0; j < data.length; j++) {
1717
- r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1718
- }
1719
- } else {
1720
- for (j = 0; j < data.length; j++) {
1721
- r.push([keyFunc(data[j][0]), toFloat(data[j][1])]);
1722
- }
1723
- }
1724
-
1725
- if (keyType === "datetime") {
1726
- r.sort(sortByTime);
1727
- } else if (keyType === "number") {
1728
- r.sort(sortByNumberSeries);
1888
+ var r = [];
1889
+ for (var i = 0; i < data.length; i++) {
1890
+ r.push([keyFunc(data[i][0]), toFloat(data[i][1])]);
1729
1891
  }
1730
-
1731
1892
  return r;
1732
1893
  }
1733
1894
 
@@ -1748,10 +1909,9 @@
1748
1909
  }
1749
1910
 
1750
1911
  function detectXTypeWithFunction(series, func) {
1751
- var i, j, data;
1752
- for (i = 0; i < series.length; i++) {
1753
- data = toArr(series[i].data);
1754
- for (j = 0; j < data.length; j++) {
1912
+ for (var i = 0; i < series.length; i++) {
1913
+ var data = toArr(series[i].data);
1914
+ for (var j = 0; j < data.length; j++) {
1755
1915
  if (!func(data[j][0])) {
1756
1916
  return false;
1757
1917
  }
@@ -1763,11 +1923,11 @@
1763
1923
  // creates a shallow copy of each element of the array
1764
1924
  // elements are expected to be objects
1765
1925
  function copySeries(series) {
1766
- var newSeries = [], i, j;
1767
- for (i = 0; i < series.length; i++) {
1926
+ var newSeries = [];
1927
+ for (var i = 0; i < series.length; i++) {
1768
1928
  var copy = {};
1769
- for (j in series[i]) {
1770
- if (series[i].hasOwnProperty(j)) {
1929
+ for (var j in series[i]) {
1930
+ if (Object.prototype.hasOwnProperty.call(series[i], j)) {
1771
1931
  copy[j] = series[i][j];
1772
1932
  }
1773
1933
  }
@@ -1777,13 +1937,11 @@
1777
1937
  }
1778
1938
 
1779
1939
  function processSeries(chart, keyType, noDatetime) {
1780
- var i;
1781
-
1782
1940
  var opts = chart.options;
1783
1941
  var series = chart.rawData;
1784
1942
 
1785
1943
  // see if one series or multiple
1786
- chart.singleSeriesFormat = (!isArray(series) || typeof series[0] !== "object" || isArray(series[0]));
1944
+ chart.singleSeriesFormat = !isArray(series) || !isPlainObject(series[0]);
1787
1945
  if (chart.singleSeriesFormat) {
1788
1946
  series = [{name: opts.label, data: series}];
1789
1947
  }
@@ -1791,23 +1949,23 @@
1791
1949
  // convert to array
1792
1950
  // must come before dataEmpty check
1793
1951
  series = copySeries(series);
1794
- for (i = 0; i < series.length; i++) {
1952
+ for (var i = 0; i < series.length; i++) {
1795
1953
  series[i].data = toArr(series[i].data);
1796
1954
  }
1797
1955
 
1798
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1956
+ chart.xtype = keyType || (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1799
1957
 
1800
1958
  // right format
1801
- for (i = 0; i < series.length; i++) {
1802
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
1959
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1960
+ series[i$1].data = formatSeriesData(series[i$1].data, chart.xtype);
1803
1961
  }
1804
1962
 
1805
1963
  return series;
1806
1964
  }
1807
1965
 
1808
1966
  function processSimple(chart) {
1809
- var perfectData = toArr(chart.rawData), i;
1810
- for (i = 0; i < perfectData.length; i++) {
1967
+ var perfectData = toArr(chart.rawData);
1968
+ for (var i = 0; i < perfectData.length; i++) {
1811
1969
  perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
1812
1970
  }
1813
1971
  return perfectData;
@@ -1827,48 +1985,51 @@
1827
1985
  }
1828
1986
 
1829
1987
  function addDownloadButton(chart) {
1830
- var element = chart.element;
1831
- var link = document.createElement("a");
1832
-
1833
1988
  var download = chart.options.download;
1834
1989
  if (download === true) {
1835
1990
  download = {};
1836
1991
  } else if (typeof download === "string") {
1837
1992
  download = {filename: download};
1838
1993
  }
1839
- link.download = download.filename || "chart.png"; // https://caniuse.com/download
1840
1994
 
1995
+ var link = document.createElement("a");
1996
+ link.download = download.filename || "chart.png";
1841
1997
  link.style.position = "absolute";
1842
1998
  link.style.top = "20px";
1843
1999
  link.style.right = "20px";
1844
2000
  link.style.zIndex = 1000;
1845
2001
  link.style.lineHeight = "20px";
1846
2002
  link.target = "_blank"; // for safari
2003
+
1847
2004
  var image = document.createElement("img");
2005
+ // icon from Font Awesome, modified to set fill color
2006
+ 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>";
2007
+ image.src = "data:image/svg+xml;utf8," + (encodeURIComponent(svg));
1848
2008
  image.alt = "Download";
2009
+ image.style.width = "20px";
2010
+ image.style.height = "20px";
1849
2011
  image.style.border = "none";
1850
- // icon from font-awesome
1851
- // http://fa2png.io/
1852
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1853
2012
  link.appendChild(image);
2013
+
2014
+ var element = chart.element;
1854
2015
  element.style.position = "relative";
1855
2016
 
1856
2017
  chart.__downloadAttached = true;
1857
2018
 
1858
2019
  // mouseenter
1859
- chart.__enterEvent = addEvent(element, "mouseover", function(e) {
2020
+ chart.__enterEvent = element.addEventListener("mouseover", function (e) {
1860
2021
  var related = e.relatedTarget;
1861
2022
  // check download option again to ensure it wasn't changed
1862
- if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
2023
+ if ((!related || (related !== this && !this.contains(related))) && chart.options.download) {
1863
2024
  link.href = chart.toImage(download);
1864
2025
  element.appendChild(link);
1865
2026
  }
1866
2027
  });
1867
2028
 
1868
2029
  // mouseleave
1869
- chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
2030
+ chart.__leaveEvent = element.addEventListener("mouseout", function (e) {
1870
2031
  var related = e.relatedTarget;
1871
- if (!related || (related !== this && !childOf(this, related))) {
2032
+ if (!related || (related !== this && !this.contains(related))) {
1872
2033
  if (link.parentNode) {
1873
2034
  link.parentNode.removeChild(link);
1874
2035
  }
@@ -1876,37 +2037,9 @@
1876
2037
  });
1877
2038
  }
1878
2039
 
1879
- // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1880
- function addEvent(elem, event, fn) {
1881
- if (elem.addEventListener) {
1882
- elem.addEventListener(event, fn, false);
1883
- return fn;
1884
- } else {
1885
- var fn2 = function() {
1886
- // set the this pointer same as addEventListener when fn is called
1887
- return(fn.call(elem, window.event));
1888
- };
1889
- elem.attachEvent("on" + event, fn2);
1890
- return fn2;
1891
- }
1892
- }
1893
-
1894
- function removeEvent(elem, event, fn) {
1895
- if (elem.removeEventListener) {
1896
- elem.removeEventListener(event, fn, false);
1897
- } else {
1898
- elem.detachEvent("on" + event, fn);
1899
- }
1900
- }
1901
-
1902
- // https://gist.github.com/shawnbot/4166283
1903
- function childOf(p, c) {
1904
- if (p === c) { return false; }
1905
- while (c && c !== p) { c = c.parentNode; }
1906
- return c === p;
1907
- }
1908
-
1909
- var pendingRequests = [], runningRequests = 0, maxRequests = 4;
2040
+ var pendingRequests = [];
2041
+ var runningRequests = 0;
2042
+ var maxRequests = 4;
1910
2043
 
1911
2044
  function pushRequest(url, success, error) {
1912
2045
  pendingRequests.push([url, success, error]);
@@ -1930,50 +2063,24 @@
1930
2063
  }
1931
2064
 
1932
2065
  function getJSON(url, success, error) {
1933
- ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1934
- var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1935
- error(message);
1936
- });
1937
- }
1938
-
1939
- function ajaxCall(url, success, error) {
1940
- var $ = window.jQuery || window.Zepto || window.$;
1941
-
1942
- if ($ && $.ajax) {
1943
- $.ajax({
1944
- dataType: "json",
1945
- url: url,
1946
- success: success,
1947
- error: error,
1948
- complete: requestComplete
1949
- });
1950
- } else {
1951
- var xhr = new XMLHttpRequest();
1952
- xhr.open("GET", url, true);
1953
- xhr.setRequestHeader("Content-Type", "application/json");
1954
- xhr.onload = function () {
1955
- requestComplete();
1956
- if (xhr.status === 200) {
1957
- success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1958
- } else {
1959
- error(xhr, "error", xhr.statusText);
1960
- }
1961
- };
1962
- xhr.send();
1963
- }
2066
+ var xhr = new XMLHttpRequest();
2067
+ xhr.open("GET", url, true);
2068
+ xhr.setRequestHeader("Content-Type", "application/json");
2069
+ xhr.onload = function () {
2070
+ requestComplete();
2071
+ if (xhr.status === 200) {
2072
+ success(JSON.parse(xhr.responseText));
2073
+ } else {
2074
+ error(xhr.statusText);
2075
+ }
2076
+ };
2077
+ xhr.send();
1964
2078
  }
1965
2079
 
1966
- var config = {};
1967
- var adapters = [];
1968
-
1969
2080
  // helpers
1970
2081
 
1971
2082
  function setText(element, text) {
1972
- if (document.body.innerText) {
1973
- element.innerText = text;
1974
- } else {
1975
- element.textContent = text;
1976
- }
2083
+ element.textContent = text;
1977
2084
  }
1978
2085
 
1979
2086
  // TODO remove prefix for all messages
@@ -2024,95 +2131,41 @@
2024
2131
  }
2025
2132
  }
2026
2133
 
2027
- function getAdapterType(library) {
2028
- if (library) {
2029
- if (library.product === "Highcharts") {
2030
- return defaultExport$1;
2031
- } else if (library.charts) {
2032
- return defaultExport;
2033
- } else if (isFunction(library)) {
2034
- return defaultExport$2;
2035
- }
2036
- }
2037
- throw new Error("Unknown adapter");
2038
- }
2039
-
2040
- function addAdapter(library) {
2041
- var adapterType = getAdapterType(library);
2042
- var adapter = new adapterType(library);
2043
-
2044
- if (adapters.indexOf(adapter) === -1) {
2045
- adapters.push(adapter);
2046
- }
2047
- }
2048
-
2049
- function loadAdapters() {
2050
- if ("Chart" in window) {
2051
- addAdapter(window.Chart);
2052
- }
2053
-
2054
- if ("Highcharts" in window) {
2055
- addAdapter(window.Highcharts);
2056
- }
2057
-
2058
- if (window.google && window.google.charts) {
2059
- addAdapter(window.google);
2060
- }
2061
- }
2062
-
2063
2134
  function renderChart(chartType, chart) {
2064
2135
  if (dataEmpty(chart.data, chartType)) {
2065
2136
  var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2066
2137
  setText(chart.element, message);
2067
2138
  } else {
2068
2139
  callAdapter(chartType, chart);
2140
+ // TODO add downloadSupported method to adapter
2069
2141
  if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
2070
2142
  addDownloadButton(chart);
2071
2143
  }
2072
2144
  }
2073
2145
  }
2074
2146
 
2075
- // TODO remove chartType if cross-browser way
2076
- // to get the name of the chart class
2077
- function callAdapter(chartType, chart) {
2078
- var i, adapter, fnName, adapterName;
2079
- fnName = "render" + chartType;
2080
- adapterName = chart.options.adapter;
2081
-
2082
- loadAdapters();
2083
-
2084
- for (i = 0; i < adapters.length; i++) {
2085
- adapter = adapters[i];
2086
- if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
2087
- chart.adapter = adapter.name;
2088
- chart.__adapterObject = adapter;
2089
- return adapter[fnName](chart);
2147
+ function getElement(element) {
2148
+ if (typeof element === "string") {
2149
+ var elementId = element;
2150
+ element = document.getElementById(element);
2151
+ if (!element) {
2152
+ throw new Error("No element with id " + elementId);
2090
2153
  }
2091
2154
  }
2092
-
2093
- if (adapters.length > 0) {
2094
- throw new Error("No charting library found for " + chartType);
2095
- } else {
2096
- throw new Error("No charting libraries found - be sure to include one before your charts");
2097
- }
2155
+ return element;
2098
2156
  }
2099
2157
 
2100
2158
  // define classes
2101
2159
 
2102
2160
  var Chart = function Chart(element, dataSource, options) {
2103
- var elementId;
2104
- if (typeof element === "string") {
2105
- elementId = element;
2106
- element = document.getElementById(element);
2107
- if (!element) {
2108
- throw new Error("No element with id " + elementId);
2109
- }
2110
- }
2111
- this.element = element;
2161
+ this.element = getElement(element);
2112
2162
  this.options = merge(Chartkick.options, options || {});
2113
2163
  this.dataSource = dataSource;
2114
2164
 
2115
- Chartkick.charts[element.id] = this;
2165
+ // TODO handle charts without an id for eachChart and destroyAll
2166
+ if (this.element.id) {
2167
+ Chartkick.charts[this.element.id] = this;
2168
+ }
2116
2169
 
2117
2170
  fetchDataSource(this, dataSource, true);
2118
2171
 
@@ -2184,7 +2237,7 @@
2184
2237
 
2185
2238
  if (!this.intervalId) {
2186
2239
  if (refresh) {
2187
- this.intervalId = setInterval( function () {
2240
+ this.intervalId = setInterval(function () {
2188
2241
  this$1$1.refreshData();
2189
2242
  }, refresh * 1000);
2190
2243
  } else {
@@ -2201,6 +2254,7 @@
2201
2254
  };
2202
2255
 
2203
2256
  Chart.prototype.toImage = function toImage (download) {
2257
+ // TODO move logic to adapter
2204
2258
  if (this.adapter === "chartjs") {
2205
2259
  if (download && download.background && download.background !== "transparent") {
2206
2260
  // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
@@ -2231,11 +2285,11 @@
2231
2285
  }
2232
2286
 
2233
2287
  if (this.__enterEvent) {
2234
- removeEvent(this.element, "mouseover", this.__enterEvent);
2288
+ this.element.removeEventListener("mouseover", this.__enterEvent);
2235
2289
  }
2236
2290
 
2237
2291
  if (this.__leaveEvent) {
2238
- removeEvent(this.element, "mouseout", this.__leaveEvent);
2292
+ this.element.removeEventListener("mouseout", this.__leaveEvent);
2239
2293
  }
2240
2294
  };
2241
2295
 
@@ -2254,7 +2308,7 @@
2254
2308
  };
2255
2309
 
2256
2310
  Chart.prototype.__config = function __config () {
2257
- return config;
2311
+ return Chartkick.config;
2258
2312
  };
2259
2313
 
2260
2314
  var LineChart = /*@__PURE__*/(function (Chart) {
@@ -2427,8 +2481,8 @@
2427
2481
  Timeline.prototype.constructor = Timeline;
2428
2482
 
2429
2483
  Timeline.prototype.__processData = function __processData () {
2430
- var i, data = this.rawData;
2431
- for (i = 0; i < data.length; i++) {
2484
+ var data = this.rawData;
2485
+ for (var i = 0; i < data.length; i++) {
2432
2486
  data[i][1] = toDate(data[i][1]);
2433
2487
  data[i][2] = toDate(data[i][2]);
2434
2488
  }
@@ -2442,70 +2496,36 @@
2442
2496
  return Timeline;
2443
2497
  }(Chart));
2444
2498
 
2445
- var Chartkick = {
2446
- LineChart: LineChart,
2447
- PieChart: PieChart,
2448
- ColumnChart: ColumnChart,
2449
- BarChart: BarChart,
2450
- AreaChart: AreaChart,
2451
- GeoChart: GeoChart,
2452
- ScatterChart: ScatterChart,
2453
- BubbleChart: BubbleChart,
2454
- Timeline: Timeline,
2455
- charts: {},
2456
- configure: function (options) {
2457
- for (var key in options) {
2458
- if (options.hasOwnProperty(key)) {
2459
- config[key] = options[key];
2460
- }
2461
- }
2462
- },
2463
- setDefaultOptions: function (opts) {
2464
- Chartkick.options = opts;
2465
- },
2466
- eachChart: function (callback) {
2467
- for (var chartId in Chartkick.charts) {
2468
- if (Chartkick.charts.hasOwnProperty(chartId)) {
2469
- callback(Chartkick.charts[chartId]);
2470
- }
2471
- }
2472
- },
2473
- destroyAll: function() {
2474
- for (var chartId in Chartkick.charts) {
2475
- if (Chartkick.charts.hasOwnProperty(chartId)) {
2476
- Chartkick.charts[chartId].destroy();
2477
- delete Chartkick.charts[chartId];
2478
- }
2479
- }
2480
- },
2481
- config: config,
2482
- options: {},
2483
- adapters: adapters,
2484
- addAdapter: addAdapter,
2485
- use: function(adapter) {
2486
- addAdapter(adapter);
2487
- return Chartkick;
2488
- }
2489
- };
2499
+ Chartkick.LineChart = LineChart;
2500
+ Chartkick.PieChart = PieChart;
2501
+ Chartkick.ColumnChart = ColumnChart;
2502
+ Chartkick.BarChart = BarChart;
2503
+ Chartkick.AreaChart = AreaChart;
2504
+ Chartkick.GeoChart = GeoChart;
2505
+ Chartkick.ScatterChart = ScatterChart;
2506
+ Chartkick.BubbleChart = BubbleChart;
2507
+ Chartkick.Timeline = Timeline;
2490
2508
 
2491
2509
  // not ideal, but allows for simpler integration
2492
2510
  if (typeof window !== "undefined" && !window.Chartkick) {
2493
2511
  window.Chartkick = Chartkick;
2494
2512
 
2495
2513
  // clean up previous charts before Turbolinks loads new page
2496
- document.addEventListener("turbolinks:before-render", function() {
2497
- if (config.autoDestroy !== false) {
2514
+ document.addEventListener("turbolinks:before-render", function () {
2515
+ if (Chartkick.config.autoDestroy !== false) {
2498
2516
  Chartkick.destroyAll();
2499
2517
  }
2500
2518
  });
2501
- document.addEventListener("turbo:before-render", function() {
2502
- if (config.autoDestroy !== false) {
2519
+
2520
+ // clean up previous charts before Turbo loads new page
2521
+ document.addEventListener("turbo:before-render", function () {
2522
+ if (Chartkick.config.autoDestroy !== false) {
2503
2523
  Chartkick.destroyAll();
2504
2524
  }
2505
2525
  });
2506
2526
 
2507
2527
  // use setTimeout so charting library can come later in same JS file
2508
- setTimeout(function() {
2528
+ setTimeout(function () {
2509
2529
  window.dispatchEvent(new Event("chartkick:load"));
2510
2530
  }, 0);
2511
2531
  }