chartkick 4.2.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }