chartkick 4.0.2 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;