chartkick 3.4.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
- /*
1
+ /*!
2
2
  * Chartkick.js
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v3.2.1
5
+ * v4.0.3
6
6
  * MIT License
7
7
  */
8
8
 
9
9
  (function (global, factory) {
10
10
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
11
  typeof define === 'function' && define.amd ? define(factory) :
12
- (global = global || self, global.Chartkick = factory());
12
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chartkick = factory());
13
13
  }(this, (function () { 'use strict';
14
14
 
15
15
  function isArray(variable) {
@@ -55,42 +55,6 @@
55
55
 
56
56
  var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
57
57
 
58
- // https://github.com/Do/iso8601.js
59
- var ISO8601_PATTERN = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([.,]\d+)?($|Z|([+-])(\d\d)(:)?(\d\d)?)/i;
60
- var DECIMAL_SEPARATOR = String(1.5).charAt(1);
61
-
62
- function parseISO8601(input) {
63
- var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
64
- type = Object.prototype.toString.call(input);
65
- if (type === "[object Date]") {
66
- return input;
67
- }
68
- if (type !== "[object String]") {
69
- return;
70
- }
71
- matches = input.match(ISO8601_PATTERN);
72
- if (matches) {
73
- year = parseInt(matches[1], 10);
74
- month = parseInt(matches[3], 10) - 1;
75
- day = parseInt(matches[5], 10);
76
- hour = parseInt(matches[7], 10);
77
- minutes = matches[9] ? parseInt(matches[9], 10) : 0;
78
- seconds = matches[11] ? parseInt(matches[11], 10) : 0;
79
- milliseconds = matches[12] ? parseFloat(DECIMAL_SEPARATOR + matches[12].slice(1)) * 1000 : 0;
80
- result = Date.UTC(year, month, day, hour, minutes, seconds, milliseconds);
81
- if (matches[13] && matches[14]) {
82
- offset = matches[15] * 60;
83
- if (matches[17]) {
84
- offset += parseInt(matches[17], 10);
85
- }
86
- offset *= matches[14] === "-" ? -1 : 1;
87
- result -= offset * 60 * 1000;
88
- }
89
- return new Date(result);
90
- }
91
- }
92
- // end iso8601.js
93
-
94
58
  function negativeValues(series) {
95
59
  var i, j, data;
96
60
  for (i = 0; i < series.length; i++) {
@@ -120,15 +84,16 @@
120
84
  } else {
121
85
  n = toStr(n);
122
86
  if ((matches = n.match(DATE_PATTERN))) {
123
- year = parseInt(matches[1], 10);
124
- month = parseInt(matches[3], 10) - 1;
125
- day = parseInt(matches[5], 10);
126
- return new Date(year, month, day);
127
- } else { // str
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 {
128
92
  // try our best to get the str into iso8601
129
93
  // TODO be smarter about this
130
94
  var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
131
- n = parseISO8601(str) || new Date(n);
95
+ // Date.parse returns milliseconds if valid and NaN if invalid
96
+ n = new Date(Date.parse(str) || n);
132
97
  }
133
98
  }
134
99
  }
@@ -154,8 +119,8 @@
154
119
  var options = merge({}, defaultOptions);
155
120
  options = merge(options, chartOptions || {});
156
121
 
157
- if (chart.hideLegend || "legend" in opts) {
158
- hideLegend(options, opts.legend, chart.hideLegend);
122
+ if (chart.singleSeriesFormat || "legend" in opts) {
123
+ hideLegend(options, opts.legend, chart.singleSeriesFormat);
159
124
  }
160
125
 
161
126
  if (opts.title) {
@@ -361,42 +326,49 @@
361
326
  var baseOptions = {
362
327
  maintainAspectRatio: false,
363
328
  animation: false,
364
- tooltips: {
365
- displayColors: false,
366
- callbacks: {}
329
+ plugins: {
330
+ legend: {},
331
+ tooltip: {
332
+ displayColors: false,
333
+ callbacks: {}
334
+ },
335
+ title: {
336
+ font: {
337
+ size: 20
338
+ },
339
+ color: "#333"
340
+ }
367
341
  },
368
- legend: {},
369
- title: {fontSize: 20, fontColor: "#333"}
342
+ interaction: {}
370
343
  };
371
344
 
372
- var defaultOptions = {
345
+ var defaultOptions$2 = {
373
346
  scales: {
374
- yAxes: [
375
- {
376
- ticks: {
377
- maxTicksLimit: 4
378
- },
379
- scaleLabel: {
380
- fontSize: 16,
381
- // fontStyle: "bold",
382
- fontColor: "#333"
383
- }
384
- }
385
- ],
386
- xAxes: [
387
- {
388
- gridLines: {
389
- drawOnChartArea: false
347
+ y: {
348
+ ticks: {
349
+ maxTicksLimit: 4
350
+ },
351
+ title: {
352
+ font: {
353
+ size: 16
390
354
  },
391
- scaleLabel: {
392
- fontSize: 16,
393
- // fontStyle: "bold",
394
- fontColor: "#333"
355
+ color: "#333"
356
+ },
357
+ grid: {}
358
+ },
359
+ x: {
360
+ grid: {
361
+ drawOnChartArea: false
362
+ },
363
+ title: {
364
+ font: {
365
+ size: 16
395
366
  },
396
- time: {},
397
- ticks: {}
398
- }
399
- ]
367
+ color: "#333"
368
+ },
369
+ time: {},
370
+ ticks: {}
371
+ }
400
372
  }
401
373
  };
402
374
 
@@ -407,66 +379,66 @@
407
379
  "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
408
380
  ];
409
381
 
410
- var hideLegend = function (options, legend, hideLegend) {
382
+ var hideLegend$2 = function (options, legend, hideLegend) {
411
383
  if (legend !== undefined) {
412
- options.legend.display = !!legend;
384
+ options.plugins.legend.display = !!legend;
413
385
  if (legend && legend !== true) {
414
- options.legend.position = legend;
386
+ options.plugins.legend.position = legend;
415
387
  }
416
388
  } else if (hideLegend) {
417
- options.legend.display = false;
389
+ options.plugins.legend.display = false;
418
390
  }
419
391
  };
420
392
 
421
- var setTitle = function (options, title) {
422
- options.title.display = true;
423
- options.title.text = title;
393
+ var setTitle$2 = function (options, title) {
394
+ options.plugins.title.display = true;
395
+ options.plugins.title.text = title;
424
396
  };
425
397
 
426
- var setMin = function (options, min) {
398
+ var setMin$2 = function (options, min) {
427
399
  if (min !== null) {
428
- options.scales.yAxes[0].ticks.min = toFloat(min);
400
+ options.scales.y.min = toFloat(min);
429
401
  }
430
402
  };
431
403
 
432
- var setMax = function (options, max) {
433
- options.scales.yAxes[0].ticks.max = toFloat(max);
404
+ var setMax$2 = function (options, max) {
405
+ options.scales.y.max = toFloat(max);
434
406
  };
435
407
 
436
- var setBarMin = function (options, min) {
408
+ var setBarMin$1 = function (options, min) {
437
409
  if (min !== null) {
438
- options.scales.xAxes[0].ticks.min = toFloat(min);
410
+ options.scales.x.min = toFloat(min);
439
411
  }
440
412
  };
441
413
 
442
- var setBarMax = function (options, max) {
443
- options.scales.xAxes[0].ticks.max = toFloat(max);
414
+ var setBarMax$1 = function (options, max) {
415
+ options.scales.x.max = toFloat(max);
444
416
  };
445
417
 
446
- var setStacked = function (options, stacked) {
447
- options.scales.xAxes[0].stacked = !!stacked;
448
- options.scales.yAxes[0].stacked = !!stacked;
418
+ var setStacked$2 = function (options, stacked) {
419
+ options.scales.x.stacked = !!stacked;
420
+ options.scales.y.stacked = !!stacked;
449
421
  };
450
422
 
451
- var setXtitle = function (options, title) {
452
- options.scales.xAxes[0].scaleLabel.display = true;
453
- options.scales.xAxes[0].scaleLabel.labelString = title;
423
+ var setXtitle$2 = function (options, title) {
424
+ options.scales.x.title.display = true;
425
+ options.scales.x.title.text = title;
454
426
  };
455
427
 
456
- var setYtitle = function (options, title) {
457
- options.scales.yAxes[0].scaleLabel.display = true;
458
- options.scales.yAxes[0].scaleLabel.labelString = title;
428
+ var setYtitle$2 = function (options, title) {
429
+ options.scales.y.title.display = true;
430
+ options.scales.y.title.text = title;
459
431
  };
460
432
 
461
433
  // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
462
- var addOpacity = function(hex, opacity) {
434
+ var addOpacity = function (hex, opacity) {
463
435
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
464
436
  return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
465
437
  };
466
438
 
467
439
  // check if not null or undefined
468
440
  // https://stackoverflow.com/a/27757708/1177228
469
- var notnull = function(x) {
441
+ var notnull = function (x) {
470
442
  return x != null;
471
443
  };
472
444
 
@@ -477,9 +449,9 @@
477
449
  } else if (maxLabelSize < 10) {
478
450
  maxLabelSize = 10;
479
451
  }
480
- if (!options.scales.xAxes[0].ticks.callback) {
481
- options.scales.xAxes[0].ticks.callback = function (value) {
482
- value = toStr(value);
452
+ if (!options.scales.x.ticks.callback) {
453
+ options.scales.x.ticks.callback = function (value) {
454
+ value = toStr(this.getLabelForValue(value));
483
455
  if (value.length > maxLabelSize) {
484
456
  return value.substring(0, maxLabelSize - 2) + "...";
485
457
  } else {
@@ -489,7 +461,7 @@
489
461
  }
490
462
  };
491
463
 
492
- var setFormatOptions = function(chart, options, chartType) {
464
+ var setFormatOptions$1 = function (chart, options, chartType) {
493
465
  var formatOptions = {
494
466
  prefix: chart.options.prefix,
495
467
  suffix: chart.options.suffix,
@@ -529,49 +501,49 @@
529
501
  }
530
502
 
531
503
  if (chartType !== "pie") {
532
- var myAxes = options.scales.yAxes;
504
+ var axis = options.scales.y;
533
505
  if (chartType === "bar") {
534
- myAxes = options.scales.xAxes;
506
+ axis = options.scales.x;
535
507
  }
536
508
 
537
509
  if (formatOptions.byteScale) {
538
- if (!myAxes[0].ticks.stepSize) {
539
- myAxes[0].ticks.stepSize = formatOptions.byteScale / 2;
510
+ if (!axis.ticks.stepSize) {
511
+ axis.ticks.stepSize = formatOptions.byteScale / 2;
540
512
  }
541
- if (!myAxes[0].ticks.maxTicksLimit) {
542
- myAxes[0].ticks.maxTicksLimit = 4;
513
+ if (!axis.ticks.maxTicksLimit) {
514
+ axis.ticks.maxTicksLimit = 4;
543
515
  }
544
516
  }
545
517
 
546
- if (!myAxes[0].ticks.callback) {
547
- myAxes[0].ticks.callback = function (value) {
518
+ if (!axis.ticks.callback) {
519
+ axis.ticks.callback = function (value) {
548
520
  return formatValue("", value, formatOptions, true);
549
521
  };
550
522
  }
551
523
  }
552
524
 
553
- if (!options.tooltips.callbacks.label) {
525
+ if (!options.plugins.tooltip.callbacks.label) {
554
526
  if (chartType === "scatter") {
555
- options.tooltips.callbacks.label = function (item, data) {
556
- var label = data.datasets[item.datasetIndex].label || '';
527
+ options.plugins.tooltip.callbacks.label = function (context) {
528
+ var label = context.dataset.label || '';
557
529
  if (label) {
558
530
  label += ': ';
559
531
  }
560
- return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
532
+ return label + '(' + context.label + ', ' + context.formattedValue + ')';
561
533
  };
562
534
  } else if (chartType === "bubble") {
563
- options.tooltips.callbacks.label = function (item, data) {
564
- var label = data.datasets[item.datasetIndex].label || '';
535
+ options.plugins.tooltip.callbacks.label = function (context) {
536
+ var label = context.dataset.label || '';
565
537
  if (label) {
566
538
  label += ': ';
567
539
  }
568
- var dataPoint = data.datasets[item.datasetIndex].data[item.index];
569
- return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')';
540
+ var dataPoint = context.raw;
541
+ return label + '(' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.v + ')';
570
542
  };
571
543
  } else if (chartType === "pie") {
572
544
  // need to use separate label for pie charts
573
- options.tooltips.callbacks.label = function (tooltipItem, data) {
574
- var dataLabel = data.labels[tooltipItem.index];
545
+ options.plugins.tooltip.callbacks.label = function (context) {
546
+ var dataLabel = context.label;
575
547
  var value = ': ';
576
548
 
577
549
  if (isArray(dataLabel)) {
@@ -583,24 +555,29 @@
583
555
  dataLabel += value;
584
556
  }
585
557
 
586
- return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
558
+ return formatValue(dataLabel, context.parsed, formatOptions);
587
559
  };
588
560
  } else {
589
- var valueLabel = chartType === "bar" ? "xLabel" : "yLabel";
590
- options.tooltips.callbacks.label = function (tooltipItem, data) {
591
- var label = data.datasets[tooltipItem.datasetIndex].label || '';
561
+ var valueLabel = chartType === "bar" ? "x" : "y";
562
+ options.plugins.tooltip.callbacks.label = function (context) {
563
+ // don't show null values for stacked charts
564
+ if (context.parsed[valueLabel] === null) {
565
+ return;
566
+ }
567
+
568
+ var label = context.dataset.label || '';
592
569
  if (label) {
593
570
  label += ': ';
594
571
  }
595
- return formatValue(label, tooltipItem[valueLabel], formatOptions);
572
+ return formatValue(label, context.parsed[valueLabel], formatOptions);
596
573
  };
597
574
  }
598
575
  }
599
576
  };
600
577
 
601
- var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
578
+ var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
602
579
 
603
- var createDataTable = function (chart, options, chartType, library) {
580
+ var createDataTable = function (chart, options, chartType) {
604
581
  var datasets = [];
605
582
  var labels = [];
606
583
 
@@ -702,11 +679,23 @@
702
679
  }
703
680
  }
704
681
 
682
+ var color;
683
+ var backgroundColor;
684
+
705
685
  for (i = 0; i < series.length; i++) {
706
686
  s = series[i];
707
687
 
708
- var color = s.color || colors[i];
709
- var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
688
+ // use colors for each bar for single series format
689
+ if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
690
+ color = colors;
691
+ backgroundColor = [];
692
+ for (var j$3 = 0; j$3 < colors.length; j$3++) {
693
+ backgroundColor[j$3] = addOpacity(color[j$3], 0.5);
694
+ }
695
+ } else {
696
+ color = s.color || colors[i];
697
+ backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
698
+ }
710
699
 
711
700
  var dataset = {
712
701
  label: s.name || "",
@@ -714,24 +703,37 @@
714
703
  fill: chartType === "area",
715
704
  borderColor: color,
716
705
  backgroundColor: backgroundColor,
717
- pointBackgroundColor: color,
718
- borderWidth: 2,
719
- pointHoverBackgroundColor: color
706
+ borderWidth: 2
720
707
  };
721
708
 
709
+ var pointChart = chartType === "line" || chartType === "area" || chartType === "scatter" || chartType === "bubble";
710
+ if (pointChart) {
711
+ dataset.pointBackgroundColor = color;
712
+ dataset.pointHoverBackgroundColor = color;
713
+ dataset.pointHitRadius = 50;
714
+ }
715
+
716
+ if (chartType === "bubble") {
717
+ dataset.pointBackgroundColor = backgroundColor;
718
+ dataset.pointHoverBackgroundColor = backgroundColor;
719
+ dataset.pointHoverBorderWidth = 2;
720
+ }
721
+
722
722
  if (s.stack) {
723
723
  dataset.stack = s.stack;
724
724
  }
725
725
 
726
726
  var curve = seriesOption(chart, s, "curve");
727
727
  if (curve === false) {
728
- dataset.lineTension = 0;
728
+ dataset.tension = 0;
729
+ } else if (pointChart) {
730
+ dataset.tension = 0.4;
729
731
  }
730
732
 
731
733
  var points = seriesOption(chart, s, "points");
732
734
  if (points === false) {
733
735
  dataset.pointRadius = 0;
734
- dataset.pointHitRadius = 5;
736
+ dataset.pointHoverRadius = 0;
735
737
  }
736
738
 
737
739
  dataset = merge(dataset, chart.options.dataset || {});
@@ -745,22 +747,18 @@
745
747
  var xmax = chart.options.xmax;
746
748
 
747
749
  if (chart.xtype === "datetime") {
748
- // hacky check for Chart.js >= 2.9.0
749
- // https://github.com/chartjs/Chart.js/compare/v2.8.0...v2.9.0
750
- var gte29 = "math" in library.helpers;
751
- var ticksKey = gte29 ? "ticks" : "time";
752
750
  if (notnull(xmin)) {
753
- options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime();
751
+ options.scales.x.ticks.min = toDate(xmin).getTime();
754
752
  }
755
753
  if (notnull(xmax)) {
756
- options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime();
754
+ options.scales.x.ticks.max = toDate(xmax).getTime();
757
755
  }
758
756
  } else if (chart.xtype === "number") {
759
757
  if (notnull(xmin)) {
760
- options.scales.xAxes[0].ticks.min = xmin;
758
+ options.scales.x.ticks.min = xmin;
761
759
  }
762
760
  if (notnull(xmax)) {
763
- options.scales.xAxes[0].ticks.max = xmax;
761
+ options.scales.x.ticks.max = xmax;
764
762
  }
765
763
  }
766
764
 
@@ -796,24 +794,24 @@
796
794
 
797
795
  var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
798
796
 
799
- if (!options.scales.xAxes[0].time.unit) {
797
+ if (!options.scales.x.time.unit) {
800
798
  var step;
801
799
  if (year || timeDiff > 365 * 10) {
802
- options.scales.xAxes[0].time.unit = "year";
800
+ options.scales.x.time.unit = "year";
803
801
  step = 365;
804
802
  } else if (month || timeDiff > 30 * 10) {
805
- options.scales.xAxes[0].time.unit = "month";
803
+ options.scales.x.time.unit = "month";
806
804
  step = 30;
807
805
  } else if (day || timeDiff > 10) {
808
- options.scales.xAxes[0].time.unit = "day";
806
+ options.scales.x.time.unit = "day";
809
807
  step = 1;
810
808
  } else if (hour || timeDiff > 0.5) {
811
- options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"};
812
- options.scales.xAxes[0].time.unit = "hour";
809
+ options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
810
+ options.scales.x.time.unit = "hour";
813
811
  step = 1 / 24.0;
814
812
  } else if (minute) {
815
- options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"};
816
- options.scales.xAxes[0].time.unit = "minute";
813
+ options.scales.x.time.displayFormats = {minute: "h:mm a"};
814
+ options.scales.x.time.unit = "minute";
817
815
  step = 1 / 24.0 / 60.0;
818
816
  }
819
817
 
@@ -822,17 +820,17 @@
822
820
  if (week && step === 1) {
823
821
  unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
824
822
  }
825
- options.scales.xAxes[0].time.unitStepSize = unitStepSize;
823
+ options.scales.x.time.stepSize = unitStepSize;
826
824
  }
827
825
  }
828
826
 
829
- if (!options.scales.xAxes[0].time.tooltipFormat) {
827
+ if (!options.scales.x.time.tooltipFormat) {
830
828
  if (day) {
831
- options.scales.xAxes[0].time.tooltipFormat = "ll";
829
+ options.scales.x.time.tooltipFormat = "PP";
832
830
  } else if (hour) {
833
- options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
831
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
834
832
  } else if (minute) {
835
- options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
833
+ options.scales.x.time.tooltipFormat = "h:mm a";
836
834
  }
837
835
  }
838
836
  }
@@ -845,49 +843,49 @@
845
843
  return data;
846
844
  };
847
845
 
848
- var defaultExport = function defaultExport(library) {
846
+ var defaultExport$2 = function defaultExport(library) {
849
847
  this.name = "chartjs";
850
848
  this.library = library;
851
849
  };
852
850
 
853
- defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) {
851
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
854
852
  var chartOptions = {};
855
853
  // fix for https://github.com/chartjs/Chart.js/issues/2441
856
854
  if (!chart.options.max && allZeros(chart.data)) {
857
855
  chartOptions.max = 1;
858
856
  }
859
857
 
860
- var options = jsOptions(chart, merge(chartOptions, chart.options));
861
- setFormatOptions(chart, options, chartType);
858
+ var options = jsOptions$2(chart, merge(chartOptions, chart.options));
859
+ setFormatOptions$1(chart, options, chartType);
862
860
 
863
- var data = createDataTable(chart, options, chartType || "line", this.library);
861
+ var data = createDataTable(chart, options, chartType || "line");
864
862
 
865
863
  if (chart.xtype === "number") {
866
- options.scales.xAxes[0].type = "linear";
867
- options.scales.xAxes[0].position = "bottom";
864
+ options.scales.x.type = "linear";
865
+ options.scales.x.position = "bottom";
868
866
  } else {
869
- options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
867
+ options.scales.x.type = chart.xtype === "string" ? "category" : "time";
870
868
  }
871
869
 
872
870
  this.drawChart(chart, "line", data, options);
873
871
  };
874
872
 
875
- defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
873
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
876
874
  var options = merge({}, baseOptions);
877
875
  if (chart.options.donut) {
878
- options.cutoutPercentage = 50;
876
+ options.cutout = "50%";
879
877
  }
880
878
 
881
879
  if ("legend" in chart.options) {
882
- hideLegend(options, chart.options.legend);
880
+ hideLegend$2(options, chart.options.legend);
883
881
  }
884
882
 
885
883
  if (chart.options.title) {
886
- setTitle(options, chart.options.title);
884
+ setTitle$2(options, chart.options.title);
887
885
  }
888
886
 
889
887
  options = merge(options, chart.options.library || {});
890
- setFormatOptions(chart, options, "pie");
888
+ setFormatOptions$1(chart, options, "pie");
891
889
 
892
890
  var labels = [];
893
891
  var values = [];
@@ -911,61 +909,73 @@
911
909
  this.drawChart(chart, "pie", data, options);
912
910
  };
913
911
 
914
- defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
912
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
913
  var options;
916
914
  if (chartType === "bar") {
917
- var barOptions = merge(baseOptions, defaultOptions);
918
- delete barOptions.scales.yAxes[0].ticks.maxTicksLimit;
919
- options = jsOptionsFunc(barOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
915
+ var barOptions = merge(baseOptions, defaultOptions$2);
916
+ barOptions.indexAxis = "y";
917
+
918
+ // ensure gridlines have proper orientation
919
+ barOptions.scales.x.grid.drawOnChartArea = true;
920
+ barOptions.scales.y.grid.drawOnChartArea = false;
921
+ delete barOptions.scales.y.ticks.maxTicksLimit;
922
+
923
+ options = jsOptionsFunc(barOptions, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options);
920
924
  } else {
921
- options = jsOptions(chart, chart.options);
925
+ options = jsOptions$2(chart, chart.options);
922
926
  }
923
- setFormatOptions(chart, options, chartType);
924
- var data = createDataTable(chart, options, "column", this.library);
927
+ setFormatOptions$1(chart, options, chartType);
928
+ var data = createDataTable(chart, options, "column");
925
929
  if (chartType !== "bar") {
926
930
  setLabelSize(chart, data, options);
927
931
  }
928
- this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
932
+ this.drawChart(chart, "bar", data, options);
929
933
  };
930
934
 
931
- defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
935
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
932
936
  this.renderLineChart(chart, "area");
933
937
  };
934
938
 
935
- defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
939
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
936
940
  this.renderColumnChart(chart, "bar");
937
941
  };
938
942
 
939
- defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
943
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
944
  chartType = chartType || "scatter";
941
945
 
942
- var options = jsOptions(chart, chart.options);
943
- setFormatOptions(chart, options, chartType);
946
+ var options = jsOptions$2(chart, chart.options);
947
+ setFormatOptions$1(chart, options, chartType);
944
948
 
945
- if (!("showLines" in options)) {
946
- options.showLines = false;
949
+ if (!("showLine" in options)) {
950
+ options.showLine = false;
947
951
  }
948
952
 
949
- var data = createDataTable(chart, options, chartType, this.library);
953
+ var data = createDataTable(chart, options, chartType);
950
954
 
951
- options.scales.xAxes[0].type = "linear";
952
- options.scales.xAxes[0].position = "bottom";
955
+ options.scales.x.type = "linear";
956
+ options.scales.x.position = "bottom";
957
+
958
+ // prevent grouping hover and tooltips
959
+ if (!("mode" in options.interaction)) {
960
+ options.interaction.mode = "nearest";
961
+ }
953
962
 
954
963
  this.drawChart(chart, chartType, data, options);
955
964
  };
956
965
 
957
- defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
966
+ defaultExport$2.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
967
  this.renderScatterChart(chart, "bubble");
959
968
  };
960
969
 
961
- defaultExport.prototype.destroy = function destroy (chart) {
970
+ defaultExport$2.prototype.destroy = function destroy (chart) {
962
971
  if (chart.chart) {
963
972
  chart.chart.destroy();
964
973
  }
965
974
  };
966
975
 
967
- defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
976
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
968
977
  this.destroy(chart);
978
+ if (chart.destroyed) { return; }
969
979
 
970
980
  var chartOptions = {
971
981
  type: type,
@@ -1024,6 +1034,9 @@
1024
1034
  series: {
1025
1035
  marker: {}
1026
1036
  }
1037
+ },
1038
+ time: {
1039
+ useUTC: false
1027
1040
  }
1028
1041
  };
1029
1042
 
@@ -1073,7 +1086,7 @@
1073
1086
 
1074
1087
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
1088
 
1076
- var setFormatOptions$1 = function(chart, options, chartType) {
1089
+ var setFormatOptions = function(chart, options, chartType) {
1077
1090
  var formatOptions = {
1078
1091
  prefix: chart.options.prefix,
1079
1092
  suffix: chart.options.suffix,
@@ -1136,7 +1149,7 @@
1136
1149
  if (!options.chart.type) {
1137
1150
  options.chart.type = chartType;
1138
1151
  }
1139
- setFormatOptions$1(chart, options, chartType);
1152
+ setFormatOptions(chart, options, chartType);
1140
1153
 
1141
1154
  var series = chart.data;
1142
1155
  for (i = 0; i < series.length; i++) {
@@ -1181,7 +1194,7 @@
1181
1194
  }
1182
1195
 
1183
1196
  var options = merge(chartOptions, chart.options.library || {});
1184
- setFormatOptions$1(chart, options, "pie");
1197
+ setFormatOptions(chart, options, "pie");
1185
1198
  var series = [{
1186
1199
  type: "pie",
1187
1200
  name: chart.options.label || "Value",
@@ -1196,7 +1209,7 @@
1196
1209
  var series = chart.data;
1197
1210
  var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1198
1211
  options.chart.type = chartType;
1199
- setFormatOptions$1(chart, options, chartType);
1212
+ setFormatOptions(chart, options, chartType);
1200
1213
 
1201
1214
  for (i = 0; i < series.length; i++) {
1202
1215
  s = series[i];
@@ -1254,6 +1267,7 @@
1254
1267
 
1255
1268
  defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
1269
  this.destroy(chart);
1270
+ if (chart.destroyed) { return; }
1257
1271
 
1258
1272
  options.chart.renderTo = chart.element.id;
1259
1273
  options.series = data;
@@ -1269,7 +1283,7 @@
1269
1283
  var callbacks = [];
1270
1284
 
1271
1285
  // Set chart options
1272
- var defaultOptions$2 = {
1286
+ var defaultOptions = {
1273
1287
  chartArea: {},
1274
1288
  fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
1289
  pointSize: 6,
@@ -1311,7 +1325,7 @@
1311
1325
  }
1312
1326
  };
1313
1327
 
1314
- var hideLegend$2 = function (options, legend, hideLegend) {
1328
+ var hideLegend = function (options, legend, hideLegend) {
1315
1329
  if (legend !== undefined) {
1316
1330
  var position;
1317
1331
  if (!legend) {
@@ -1327,42 +1341,42 @@
1327
1341
  }
1328
1342
  };
1329
1343
 
1330
- var setTitle$2 = function (options, title) {
1344
+ var setTitle = function (options, title) {
1331
1345
  options.title = title;
1332
1346
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
1347
  };
1334
1348
 
1335
- var setMin$2 = function (options, min) {
1349
+ var setMin = function (options, min) {
1336
1350
  options.vAxis.viewWindow.min = min;
1337
1351
  };
1338
1352
 
1339
- var setMax$2 = function (options, max) {
1353
+ var setMax = function (options, max) {
1340
1354
  options.vAxis.viewWindow.max = max;
1341
1355
  };
1342
1356
 
1343
- var setBarMin$1 = function (options, min) {
1357
+ var setBarMin = function (options, min) {
1344
1358
  options.hAxis.viewWindow.min = min;
1345
1359
  };
1346
1360
 
1347
- var setBarMax$1 = function (options, max) {
1361
+ var setBarMax = function (options, max) {
1348
1362
  options.hAxis.viewWindow.max = max;
1349
1363
  };
1350
1364
 
1351
- var setStacked$2 = function (options, stacked) {
1365
+ var setStacked = function (options, stacked) {
1352
1366
  options.isStacked = stacked ? stacked : false;
1353
1367
  };
1354
1368
 
1355
- var setXtitle$2 = function (options, title) {
1369
+ var setXtitle = function (options, title) {
1356
1370
  options.hAxis.title = title;
1357
1371
  options.hAxis.titleTextStyle.italic = false;
1358
1372
  };
1359
1373
 
1360
- var setYtitle$2 = function (options, title) {
1374
+ var setYtitle = function (options, title) {
1361
1375
  options.vAxis.title = title;
1362
1376
  options.vAxis.titleTextStyle.italic = false;
1363
1377
  };
1364
1378
 
1365
- var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1379
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1366
1380
 
1367
1381
  var resize = function (callback) {
1368
1382
  if (window.attachEvent) {
@@ -1373,12 +1387,12 @@
1373
1387
  callback();
1374
1388
  };
1375
1389
 
1376
- var defaultExport$2 = function defaultExport(library) {
1390
+ var defaultExport = function defaultExport(library) {
1377
1391
  this.name = "google";
1378
1392
  this.library = library;
1379
1393
  };
1380
1394
 
1381
- defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1395
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart) {
1382
1396
  var this$1 = this;
1383
1397
 
1384
1398
  this.waitForLoaded(chart, function () {
@@ -1392,14 +1406,14 @@
1392
1406
  chartOptions.pointSize = 0;
1393
1407
  }
1394
1408
 
1395
- var options = jsOptions$2(chart, chart.options, chartOptions);
1409
+ var options = jsOptions(chart, chart.options, chartOptions);
1396
1410
  var data = this$1.createDataTable(chart.data, chart.xtype);
1397
1411
 
1398
1412
  this$1.drawChart(chart, "LineChart", data, options);
1399
1413
  });
1400
1414
  };
1401
1415
 
1402
- defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1416
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
1403
1417
  var this$1 = this;
1404
1418
 
1405
1419
  this.waitForLoaded(chart, function () {
@@ -1417,12 +1431,12 @@
1417
1431
  chartOptions.pieHole = 0.5;
1418
1432
  }
1419
1433
  if ("legend" in chart.options) {
1420
- hideLegend$2(chartOptions, chart.options.legend);
1434
+ hideLegend(chartOptions, chart.options.legend);
1421
1435
  }
1422
1436
  if (chart.options.title) {
1423
- setTitle$2(chartOptions, chart.options.title);
1437
+ setTitle(chartOptions, chart.options.title);
1424
1438
  }
1425
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1439
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1426
1440
 
1427
1441
  var data = new this$1.library.visualization.DataTable();
1428
1442
  data.addColumn("string", "");
@@ -1433,18 +1447,18 @@
1433
1447
  });
1434
1448
  };
1435
1449
 
1436
- defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1450
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
1451
  var this$1 = this;
1438
1452
 
1439
1453
  this.waitForLoaded(chart, function () {
1440
- var options = jsOptions$2(chart, chart.options);
1454
+ var options = jsOptions(chart, chart.options);
1441
1455
  var data = this$1.createDataTable(chart.data, chart.xtype);
1442
1456
 
1443
1457
  this$1.drawChart(chart, "ColumnChart", data, options);
1444
1458
  });
1445
1459
  };
1446
1460
 
1447
- defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1461
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1448
1462
  var this$1 = this;
1449
1463
 
1450
1464
  this.waitForLoaded(chart, function () {
@@ -1455,14 +1469,14 @@
1455
1469
  }
1456
1470
  }
1457
1471
  };
1458
- var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions);
1472
+ var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
1459
1473
  var data = this$1.createDataTable(chart.data, chart.xtype);
1460
1474
 
1461
1475
  this$1.drawChart(chart, "BarChart", data, options);
1462
1476
  });
1463
1477
  };
1464
1478
 
1465
- defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1479
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
1480
  var this$1 = this;
1467
1481
 
1468
1482
  this.waitForLoaded(chart, function () {
@@ -1472,14 +1486,14 @@
1472
1486
  areaOpacity: 0.5
1473
1487
  };
1474
1488
 
1475
- var options = jsOptions$2(chart, chart.options, chartOptions);
1489
+ var options = jsOptions(chart, chart.options, chartOptions);
1476
1490
  var data = this$1.createDataTable(chart.data, chart.xtype);
1477
1491
 
1478
1492
  this$1.drawChart(chart, "AreaChart", data, options);
1479
1493
  });
1480
1494
  };
1481
1495
 
1482
- defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1496
+ defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
1497
  var this$1 = this;
1484
1498
 
1485
1499
  this.waitForLoaded(chart, "geochart", function () {
@@ -1489,7 +1503,7 @@
1489
1503
  colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
1504
  }
1491
1505
  };
1492
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1506
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1493
1507
 
1494
1508
  var data = new this$1.library.visualization.DataTable();
1495
1509
  data.addColumn("string", "");
@@ -1500,12 +1514,12 @@
1500
1514
  });
1501
1515
  };
1502
1516
 
1503
- defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1517
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
1518
  var this$1 = this;
1505
1519
 
1506
1520
  this.waitForLoaded(chart, function () {
1507
1521
  var chartOptions = {};
1508
- var options = jsOptions$2(chart, chart.options, chartOptions);
1522
+ var options = jsOptions(chart, chart.options, chartOptions);
1509
1523
 
1510
1524
  var series = chart.data, rows2 = [], i, j, data, d;
1511
1525
  for (i = 0; i < series.length; i++) {
@@ -1530,7 +1544,7 @@
1530
1544
  });
1531
1545
  };
1532
1546
 
1533
- defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1547
+ defaultExport.prototype.renderTimeline = function renderTimeline (chart) {
1534
1548
  var this$1 = this;
1535
1549
 
1536
1550
  this.waitForLoaded(chart, "timeline", function () {
@@ -1541,7 +1555,7 @@
1541
1555
  if (chart.options.colors) {
1542
1556
  chartOptions.colors = chart.options.colors;
1543
1557
  }
1544
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1558
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1545
1559
 
1546
1560
  var data = new this$1.library.visualization.DataTable();
1547
1561
  data.addColumn({type: "string", id: "Name"});
@@ -1555,14 +1569,16 @@
1555
1569
  });
1556
1570
  };
1557
1571
 
1558
- defaultExport$2.prototype.destroy = function destroy (chart) {
1572
+ // TODO remove resize events
1573
+ defaultExport.prototype.destroy = function destroy (chart) {
1559
1574
  if (chart.chart) {
1560
1575
  chart.chart.clearChart();
1561
1576
  }
1562
1577
  };
1563
1578
 
1564
- defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1579
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
1580
  this.destroy(chart);
1581
+ if (chart.destroyed) { return; }
1566
1582
 
1567
1583
  if (chart.options.code) {
1568
1584
  window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");");
@@ -1574,7 +1590,7 @@
1574
1590
  });
1575
1591
  };
1576
1592
 
1577
- defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1593
+ defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
1594
  var this$1 = this;
1579
1595
 
1580
1596
  if (!callback) {
@@ -1606,7 +1622,7 @@
1606
1622
  }
1607
1623
  };
1608
1624
 
1609
- defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1625
+ defaultExport.prototype.runCallbacks = function runCallbacks () {
1610
1626
  var cb, call;
1611
1627
  for (var i = 0; i < callbacks.length; i++) {
1612
1628
  cb = callbacks[i];
@@ -1620,7 +1636,7 @@
1620
1636
  };
1621
1637
 
1622
1638
  // cant use object as key
1623
- defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) {
1639
+ defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1624
1640
  var i, j, s, d, key, rows = [], sortedLabels = [];
1625
1641
  for (i = 0; i < series.length; i++) {
1626
1642
  s = series[i];
@@ -1676,6 +1692,202 @@
1676
1692
  return data;
1677
1693
  };
1678
1694
 
1695
+ function formatSeriesData(data, keyType) {
1696
+ var r = [], j, keyFunc;
1697
+
1698
+ if (keyType === "number") {
1699
+ keyFunc = toFloat;
1700
+ } else if (keyType === "datetime") {
1701
+ keyFunc = toDate;
1702
+ } else {
1703
+ keyFunc = toStr;
1704
+ }
1705
+
1706
+ if (keyType === "bubble") {
1707
+ for (j = 0; j < data.length; j++) {
1708
+ r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1709
+ }
1710
+ } else {
1711
+ for (j = 0; j < data.length; j++) {
1712
+ r.push([keyFunc(data[j][0]), toFloat(data[j][1])]);
1713
+ }
1714
+ }
1715
+
1716
+ if (keyType === "datetime") {
1717
+ r.sort(sortByTime);
1718
+ } else if (keyType === "number") {
1719
+ r.sort(sortByNumberSeries);
1720
+ }
1721
+
1722
+ return r;
1723
+ }
1724
+ function detectXType(series, noDatetime, options) {
1725
+ if (dataEmpty(series)) {
1726
+ if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1727
+ return "datetime";
1728
+ } else {
1729
+ return "number";
1730
+ }
1731
+ } else if (detectXTypeWithFunction(series, isNumber)) {
1732
+ return "number";
1733
+ } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1734
+ return "datetime";
1735
+ } else {
1736
+ return "string";
1737
+ }
1738
+ }
1739
+
1740
+ function detectXTypeWithFunction(series, func) {
1741
+ var i, j, data;
1742
+ for (i = 0; i < series.length; i++) {
1743
+ data = toArr(series[i].data);
1744
+ for (j = 0; j < data.length; j++) {
1745
+ if (!func(data[j][0])) {
1746
+ return false;
1747
+ }
1748
+ }
1749
+ }
1750
+ return true;
1751
+ }
1752
+
1753
+ // creates a shallow copy of each element of the array
1754
+ // elements are expected to be objects
1755
+ function copySeries(series) {
1756
+ var newSeries = [], i, j;
1757
+ for (i = 0; i < series.length; i++) {
1758
+ var copy = {};
1759
+ for (j in series[i]) {
1760
+ if (series[i].hasOwnProperty(j)) {
1761
+ copy[j] = series[i][j];
1762
+ }
1763
+ }
1764
+ newSeries.push(copy);
1765
+ }
1766
+ return newSeries;
1767
+ }
1768
+
1769
+ function processSeries(chart, keyType, noDatetime) {
1770
+ var i;
1771
+
1772
+ var opts = chart.options;
1773
+ var series = chart.rawData;
1774
+
1775
+ // see if one series or multiple
1776
+ chart.singleSeriesFormat = (!isArray(series) || typeof series[0] !== "object" || isArray(series[0]));
1777
+ if (chart.singleSeriesFormat) {
1778
+ series = [{name: opts.label, data: series}];
1779
+ }
1780
+
1781
+ // convert to array
1782
+ // must come before dataEmpty check
1783
+ series = copySeries(series);
1784
+ for (i = 0; i < series.length; i++) {
1785
+ series[i].data = toArr(series[i].data);
1786
+ }
1787
+
1788
+ chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1789
+
1790
+ // right format
1791
+ for (i = 0; i < series.length; i++) {
1792
+ series[i].data = formatSeriesData(series[i].data, chart.xtype);
1793
+ }
1794
+
1795
+ return series;
1796
+ }
1797
+
1798
+ function processSimple(chart) {
1799
+ var perfectData = toArr(chart.rawData), i;
1800
+ for (i = 0; i < perfectData.length; i++) {
1801
+ perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
1802
+ }
1803
+ return perfectData;
1804
+ }
1805
+
1806
+ function dataEmpty(data, chartType) {
1807
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1808
+ return data.length === 0;
1809
+ } else {
1810
+ for (var i = 0; i < data.length; i++) {
1811
+ if (data[i].data.length > 0) {
1812
+ return false;
1813
+ }
1814
+ }
1815
+ return true;
1816
+ }
1817
+ }
1818
+
1819
+ function addDownloadButton(chart) {
1820
+ var element = chart.element;
1821
+ var link = document.createElement("a");
1822
+
1823
+ var download = chart.options.download;
1824
+ if (download === true) {
1825
+ download = {};
1826
+ } else if (typeof download === "string") {
1827
+ download = {filename: download};
1828
+ }
1829
+ link.download = download.filename || "chart.png"; // https://caniuse.com/download
1830
+
1831
+ link.style.position = "absolute";
1832
+ link.style.top = "20px";
1833
+ link.style.right = "20px";
1834
+ link.style.zIndex = 1000;
1835
+ link.style.lineHeight = "20px";
1836
+ link.target = "_blank"; // for safari
1837
+ var image = document.createElement("img");
1838
+ image.alt = "Download";
1839
+ image.style.border = "none";
1840
+ // icon from font-awesome
1841
+ // http://fa2png.io/
1842
+ image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1843
+ link.appendChild(image);
1844
+ element.style.position = "relative";
1845
+
1846
+ chart.__downloadAttached = true;
1847
+
1848
+ // mouseenter
1849
+ chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1850
+ var related = e.relatedTarget;
1851
+ // check download option again to ensure it wasn't changed
1852
+ if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1853
+ link.href = chart.toImage(download);
1854
+ element.appendChild(link);
1855
+ }
1856
+ });
1857
+
1858
+ // mouseleave
1859
+ chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1860
+ var related = e.relatedTarget;
1861
+ if (!related || (related !== this && !childOf(this, related))) {
1862
+ if (link.parentNode) {
1863
+ link.parentNode.removeChild(link);
1864
+ }
1865
+ }
1866
+ });
1867
+ }
1868
+
1869
+ // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1870
+ function addEvent(elem, event, fn) {
1871
+ if (elem.addEventListener) {
1872
+ elem.addEventListener(event, fn, false);
1873
+ return fn;
1874
+ } else {
1875
+ var fn2 = function() {
1876
+ // set the this pointer same as addEventListener when fn is called
1877
+ return(fn.call(elem, window.event));
1878
+ };
1879
+ elem.attachEvent("on" + event, fn2);
1880
+ return fn2;
1881
+ }
1882
+ }
1883
+
1884
+ // https://gist.github.com/shawnbot/4166283
1885
+ function childOf(p, c) {
1886
+ if (p === c) { return false; }
1887
+ while (c && c !== p) { c = c.parentNode; }
1888
+ return c === p;
1889
+ }
1890
+
1679
1891
  var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1680
1892
 
1681
1893
  function pushRequest(url, success, error) {
@@ -1764,7 +1976,12 @@
1764
1976
  }
1765
1977
  }
1766
1978
 
1767
- function fetchDataSource(chart, dataSource) {
1979
+ function fetchDataSource(chart, dataSource, showLoading) {
1980
+ // only show loading message for urls and callbacks
1981
+ if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
1982
+ setText(chart.element, chart.options.loading);
1983
+ }
1984
+
1768
1985
  if (typeof dataSource === "string") {
1769
1986
  pushRequest(dataSource, function (data) {
1770
1987
  chart.rawData = data;
@@ -1789,94 +2006,14 @@
1789
2006
  }
1790
2007
  }
1791
2008
 
1792
- function addDownloadButton(chart) {
1793
- var element = chart.element;
1794
- var link = document.createElement("a");
1795
-
1796
- var download = chart.options.download;
1797
- if (download === true) {
1798
- download = {};
1799
- } else if (typeof download === "string") {
1800
- download = {filename: download};
1801
- }
1802
- link.download = download.filename || "chart.png"; // https://caniuse.com/download
1803
-
1804
- link.style.position = "absolute";
1805
- link.style.top = "20px";
1806
- link.style.right = "20px";
1807
- link.style.zIndex = 1000;
1808
- link.style.lineHeight = "20px";
1809
- link.target = "_blank"; // for safari
1810
- var image = document.createElement("img");
1811
- image.alt = "Download";
1812
- image.style.border = "none";
1813
- // icon from font-awesome
1814
- // http://fa2png.io/
1815
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1816
- link.appendChild(image);
1817
- element.style.position = "relative";
1818
-
1819
- chart.__downloadAttached = true;
1820
-
1821
- // mouseenter
1822
- chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1823
- var related = e.relatedTarget;
1824
- // check download option again to ensure it wasn't changed
1825
- if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1826
- link.href = chart.toImage(download);
1827
- element.appendChild(link);
1828
- }
1829
- });
1830
-
1831
- // mouseleave
1832
- chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1833
- var related = e.relatedTarget;
1834
- if (!related || (related !== this && !childOf(this, related))) {
1835
- if (link.parentNode) {
1836
- link.parentNode.removeChild(link);
1837
- }
1838
- }
1839
- });
1840
- }
1841
-
1842
- // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1843
- function addEvent(elem, event, fn) {
1844
- if (elem.addEventListener) {
1845
- elem.addEventListener(event, fn, false);
1846
- return fn;
1847
- } else {
1848
- var fn2 = function() {
1849
- // set the this pointer same as addEventListener when fn is called
1850
- return(fn.call(elem, window.event));
1851
- };
1852
- elem.attachEvent("on" + event, fn2);
1853
- return fn2;
1854
- }
1855
- }
1856
-
1857
- function removeEvent(elem, event, fn) {
1858
- if (elem.removeEventListener) {
1859
- elem.removeEventListener(event, fn, false);
1860
- } else {
1861
- elem.detachEvent("on" + event, fn);
1862
- }
1863
- }
1864
-
1865
- // https://gist.github.com/shawnbot/4166283
1866
- function childOf(p, c) {
1867
- if (p === c) { return false; }
1868
- while (c && c !== p) { c = c.parentNode; }
1869
- return c === p;
1870
- }
1871
-
1872
2009
  function getAdapterType(library) {
1873
2010
  if (library) {
1874
2011
  if (library.product === "Highcharts") {
1875
2012
  return defaultExport$1;
1876
2013
  } else if (library.charts) {
1877
- return defaultExport$2;
1878
- } else if (isFunction(library)) {
1879
2014
  return defaultExport;
2015
+ } else if (isFunction(library)) {
2016
+ return defaultExport$2;
1880
2017
  }
1881
2018
  }
1882
2019
  throw new Error("Unknown adapter");
@@ -1905,22 +2042,10 @@
1905
2042
  }
1906
2043
  }
1907
2044
 
1908
- function dataEmpty(data, chartType) {
1909
- if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1910
- return data.length === 0;
1911
- } else {
1912
- for (var i = 0; i < data.length; i++) {
1913
- if (data[i].data.length > 0) {
1914
- return false;
1915
- }
1916
- }
1917
- return true;
1918
- }
1919
- }
1920
-
1921
2045
  function renderChart(chartType, chart) {
1922
- if (chart.options.messages && chart.options.messages.empty && dataEmpty(chart.data, chartType)) {
1923
- setText(chart.element, chart.options.messages.empty);
2046
+ if (dataEmpty(chart.data, chartType)) {
2047
+ var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2048
+ setText(chart.element, message);
1924
2049
  } else {
1925
2050
  callAdapter(chartType, chart);
1926
2051
  if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
@@ -1954,121 +2079,6 @@
1954
2079
  }
1955
2080
  }
1956
2081
 
1957
- // process data
1958
-
1959
- var toFormattedKey = function (key, keyType) {
1960
- if (keyType === "number") {
1961
- key = toFloat(key);
1962
- } else if (keyType === "datetime") {
1963
- key = toDate(key);
1964
- } else {
1965
- key = toStr(key);
1966
- }
1967
- return key;
1968
- };
1969
-
1970
- var formatSeriesData = function (data, keyType) {
1971
- var r = [], key, j;
1972
- for (j = 0; j < data.length; j++) {
1973
- if (keyType === "bubble") {
1974
- r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1975
- } else {
1976
- key = toFormattedKey(data[j][0], keyType);
1977
- r.push([key, toFloat(data[j][1])]);
1978
- }
1979
- }
1980
- if (keyType === "datetime") {
1981
- r.sort(sortByTime);
1982
- } else if (keyType === "number") {
1983
- r.sort(sortByNumberSeries);
1984
- }
1985
- return r;
1986
- };
1987
-
1988
- function detectXType(series, noDatetime, options) {
1989
- if (dataEmpty(series)) {
1990
- if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1991
- return "datetime";
1992
- } else {
1993
- return "number";
1994
- }
1995
- } else if (detectXTypeWithFunction(series, isNumber)) {
1996
- return "number";
1997
- } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1998
- return "datetime";
1999
- } else {
2000
- return "string";
2001
- }
2002
- }
2003
-
2004
- function detectXTypeWithFunction(series, func) {
2005
- var i, j, data;
2006
- for (i = 0; i < series.length; i++) {
2007
- data = toArr(series[i].data);
2008
- for (j = 0; j < data.length; j++) {
2009
- if (!func(data[j][0])) {
2010
- return false;
2011
- }
2012
- }
2013
- }
2014
- return true;
2015
- }
2016
-
2017
- // creates a shallow copy of each element of the array
2018
- // elements are expected to be objects
2019
- function copySeries(series) {
2020
- var newSeries = [], i, j;
2021
- for (i = 0; i < series.length; i++) {
2022
- var copy = {};
2023
- for (j in series[i]) {
2024
- if (series[i].hasOwnProperty(j)) {
2025
- copy[j] = series[i][j];
2026
- }
2027
- }
2028
- newSeries.push(copy);
2029
- }
2030
- return newSeries;
2031
- }
2032
-
2033
- function processSeries(chart, keyType, noDatetime) {
2034
- var i;
2035
-
2036
- var opts = chart.options;
2037
- var series = chart.rawData;
2038
-
2039
- // see if one series or multiple
2040
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
2041
- series = [{name: opts.label, data: series}];
2042
- chart.hideLegend = true;
2043
- } else {
2044
- chart.hideLegend = false;
2045
- }
2046
-
2047
- // convert to array
2048
- // must come before dataEmpty check
2049
- series = copySeries(series);
2050
- for (i = 0; i < series.length; i++) {
2051
- series[i].data = toArr(series[i].data);
2052
- }
2053
-
2054
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2055
-
2056
- // right format
2057
- for (i = 0; i < series.length; i++) {
2058
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
2059
- }
2060
-
2061
- return series;
2062
- }
2063
-
2064
- function processSimple(chart) {
2065
- var perfectData = toArr(chart.rawData), i;
2066
- for (i = 0; i < perfectData.length; i++) {
2067
- perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
2068
- }
2069
- return perfectData;
2070
- }
2071
-
2072
2082
  // define classes
2073
2083
 
2074
2084
  var Chart = function Chart(element, dataSource, options) {
@@ -2086,7 +2096,7 @@
2086
2096
 
2087
2097
  Chartkick.charts[element.id] = this;
2088
2098
 
2089
- fetchDataSource(this, dataSource);
2099
+ fetchDataSource(this, dataSource, true);
2090
2100
 
2091
2101
  if (this.options.refresh) {
2092
2102
  this.startRefresh();
@@ -2122,7 +2132,7 @@
2122
2132
  if (options) {
2123
2133
  this.__updateOptions(options);
2124
2134
  }
2125
- fetchDataSource(this, dataSource);
2135
+ fetchDataSource(this, dataSource, true);
2126
2136
  };
2127
2137
 
2128
2138
  Chart.prototype.setOptions = function setOptions (options) {
@@ -2176,8 +2186,8 @@
2176
2186
  if (this.adapter === "chartjs") {
2177
2187
  if (download && download.background && download.background !== "transparent") {
2178
2188
  // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2179
- var canvas = this.chart.chart.canvas;
2180
- var ctx = this.chart.chart.ctx;
2189
+ var canvas = this.chart.canvas;
2190
+ var ctx = this.chart.ctx;
2181
2191
  var tmpCanvas = document.createElement("canvas");
2182
2192
  var tmpCtx = tmpCanvas.getContext("2d");
2183
2193
  tmpCanvas.width = ctx.canvas.width;
@@ -2190,13 +2200,14 @@
2190
2200
  return this.chart.toBase64Image();
2191
2201
  }
2192
2202
  } else {
2193
- // TODO throw error in next major version
2194
- // throw new Error("Feature only available for Chart.js");
2195
- return null;
2203
+ throw new Error("Feature only available for Chart.js");
2196
2204
  }
2197
2205
  };
2198
2206
 
2199
2207
  Chart.prototype.destroy = function destroy () {
2208
+ this.destroyed = true;
2209
+ this.stopRefresh();
2210
+
2200
2211
  if (this.__adapterObject) {
2201
2212
  this.__adapterObject.destroy(this);
2202
2213
  }
@@ -2441,6 +2452,14 @@
2441
2452
  }
2442
2453
  }
2443
2454
  },
2455
+ destroyAll: function() {
2456
+ for (var chartId in Chartkick.charts) {
2457
+ if (Chartkick.charts.hasOwnProperty(chartId)) {
2458
+ Chartkick.charts[chartId].destroy();
2459
+ delete Chartkick.charts[chartId];
2460
+ }
2461
+ }
2462
+ },
2444
2463
  config: config,
2445
2464
  options: {},
2446
2465
  adapters: adapters,
@@ -2454,6 +2473,16 @@
2454
2473
  // not ideal, but allows for simpler integration
2455
2474
  if (typeof window !== "undefined" && !window.Chartkick) {
2456
2475
  window.Chartkick = Chartkick;
2476
+
2477
+ // clean up previous charts before Turbolinks loads new page
2478
+ document.addEventListener("turbolinks:before-render", function() {
2479
+ Chartkick.destroyAll();
2480
+ });
2481
+
2482
+ // use setTimeout so charting library can come later in same JS file
2483
+ setTimeout(function() {
2484
+ window.dispatchEvent(new Event("chartkick:load"));
2485
+ }, 0);
2457
2486
  }
2458
2487
 
2459
2488
  // backwards compatibility for esm require