chartkick 4.0.2 → 4.0.3

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.
@@ -2,7 +2,7 @@
2
2
  * Chartkick.js
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v4.0.2
5
+ * v4.0.3
6
6
  * MIT License
7
7
  */
8
8
 
@@ -560,6 +560,11 @@
560
560
  } else {
561
561
  var valueLabel = chartType === "bar" ? "x" : "y";
562
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
+
563
568
  var label = context.dataset.label || '';
564
569
  if (label) {
565
570
  label += ': ';
@@ -681,7 +686,7 @@
681
686
  s = series[i];
682
687
 
683
688
  // use colors for each bar for single series format
684
- if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color) {
689
+ if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
685
690
  color = colors;
686
691
  backgroundColor = [];
687
692
  for (var j$3 = 0; j$3 < colors.length; j$3++) {
@@ -1687,6 +1692,202 @@
1687
1692
  return data;
1688
1693
  };
1689
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
+
1690
1891
  var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1691
1892
 
1692
1893
  function pushRequest(url, success, error) {
@@ -1805,86 +2006,6 @@
1805
2006
  }
1806
2007
  }
1807
2008
 
1808
- function addDownloadButton(chart) {
1809
- var element = chart.element;
1810
- var link = document.createElement("a");
1811
-
1812
- var download = chart.options.download;
1813
- if (download === true) {
1814
- download = {};
1815
- } else if (typeof download === "string") {
1816
- download = {filename: download};
1817
- }
1818
- link.download = download.filename || "chart.png"; // https://caniuse.com/download
1819
-
1820
- link.style.position = "absolute";
1821
- link.style.top = "20px";
1822
- link.style.right = "20px";
1823
- link.style.zIndex = 1000;
1824
- link.style.lineHeight = "20px";
1825
- link.target = "_blank"; // for safari
1826
- var image = document.createElement("img");
1827
- image.alt = "Download";
1828
- image.style.border = "none";
1829
- // icon from font-awesome
1830
- // http://fa2png.io/
1831
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1832
- link.appendChild(image);
1833
- element.style.position = "relative";
1834
-
1835
- chart.__downloadAttached = true;
1836
-
1837
- // mouseenter
1838
- chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1839
- var related = e.relatedTarget;
1840
- // check download option again to ensure it wasn't changed
1841
- if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1842
- link.href = chart.toImage(download);
1843
- element.appendChild(link);
1844
- }
1845
- });
1846
-
1847
- // mouseleave
1848
- chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1849
- var related = e.relatedTarget;
1850
- if (!related || (related !== this && !childOf(this, related))) {
1851
- if (link.parentNode) {
1852
- link.parentNode.removeChild(link);
1853
- }
1854
- }
1855
- });
1856
- }
1857
-
1858
- // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1859
- function addEvent(elem, event, fn) {
1860
- if (elem.addEventListener) {
1861
- elem.addEventListener(event, fn, false);
1862
- return fn;
1863
- } else {
1864
- var fn2 = function() {
1865
- // set the this pointer same as addEventListener when fn is called
1866
- return(fn.call(elem, window.event));
1867
- };
1868
- elem.attachEvent("on" + event, fn2);
1869
- return fn2;
1870
- }
1871
- }
1872
-
1873
- function removeEvent(elem, event, fn) {
1874
- if (elem.removeEventListener) {
1875
- elem.removeEventListener(event, fn, false);
1876
- } else {
1877
- elem.detachEvent("on" + event, fn);
1878
- }
1879
- }
1880
-
1881
- // https://gist.github.com/shawnbot/4166283
1882
- function childOf(p, c) {
1883
- if (p === c) { return false; }
1884
- while (c && c !== p) { c = c.parentNode; }
1885
- return c === p;
1886
- }
1887
-
1888
2009
  function getAdapterType(library) {
1889
2010
  if (library) {
1890
2011
  if (library.product === "Highcharts") {
@@ -1921,19 +2042,6 @@
1921
2042
  }
1922
2043
  }
1923
2044
 
1924
- function dataEmpty(data, chartType) {
1925
- if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1926
- return data.length === 0;
1927
- } else {
1928
- for (var i = 0; i < data.length; i++) {
1929
- if (data[i].data.length > 0) {
1930
- return false;
1931
- }
1932
- }
1933
- return true;
1934
- }
1935
- }
1936
-
1937
2045
  function renderChart(chartType, chart) {
1938
2046
  if (dataEmpty(chart.data, chartType)) {
1939
2047
  var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
@@ -1971,121 +2079,6 @@
1971
2079
  }
1972
2080
  }
1973
2081
 
1974
- // process data
1975
-
1976
- var toFormattedKey = function (key, keyType) {
1977
- if (keyType === "number") {
1978
- key = toFloat(key);
1979
- } else if (keyType === "datetime") {
1980
- key = toDate(key);
1981
- } else {
1982
- key = toStr(key);
1983
- }
1984
- return key;
1985
- };
1986
-
1987
- var formatSeriesData = function (data, keyType) {
1988
- var r = [], key, j;
1989
- for (j = 0; j < data.length; j++) {
1990
- if (keyType === "bubble") {
1991
- r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1992
- } else {
1993
- key = toFormattedKey(data[j][0], keyType);
1994
- r.push([key, toFloat(data[j][1])]);
1995
- }
1996
- }
1997
- if (keyType === "datetime") {
1998
- r.sort(sortByTime);
1999
- } else if (keyType === "number") {
2000
- r.sort(sortByNumberSeries);
2001
- }
2002
- return r;
2003
- };
2004
-
2005
- function detectXType(series, noDatetime, options) {
2006
- if (dataEmpty(series)) {
2007
- if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
2008
- return "datetime";
2009
- } else {
2010
- return "number";
2011
- }
2012
- } else if (detectXTypeWithFunction(series, isNumber)) {
2013
- return "number";
2014
- } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
2015
- return "datetime";
2016
- } else {
2017
- return "string";
2018
- }
2019
- }
2020
-
2021
- function detectXTypeWithFunction(series, func) {
2022
- var i, j, data;
2023
- for (i = 0; i < series.length; i++) {
2024
- data = toArr(series[i].data);
2025
- for (j = 0; j < data.length; j++) {
2026
- if (!func(data[j][0])) {
2027
- return false;
2028
- }
2029
- }
2030
- }
2031
- return true;
2032
- }
2033
-
2034
- // creates a shallow copy of each element of the array
2035
- // elements are expected to be objects
2036
- function copySeries(series) {
2037
- var newSeries = [], i, j;
2038
- for (i = 0; i < series.length; i++) {
2039
- var copy = {};
2040
- for (j in series[i]) {
2041
- if (series[i].hasOwnProperty(j)) {
2042
- copy[j] = series[i][j];
2043
- }
2044
- }
2045
- newSeries.push(copy);
2046
- }
2047
- return newSeries;
2048
- }
2049
-
2050
- function processSeries(chart, keyType, noDatetime) {
2051
- var i;
2052
-
2053
- var opts = chart.options;
2054
- var series = chart.rawData;
2055
-
2056
- // see if one series or multiple
2057
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
2058
- series = [{name: opts.label, data: series}];
2059
- chart.singleSeriesFormat = true;
2060
- } else {
2061
- chart.singleSeriesFormat = false;
2062
- }
2063
-
2064
- // convert to array
2065
- // must come before dataEmpty check
2066
- series = copySeries(series);
2067
- for (i = 0; i < series.length; i++) {
2068
- series[i].data = toArr(series[i].data);
2069
- }
2070
-
2071
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2072
-
2073
- // right format
2074
- for (i = 0; i < series.length; i++) {
2075
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
2076
- }
2077
-
2078
- return series;
2079
- }
2080
-
2081
- function processSimple(chart) {
2082
- var perfectData = toArr(chart.rawData), i;
2083
- for (i = 0; i < perfectData.length; i++) {
2084
- perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
2085
- }
2086
- return perfectData;
2087
- }
2088
-
2089
2082
  // define classes
2090
2083
 
2091
2084
  var Chart = function Chart(element, dataSource, options) {
@@ -2193,8 +2186,8 @@
2193
2186
  if (this.adapter === "chartjs") {
2194
2187
  if (download && download.background && download.background !== "transparent") {
2195
2188
  // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2196
- var canvas = this.chart.chart.canvas;
2197
- var ctx = this.chart.chart.ctx;
2189
+ var canvas = this.chart.canvas;
2190
+ var ctx = this.chart.ctx;
2198
2191
  var tmpCanvas = document.createElement("canvas");
2199
2192
  var tmpCtx = tmpCanvas.getContext("2d");
2200
2193
  tmpCanvas.width = ctx.canvas.width;