chart-js-rails 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/chart-js-rails/version.rb +1 -1
- data/vendor/assets/javascripts/Chart.js +1741 -1029
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27e48fe398bd9a47f7b4f80d154f5eacc3db0b8e
|
|
4
|
+
data.tar.gz: 518d5312ffed1c9181d6c9b11aa99f5091b8c495
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be9c00e5b1ebfc0fec07c0f30dfc3ffeaf24e80bf914e0491da764b992b4c065eb2dfb0b56e36258121145a01f12a1f575fc72b1faab58e33186b34319848d85
|
|
7
|
+
data.tar.gz: faace6ddb07125eb57fc87c1c7a6cf0f37216932609f75125ce0980b2cf354a1e10e872a9b50c5c99eb475a4c1747119519f6f4bff7b0ef55f580b6bdefb3485
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Chart.js
|
|
3
3
|
* http://chartjs.org/
|
|
4
|
-
* Version: 2.
|
|
4
|
+
* Version: 2.5.0
|
|
5
5
|
*
|
|
6
|
-
* Copyright
|
|
6
|
+
* Copyright 2017 Nick Downie
|
|
7
7
|
* Released under the MIT license
|
|
8
8
|
* https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
|
|
9
9
|
*/
|
|
@@ -1668,14 +1668,15 @@ module.exports = {
|
|
|
1668
1668
|
var Chart = require(28)();
|
|
1669
1669
|
|
|
1670
1670
|
require(26)(Chart);
|
|
1671
|
+
require(42)(Chart);
|
|
1671
1672
|
require(22)(Chart);
|
|
1673
|
+
require(31)(Chart);
|
|
1672
1674
|
require(25)(Chart);
|
|
1673
1675
|
require(21)(Chart);
|
|
1674
1676
|
require(23)(Chart);
|
|
1675
1677
|
require(24)(Chart);
|
|
1676
1678
|
require(29)(Chart);
|
|
1677
1679
|
require(33)(Chart);
|
|
1678
|
-
require(31)(Chart);
|
|
1679
1680
|
require(34)(Chart);
|
|
1680
1681
|
require(32)(Chart);
|
|
1681
1682
|
require(35)(Chart);
|
|
@@ -1688,12 +1689,12 @@ require(38)(Chart);
|
|
|
1688
1689
|
require(39)(Chart);
|
|
1689
1690
|
require(40)(Chart);
|
|
1690
1691
|
|
|
1692
|
+
require(45)(Chart);
|
|
1691
1693
|
require(43)(Chart);
|
|
1692
|
-
require(41)(Chart);
|
|
1693
|
-
require(42)(Chart);
|
|
1694
1694
|
require(44)(Chart);
|
|
1695
|
-
require(45)(Chart);
|
|
1696
1695
|
require(46)(Chart);
|
|
1696
|
+
require(47)(Chart);
|
|
1697
|
+
require(48)(Chart);
|
|
1697
1698
|
|
|
1698
1699
|
// Controllers must be loaded after elements
|
|
1699
1700
|
// See Chart.core.datasetController.dataElementType
|
|
@@ -1714,7 +1715,7 @@ require(14)(Chart);
|
|
|
1714
1715
|
|
|
1715
1716
|
window.Chart = module.exports = Chart;
|
|
1716
1717
|
|
|
1717
|
-
},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"39":39,"40":40,"
|
|
1718
|
+
},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"39":39,"40":40,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"8":8,"9":9}],8:[function(require,module,exports){
|
|
1718
1719
|
'use strict';
|
|
1719
1720
|
|
|
1720
1721
|
module.exports = function(Chart) {
|
|
@@ -1878,21 +1879,33 @@ module.exports = function(Chart) {
|
|
|
1878
1879
|
initialize: function(chart, datasetIndex) {
|
|
1879
1880
|
Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
|
|
1880
1881
|
|
|
1882
|
+
var me = this;
|
|
1883
|
+
var meta = me.getMeta();
|
|
1884
|
+
var dataset = me.getDataset();
|
|
1885
|
+
|
|
1886
|
+
meta.stack = dataset.stack;
|
|
1881
1887
|
// Use this to indicate that this is a bar dataset.
|
|
1882
|
-
|
|
1888
|
+
meta.bar = true;
|
|
1883
1889
|
},
|
|
1884
1890
|
|
|
1885
|
-
//
|
|
1886
|
-
|
|
1891
|
+
// Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible
|
|
1892
|
+
getStackCount: function() {
|
|
1887
1893
|
var me = this;
|
|
1888
|
-
var
|
|
1894
|
+
var meta = me.getMeta();
|
|
1895
|
+
var yScale = me.getScaleForId(meta.yAxisID);
|
|
1896
|
+
|
|
1897
|
+
var stacks = [];
|
|
1889
1898
|
helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
|
|
1890
|
-
var
|
|
1891
|
-
if (
|
|
1892
|
-
|
|
1899
|
+
var dsMeta = me.chart.getDatasetMeta(datasetIndex);
|
|
1900
|
+
if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) &&
|
|
1901
|
+
(yScale.options.stacked === false ||
|
|
1902
|
+
(yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
|
|
1903
|
+
(yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
|
|
1904
|
+
stacks.push(dsMeta.stack);
|
|
1893
1905
|
}
|
|
1894
1906
|
}, me);
|
|
1895
|
-
|
|
1907
|
+
|
|
1908
|
+
return stacks.length;
|
|
1896
1909
|
},
|
|
1897
1910
|
|
|
1898
1911
|
update: function(reset) {
|
|
@@ -1917,7 +1930,7 @@ module.exports = function(Chart) {
|
|
|
1917
1930
|
rectangle._datasetIndex = me.index;
|
|
1918
1931
|
rectangle._index = index;
|
|
1919
1932
|
|
|
1920
|
-
var ruler = me.getRuler(index);
|
|
1933
|
+
var ruler = me.getRuler(index); // The index argument for compatible
|
|
1921
1934
|
rectangle._model = {
|
|
1922
1935
|
x: me.calculateBarX(index, me.index, ruler),
|
|
1923
1936
|
y: reset ? scaleBase : me.calculateBarY(index, me.index),
|
|
@@ -1927,6 +1940,7 @@ module.exports = function(Chart) {
|
|
|
1927
1940
|
datasetLabel: dataset.label,
|
|
1928
1941
|
|
|
1929
1942
|
// Appearance
|
|
1943
|
+
horizontal: false,
|
|
1930
1944
|
base: reset ? scaleBase : me.calculateBarBase(me.index, index),
|
|
1931
1945
|
width: me.calculateBarWidth(ruler),
|
|
1932
1946
|
backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
|
|
@@ -1942,9 +1956,11 @@ module.exports = function(Chart) {
|
|
|
1942
1956
|
var me = this;
|
|
1943
1957
|
var meta = me.getMeta();
|
|
1944
1958
|
var yScale = me.getScaleForId(meta.yAxisID);
|
|
1945
|
-
var base =
|
|
1959
|
+
var base = yScale.getBaseValue();
|
|
1960
|
+
var original = base;
|
|
1946
1961
|
|
|
1947
|
-
if (yScale.options.stacked)
|
|
1962
|
+
if ((yScale.options.stacked === true) ||
|
|
1963
|
+
(yScale.options.stacked === undefined && meta.stack !== undefined)) {
|
|
1948
1964
|
var chart = me.chart;
|
|
1949
1965
|
var datasets = chart.data.datasets;
|
|
1950
1966
|
var value = Number(datasets[datasetIndex].data[index]);
|
|
@@ -1952,9 +1968,10 @@ module.exports = function(Chart) {
|
|
|
1952
1968
|
for (var i = 0; i < datasetIndex; i++) {
|
|
1953
1969
|
var currentDs = datasets[i];
|
|
1954
1970
|
var currentDsMeta = chart.getDatasetMeta(i);
|
|
1955
|
-
if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)
|
|
1971
|
+
if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i) &&
|
|
1972
|
+
meta.stack === currentDsMeta.stack) {
|
|
1956
1973
|
var currentVal = Number(currentDs.data[index]);
|
|
1957
|
-
base += value < 0 ? Math.min(currentVal,
|
|
1974
|
+
base += value < 0 ? Math.min(currentVal, original) : Math.max(currentVal, original);
|
|
1958
1975
|
}
|
|
1959
1976
|
}
|
|
1960
1977
|
|
|
@@ -1964,34 +1981,22 @@ module.exports = function(Chart) {
|
|
|
1964
1981
|
return yScale.getBasePixel();
|
|
1965
1982
|
},
|
|
1966
1983
|
|
|
1967
|
-
getRuler: function(
|
|
1984
|
+
getRuler: function() {
|
|
1968
1985
|
var me = this;
|
|
1969
1986
|
var meta = me.getMeta();
|
|
1970
1987
|
var xScale = me.getScaleForId(meta.xAxisID);
|
|
1971
|
-
var
|
|
1972
|
-
|
|
1973
|
-
var tickWidth;
|
|
1988
|
+
var stackCount = me.getStackCount();
|
|
1974
1989
|
|
|
1975
|
-
|
|
1976
|
-
tickWidth = xScale.getPixelForTick(index + 1) - xScale.getPixelForTick(index);
|
|
1977
|
-
} else {
|
|
1978
|
-
// Average width
|
|
1979
|
-
tickWidth = xScale.width / xScale.ticks.length;
|
|
1980
|
-
}
|
|
1990
|
+
var tickWidth = xScale.width / xScale.ticks.length;
|
|
1981
1991
|
var categoryWidth = tickWidth * xScale.options.categoryPercentage;
|
|
1982
1992
|
var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
|
|
1983
|
-
var fullBarWidth = categoryWidth /
|
|
1984
|
-
|
|
1985
|
-
if (xScale.ticks.length !== me.chart.data.labels.length) {
|
|
1986
|
-
var perc = xScale.ticks.length / me.chart.data.labels.length;
|
|
1987
|
-
fullBarWidth = fullBarWidth * perc;
|
|
1988
|
-
}
|
|
1993
|
+
var fullBarWidth = categoryWidth / stackCount;
|
|
1989
1994
|
|
|
1990
1995
|
var barWidth = fullBarWidth * xScale.options.barPercentage;
|
|
1991
1996
|
var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);
|
|
1992
1997
|
|
|
1993
1998
|
return {
|
|
1994
|
-
|
|
1999
|
+
stackCount: stackCount,
|
|
1995
2000
|
tickWidth: tickWidth,
|
|
1996
2001
|
categoryWidth: categoryWidth,
|
|
1997
2002
|
categorySpacing: categorySpacing,
|
|
@@ -2002,46 +2007,50 @@ module.exports = function(Chart) {
|
|
|
2002
2007
|
},
|
|
2003
2008
|
|
|
2004
2009
|
calculateBarWidth: function(ruler) {
|
|
2005
|
-
var
|
|
2010
|
+
var me = this;
|
|
2011
|
+
var meta = me.getMeta();
|
|
2012
|
+
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2006
2013
|
if (xScale.options.barThickness) {
|
|
2007
2014
|
return xScale.options.barThickness;
|
|
2008
2015
|
}
|
|
2009
|
-
return
|
|
2016
|
+
return ruler.barWidth;
|
|
2010
2017
|
},
|
|
2011
2018
|
|
|
2012
|
-
// Get
|
|
2013
|
-
|
|
2014
|
-
var
|
|
2015
|
-
var meta
|
|
2019
|
+
// Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible
|
|
2020
|
+
getStackIndex: function(datasetIndex) {
|
|
2021
|
+
var me = this;
|
|
2022
|
+
var meta = me.chart.getDatasetMeta(datasetIndex);
|
|
2023
|
+
var yScale = me.getScaleForId(meta.yAxisID);
|
|
2024
|
+
var dsMeta, j;
|
|
2025
|
+
var stacks = [meta.stack];
|
|
2016
2026
|
|
|
2017
2027
|
for (j = 0; j < datasetIndex; ++j) {
|
|
2018
|
-
|
|
2019
|
-
if (
|
|
2020
|
-
|
|
2028
|
+
dsMeta = this.chart.getDatasetMeta(j);
|
|
2029
|
+
if (dsMeta.bar && this.chart.isDatasetVisible(j) &&
|
|
2030
|
+
(yScale.options.stacked === false ||
|
|
2031
|
+
(yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
|
|
2032
|
+
(yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
|
|
2033
|
+
stacks.push(dsMeta.stack);
|
|
2021
2034
|
}
|
|
2022
2035
|
}
|
|
2023
2036
|
|
|
2024
|
-
return
|
|
2037
|
+
return stacks.length - 1;
|
|
2025
2038
|
},
|
|
2026
2039
|
|
|
2027
2040
|
calculateBarX: function(index, datasetIndex, ruler) {
|
|
2028
2041
|
var me = this;
|
|
2029
2042
|
var meta = me.getMeta();
|
|
2030
2043
|
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2031
|
-
var
|
|
2044
|
+
var stackIndex = me.getStackIndex(datasetIndex);
|
|
2032
2045
|
var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
|
|
2033
2046
|
leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0;
|
|
2034
2047
|
|
|
2035
|
-
if (xScale.options.stacked) {
|
|
2036
|
-
return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing;
|
|
2037
|
-
}
|
|
2038
|
-
|
|
2039
2048
|
return leftTick +
|
|
2040
2049
|
(ruler.barWidth / 2) +
|
|
2041
2050
|
ruler.categorySpacing +
|
|
2042
|
-
(ruler.barWidth *
|
|
2051
|
+
(ruler.barWidth * stackIndex) +
|
|
2043
2052
|
(ruler.barSpacing / 2) +
|
|
2044
|
-
(ruler.barSpacing *
|
|
2053
|
+
(ruler.barSpacing * stackIndex);
|
|
2045
2054
|
},
|
|
2046
2055
|
|
|
2047
2056
|
calculateBarY: function(index, datasetIndex) {
|
|
@@ -2050,15 +2059,17 @@ module.exports = function(Chart) {
|
|
|
2050
2059
|
var yScale = me.getScaleForId(meta.yAxisID);
|
|
2051
2060
|
var value = Number(me.getDataset().data[index]);
|
|
2052
2061
|
|
|
2053
|
-
if (yScale.options.stacked
|
|
2054
|
-
|
|
2055
|
-
var
|
|
2056
|
-
|
|
2062
|
+
if (yScale.options.stacked ||
|
|
2063
|
+
(yScale.options.stacked === undefined && meta.stack !== undefined)) {
|
|
2064
|
+
var base = yScale.getBaseValue();
|
|
2065
|
+
var sumPos = base,
|
|
2066
|
+
sumNeg = base;
|
|
2057
2067
|
|
|
2058
2068
|
for (var i = 0; i < datasetIndex; i++) {
|
|
2059
2069
|
var ds = me.chart.data.datasets[i];
|
|
2060
2070
|
var dsMeta = me.chart.getDatasetMeta(i);
|
|
2061
|
-
if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i)
|
|
2071
|
+
if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i) &&
|
|
2072
|
+
meta.stack === dsMeta.stack) {
|
|
2062
2073
|
var stackedVal = Number(ds.data[index]);
|
|
2063
2074
|
if (stackedVal < 0) {
|
|
2064
2075
|
sumNeg += stackedVal || 0;
|
|
@@ -2084,12 +2095,14 @@ module.exports = function(Chart) {
|
|
|
2084
2095
|
var dataset = me.getDataset();
|
|
2085
2096
|
var i, len;
|
|
2086
2097
|
|
|
2098
|
+
Chart.canvasHelpers.clipArea(me.chart.chart.ctx, me.chart.chartArea);
|
|
2087
2099
|
for (i = 0, len = metaData.length; i < len; ++i) {
|
|
2088
2100
|
var d = dataset.data[i];
|
|
2089
2101
|
if (d !== null && d !== undefined && !isNaN(d)) {
|
|
2090
2102
|
metaData[i].transition(easingDecimal).draw();
|
|
2091
2103
|
}
|
|
2092
2104
|
}
|
|
2105
|
+
Chart.canvasHelpers.unclipArea(me.chart.chart.ctx);
|
|
2093
2106
|
},
|
|
2094
2107
|
|
|
2095
2108
|
setHoverStyle: function(rectangle) {
|
|
@@ -2174,6 +2187,27 @@ module.exports = function(Chart) {
|
|
|
2174
2187
|
};
|
|
2175
2188
|
|
|
2176
2189
|
Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
|
|
2190
|
+
|
|
2191
|
+
// Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible
|
|
2192
|
+
getStackCount: function() {
|
|
2193
|
+
var me = this;
|
|
2194
|
+
var meta = me.getMeta();
|
|
2195
|
+
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2196
|
+
|
|
2197
|
+
var stacks = [];
|
|
2198
|
+
helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
|
|
2199
|
+
var dsMeta = me.chart.getDatasetMeta(datasetIndex);
|
|
2200
|
+
if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) &&
|
|
2201
|
+
(xScale.options.stacked === false ||
|
|
2202
|
+
(xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
|
|
2203
|
+
(xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
|
|
2204
|
+
stacks.push(dsMeta.stack);
|
|
2205
|
+
}
|
|
2206
|
+
}, me);
|
|
2207
|
+
|
|
2208
|
+
return stacks.length;
|
|
2209
|
+
},
|
|
2210
|
+
|
|
2177
2211
|
updateElement: function(rectangle, index, reset) {
|
|
2178
2212
|
var me = this;
|
|
2179
2213
|
var meta = me.getMeta();
|
|
@@ -2189,7 +2223,7 @@ module.exports = function(Chart) {
|
|
|
2189
2223
|
rectangle._datasetIndex = me.index;
|
|
2190
2224
|
rectangle._index = index;
|
|
2191
2225
|
|
|
2192
|
-
var ruler = me.getRuler(index);
|
|
2226
|
+
var ruler = me.getRuler(index); // The index argument for compatible
|
|
2193
2227
|
rectangle._model = {
|
|
2194
2228
|
x: reset ? scaleBase : me.calculateBarX(index, me.index),
|
|
2195
2229
|
y: me.calculateBarY(index, me.index, ruler),
|
|
@@ -2199,6 +2233,7 @@ module.exports = function(Chart) {
|
|
|
2199
2233
|
datasetLabel: dataset.label,
|
|
2200
2234
|
|
|
2201
2235
|
// Appearance
|
|
2236
|
+
horizontal: true,
|
|
2202
2237
|
base: reset ? scaleBase : me.calculateBarBase(me.index, index),
|
|
2203
2238
|
height: me.calculateBarHeight(ruler),
|
|
2204
2239
|
backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
|
|
@@ -2206,62 +2241,6 @@ module.exports = function(Chart) {
|
|
|
2206
2241
|
borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor),
|
|
2207
2242
|
borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth)
|
|
2208
2243
|
};
|
|
2209
|
-
rectangle.draw = function() {
|
|
2210
|
-
var ctx = this._chart.ctx;
|
|
2211
|
-
var vm = this._view;
|
|
2212
|
-
|
|
2213
|
-
var halfHeight = vm.height / 2,
|
|
2214
|
-
topY = vm.y - halfHeight,
|
|
2215
|
-
bottomY = vm.y + halfHeight,
|
|
2216
|
-
right = vm.base - (vm.base - vm.x),
|
|
2217
|
-
halfStroke = vm.borderWidth / 2;
|
|
2218
|
-
|
|
2219
|
-
// Canvas doesn't allow us to stroke inside the width so we can
|
|
2220
|
-
// adjust the sizes to fit if we're setting a stroke on the line
|
|
2221
|
-
if (vm.borderWidth) {
|
|
2222
|
-
topY += halfStroke;
|
|
2223
|
-
bottomY -= halfStroke;
|
|
2224
|
-
right += halfStroke;
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
ctx.beginPath();
|
|
2228
|
-
|
|
2229
|
-
ctx.fillStyle = vm.backgroundColor;
|
|
2230
|
-
ctx.strokeStyle = vm.borderColor;
|
|
2231
|
-
ctx.lineWidth = vm.borderWidth;
|
|
2232
|
-
|
|
2233
|
-
// Corner points, from bottom-left to bottom-right clockwise
|
|
2234
|
-
// | 1 2 |
|
|
2235
|
-
// | 0 3 |
|
|
2236
|
-
var corners = [
|
|
2237
|
-
[vm.base, bottomY],
|
|
2238
|
-
[vm.base, topY],
|
|
2239
|
-
[right, topY],
|
|
2240
|
-
[right, bottomY]
|
|
2241
|
-
];
|
|
2242
|
-
|
|
2243
|
-
// Find first (starting) corner with fallback to 'bottom'
|
|
2244
|
-
var borders = ['bottom', 'left', 'top', 'right'];
|
|
2245
|
-
var startCorner = borders.indexOf(vm.borderSkipped, 0);
|
|
2246
|
-
if (startCorner === -1) {
|
|
2247
|
-
startCorner = 0;
|
|
2248
|
-
}
|
|
2249
|
-
|
|
2250
|
-
function cornerAt(cornerIndex) {
|
|
2251
|
-
return corners[(startCorner + cornerIndex) % 4];
|
|
2252
|
-
}
|
|
2253
|
-
|
|
2254
|
-
// Draw rectangle from 'startCorner'
|
|
2255
|
-
ctx.moveTo.apply(ctx, cornerAt(0));
|
|
2256
|
-
for (var i = 1; i < 4; i++) {
|
|
2257
|
-
ctx.lineTo.apply(ctx, cornerAt(i));
|
|
2258
|
-
}
|
|
2259
|
-
|
|
2260
|
-
ctx.fill();
|
|
2261
|
-
if (vm.borderWidth) {
|
|
2262
|
-
ctx.stroke();
|
|
2263
|
-
}
|
|
2264
|
-
};
|
|
2265
2244
|
|
|
2266
2245
|
rectangle.pivot();
|
|
2267
2246
|
},
|
|
@@ -2270,9 +2249,11 @@ module.exports = function(Chart) {
|
|
|
2270
2249
|
var me = this;
|
|
2271
2250
|
var meta = me.getMeta();
|
|
2272
2251
|
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2273
|
-
var base =
|
|
2252
|
+
var base = xScale.getBaseValue();
|
|
2253
|
+
var originalBase = base;
|
|
2274
2254
|
|
|
2275
|
-
if (xScale.options.stacked
|
|
2255
|
+
if (xScale.options.stacked ||
|
|
2256
|
+
(xScale.options.stacked === undefined && meta.stack !== undefined)) {
|
|
2276
2257
|
var chart = me.chart;
|
|
2277
2258
|
var datasets = chart.data.datasets;
|
|
2278
2259
|
var value = Number(datasets[datasetIndex].data[index]);
|
|
@@ -2280,9 +2261,10 @@ module.exports = function(Chart) {
|
|
|
2280
2261
|
for (var i = 0; i < datasetIndex; i++) {
|
|
2281
2262
|
var currentDs = datasets[i];
|
|
2282
2263
|
var currentDsMeta = chart.getDatasetMeta(i);
|
|
2283
|
-
if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i)
|
|
2264
|
+
if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i) &&
|
|
2265
|
+
meta.stack === currentDsMeta.stack) {
|
|
2284
2266
|
var currentVal = Number(currentDs.data[index]);
|
|
2285
|
-
base += value < 0 ? Math.min(currentVal,
|
|
2267
|
+
base += value < 0 ? Math.min(currentVal, originalBase) : Math.max(currentVal, originalBase);
|
|
2286
2268
|
}
|
|
2287
2269
|
}
|
|
2288
2270
|
|
|
@@ -2292,33 +2274,22 @@ module.exports = function(Chart) {
|
|
|
2292
2274
|
return xScale.getBasePixel();
|
|
2293
2275
|
},
|
|
2294
2276
|
|
|
2295
|
-
getRuler: function(
|
|
2277
|
+
getRuler: function() {
|
|
2296
2278
|
var me = this;
|
|
2297
2279
|
var meta = me.getMeta();
|
|
2298
2280
|
var yScale = me.getScaleForId(meta.yAxisID);
|
|
2299
|
-
var
|
|
2281
|
+
var stackCount = me.getStackCount();
|
|
2300
2282
|
|
|
2301
|
-
var tickHeight;
|
|
2302
|
-
if (yScale.options.type === 'category') {
|
|
2303
|
-
tickHeight = yScale.getPixelForTick(index + 1) - yScale.getPixelForTick(index);
|
|
2304
|
-
} else {
|
|
2305
|
-
// Average width
|
|
2306
|
-
tickHeight = yScale.width / yScale.ticks.length;
|
|
2307
|
-
}
|
|
2283
|
+
var tickHeight = yScale.height / yScale.ticks.length;
|
|
2308
2284
|
var categoryHeight = tickHeight * yScale.options.categoryPercentage;
|
|
2309
2285
|
var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2;
|
|
2310
|
-
var fullBarHeight = categoryHeight /
|
|
2311
|
-
|
|
2312
|
-
if (yScale.ticks.length !== me.chart.data.labels.length) {
|
|
2313
|
-
var perc = yScale.ticks.length / me.chart.data.labels.length;
|
|
2314
|
-
fullBarHeight = fullBarHeight * perc;
|
|
2315
|
-
}
|
|
2286
|
+
var fullBarHeight = categoryHeight / stackCount;
|
|
2316
2287
|
|
|
2317
2288
|
var barHeight = fullBarHeight * yScale.options.barPercentage;
|
|
2318
2289
|
var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage);
|
|
2319
2290
|
|
|
2320
2291
|
return {
|
|
2321
|
-
|
|
2292
|
+
stackCount: stackCount,
|
|
2322
2293
|
tickHeight: tickHeight,
|
|
2323
2294
|
categoryHeight: categoryHeight,
|
|
2324
2295
|
categorySpacing: categorySpacing,
|
|
@@ -2330,11 +2301,33 @@ module.exports = function(Chart) {
|
|
|
2330
2301
|
|
|
2331
2302
|
calculateBarHeight: function(ruler) {
|
|
2332
2303
|
var me = this;
|
|
2333
|
-
var
|
|
2304
|
+
var meta = me.getMeta();
|
|
2305
|
+
var yScale = me.getScaleForId(meta.yAxisID);
|
|
2334
2306
|
if (yScale.options.barThickness) {
|
|
2335
2307
|
return yScale.options.barThickness;
|
|
2336
2308
|
}
|
|
2337
|
-
return
|
|
2309
|
+
return ruler.barHeight;
|
|
2310
|
+
},
|
|
2311
|
+
|
|
2312
|
+
// Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible
|
|
2313
|
+
getStackIndex: function(datasetIndex) {
|
|
2314
|
+
var me = this;
|
|
2315
|
+
var meta = me.chart.getDatasetMeta(datasetIndex);
|
|
2316
|
+
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2317
|
+
var dsMeta, j;
|
|
2318
|
+
var stacks = [meta.stack];
|
|
2319
|
+
|
|
2320
|
+
for (j = 0; j < datasetIndex; ++j) {
|
|
2321
|
+
dsMeta = this.chart.getDatasetMeta(j);
|
|
2322
|
+
if (dsMeta.bar && this.chart.isDatasetVisible(j) &&
|
|
2323
|
+
(xScale.options.stacked === false ||
|
|
2324
|
+
(xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
|
|
2325
|
+
(xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
|
|
2326
|
+
stacks.push(dsMeta.stack);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
return stacks.length - 1;
|
|
2338
2331
|
},
|
|
2339
2332
|
|
|
2340
2333
|
calculateBarX: function(index, datasetIndex) {
|
|
@@ -2343,15 +2336,17 @@ module.exports = function(Chart) {
|
|
|
2343
2336
|
var xScale = me.getScaleForId(meta.xAxisID);
|
|
2344
2337
|
var value = Number(me.getDataset().data[index]);
|
|
2345
2338
|
|
|
2346
|
-
if (xScale.options.stacked
|
|
2347
|
-
|
|
2348
|
-
var
|
|
2349
|
-
|
|
2339
|
+
if (xScale.options.stacked ||
|
|
2340
|
+
(xScale.options.stacked === undefined && meta.stack !== undefined)) {
|
|
2341
|
+
var base = xScale.getBaseValue();
|
|
2342
|
+
var sumPos = base,
|
|
2343
|
+
sumNeg = base;
|
|
2350
2344
|
|
|
2351
2345
|
for (var i = 0; i < datasetIndex; i++) {
|
|
2352
2346
|
var ds = me.chart.data.datasets[i];
|
|
2353
2347
|
var dsMeta = me.chart.getDatasetMeta(i);
|
|
2354
|
-
if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i)
|
|
2348
|
+
if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i) &&
|
|
2349
|
+
meta.stack === dsMeta.stack) {
|
|
2355
2350
|
var stackedVal = Number(ds.data[index]);
|
|
2356
2351
|
if (stackedVal < 0) {
|
|
2357
2352
|
sumNeg += stackedVal || 0;
|
|
@@ -2374,20 +2369,16 @@ module.exports = function(Chart) {
|
|
|
2374
2369
|
var me = this;
|
|
2375
2370
|
var meta = me.getMeta();
|
|
2376
2371
|
var yScale = me.getScaleForId(meta.yAxisID);
|
|
2377
|
-
var
|
|
2372
|
+
var stackIndex = me.getStackIndex(datasetIndex);
|
|
2378
2373
|
var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
|
|
2379
2374
|
topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0;
|
|
2380
2375
|
|
|
2381
|
-
if (yScale.options.stacked) {
|
|
2382
|
-
return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
|
|
2383
|
-
}
|
|
2384
|
-
|
|
2385
2376
|
return topTick +
|
|
2386
2377
|
(ruler.barHeight / 2) +
|
|
2387
2378
|
ruler.categorySpacing +
|
|
2388
|
-
(ruler.barHeight *
|
|
2379
|
+
(ruler.barHeight * stackIndex) +
|
|
2389
2380
|
(ruler.barSpacing / 2) +
|
|
2390
|
-
(ruler.barSpacing *
|
|
2381
|
+
(ruler.barSpacing * stackIndex);
|
|
2391
2382
|
}
|
|
2392
2383
|
});
|
|
2393
2384
|
};
|
|
@@ -2702,7 +2693,7 @@ module.exports = function(Chart) {
|
|
|
2702
2693
|
|
|
2703
2694
|
chart.borderWidth = me.getMaxBorderWidth(meta.data);
|
|
2704
2695
|
chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
|
|
2705
|
-
chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) :
|
|
2696
|
+
chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
|
|
2706
2697
|
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
|
|
2707
2698
|
chart.offsetX = offset.x * chart.outerRadius;
|
|
2708
2699
|
chart.offsetY = offset.y * chart.outerRadius;
|
|
@@ -2710,7 +2701,7 @@ module.exports = function(Chart) {
|
|
|
2710
2701
|
meta.total = me.calculateTotal();
|
|
2711
2702
|
|
|
2712
2703
|
me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
|
|
2713
|
-
me.innerRadius = me.outerRadius - chart.radiusLength;
|
|
2704
|
+
me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
|
|
2714
2705
|
|
|
2715
2706
|
helpers.each(meta.data, function(arc, index) {
|
|
2716
2707
|
me.updateElement(arc, index, reset);
|
|
@@ -2963,11 +2954,11 @@ module.exports = function(Chart) {
|
|
|
2963
2954
|
var dataset = this.getDataset();
|
|
2964
2955
|
var custom = point.custom || {};
|
|
2965
2956
|
|
|
2966
|
-
if (custom.borderWidth) {
|
|
2957
|
+
if (!isNaN(custom.borderWidth)) {
|
|
2967
2958
|
borderWidth = custom.borderWidth;
|
|
2968
|
-
} else if (dataset.pointBorderWidth) {
|
|
2959
|
+
} else if (!isNaN(dataset.pointBorderWidth)) {
|
|
2969
2960
|
borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
|
|
2970
|
-
} else if (dataset.borderWidth) {
|
|
2961
|
+
} else if (!isNaN(dataset.borderWidth)) {
|
|
2971
2962
|
borderWidth = dataset.borderWidth;
|
|
2972
2963
|
}
|
|
2973
2964
|
|
|
@@ -3116,14 +3107,16 @@ module.exports = function(Chart) {
|
|
|
3116
3107
|
points[i].transition(easingDecimal);
|
|
3117
3108
|
}
|
|
3118
3109
|
|
|
3110
|
+
Chart.canvasHelpers.clipArea(me.chart.chart.ctx, me.chart.chartArea);
|
|
3119
3111
|
// Transition and Draw the line
|
|
3120
3112
|
if (lineEnabled(me.getDataset(), me.chart.options)) {
|
|
3121
3113
|
meta.dataset.transition(easingDecimal).draw();
|
|
3122
3114
|
}
|
|
3115
|
+
Chart.canvasHelpers.unclipArea(me.chart.chart.ctx);
|
|
3123
3116
|
|
|
3124
3117
|
// Draw the points
|
|
3125
3118
|
for (i=0, ilen=points.length; i<ilen; ++i) {
|
|
3126
|
-
points[i].draw();
|
|
3119
|
+
points[i].draw(me.chart.chartArea);
|
|
3127
3120
|
}
|
|
3128
3121
|
},
|
|
3129
3122
|
|
|
@@ -3475,7 +3468,7 @@ module.exports = function(Chart) {
|
|
|
3475
3468
|
y: reset ? scale.yCenter : pointPosition.y,
|
|
3476
3469
|
|
|
3477
3470
|
// Appearance
|
|
3478
|
-
tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.
|
|
3471
|
+
tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
|
|
3479
3472
|
radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
|
|
3480
3473
|
backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
|
|
3481
3474
|
borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
|
|
@@ -3747,6 +3740,14 @@ module.exports = function(Chart) {
|
|
|
3747
3740
|
ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
|
|
3748
3741
|
ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
|
|
3749
3742
|
break;
|
|
3743
|
+
case 'rectRounded':
|
|
3744
|
+
var offset = radius / Math.SQRT2;
|
|
3745
|
+
var leftX = x - offset;
|
|
3746
|
+
var topY = y - offset;
|
|
3747
|
+
var sideSize = Math.SQRT2 * radius;
|
|
3748
|
+
Chart.helpers.drawRoundedRectangle(ctx, leftX, topY, sideSize, sideSize, radius / 2);
|
|
3749
|
+
ctx.fill();
|
|
3750
|
+
break;
|
|
3750
3751
|
case 'rectRot':
|
|
3751
3752
|
size = 1 / Math.SQRT2 * radius;
|
|
3752
3753
|
ctx.beginPath();
|
|
@@ -3805,6 +3806,18 @@ module.exports = function(Chart) {
|
|
|
3805
3806
|
|
|
3806
3807
|
ctx.stroke();
|
|
3807
3808
|
};
|
|
3809
|
+
|
|
3810
|
+
helpers.clipArea = function(ctx, clipArea) {
|
|
3811
|
+
ctx.save();
|
|
3812
|
+
ctx.beginPath();
|
|
3813
|
+
ctx.rect(clipArea.left, clipArea.top, clipArea.right - clipArea.left, clipArea.bottom - clipArea.top);
|
|
3814
|
+
ctx.clip();
|
|
3815
|
+
};
|
|
3816
|
+
|
|
3817
|
+
helpers.unclipArea = function(ctx) {
|
|
3818
|
+
ctx.restore();
|
|
3819
|
+
};
|
|
3820
|
+
|
|
3808
3821
|
};
|
|
3809
3822
|
|
|
3810
3823
|
},{}],23:[function(require,module,exports){
|
|
@@ -3813,6 +3826,8 @@ module.exports = function(Chart) {
|
|
|
3813
3826
|
module.exports = function(Chart) {
|
|
3814
3827
|
|
|
3815
3828
|
var helpers = Chart.helpers;
|
|
3829
|
+
var plugins = Chart.plugins;
|
|
3830
|
+
var platform = Chart.platform;
|
|
3816
3831
|
|
|
3817
3832
|
// Create a dictionary of chart types, to allow for extension of existing types
|
|
3818
3833
|
Chart.types = {};
|
|
@@ -3824,140 +3839,6 @@ module.exports = function(Chart) {
|
|
|
3824
3839
|
// Controllers available for dataset visualization eg. bar, line, slice, etc.
|
|
3825
3840
|
Chart.controllers = {};
|
|
3826
3841
|
|
|
3827
|
-
/**
|
|
3828
|
-
* The "used" size is the final value of a dimension property after all calculations have
|
|
3829
|
-
* been performed. This method uses the computed style of `element` but returns undefined
|
|
3830
|
-
* if the computed style is not expressed in pixels. That can happen in some cases where
|
|
3831
|
-
* `element` has a size relative to its parent and this last one is not yet displayed,
|
|
3832
|
-
* for example because of `display: none` on a parent node.
|
|
3833
|
-
* TODO(SB) Move this method in the upcoming core.platform class.
|
|
3834
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
|
|
3835
|
-
* @returns {Number} Size in pixels or undefined if unknown.
|
|
3836
|
-
*/
|
|
3837
|
-
function readUsedSize(element, property) {
|
|
3838
|
-
var value = helpers.getStyle(element, property);
|
|
3839
|
-
var matches = value && value.match(/(\d+)px/);
|
|
3840
|
-
return matches? Number(matches[1]) : undefined;
|
|
3841
|
-
}
|
|
3842
|
-
|
|
3843
|
-
/**
|
|
3844
|
-
* Initializes the canvas style and render size without modifying the canvas display size,
|
|
3845
|
-
* since responsiveness is handled by the controller.resize() method. The config is used
|
|
3846
|
-
* to determine the aspect ratio to apply in case no explicit height has been specified.
|
|
3847
|
-
* TODO(SB) Move this method in the upcoming core.platform class.
|
|
3848
|
-
*/
|
|
3849
|
-
function initCanvas(canvas, config) {
|
|
3850
|
-
var style = canvas.style;
|
|
3851
|
-
|
|
3852
|
-
// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
|
|
3853
|
-
// returns null or '' if no explicit value has been set to the canvas attribute.
|
|
3854
|
-
var renderHeight = canvas.getAttribute('height');
|
|
3855
|
-
var renderWidth = canvas.getAttribute('width');
|
|
3856
|
-
|
|
3857
|
-
// Chart.js modifies some canvas values that we want to restore on destroy
|
|
3858
|
-
canvas._chartjs = {
|
|
3859
|
-
initial: {
|
|
3860
|
-
height: renderHeight,
|
|
3861
|
-
width: renderWidth,
|
|
3862
|
-
style: {
|
|
3863
|
-
display: style.display,
|
|
3864
|
-
height: style.height,
|
|
3865
|
-
width: style.width
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
};
|
|
3869
|
-
|
|
3870
|
-
// Force canvas to display as block to avoid extra space caused by inline
|
|
3871
|
-
// elements, which would interfere with the responsive resize process.
|
|
3872
|
-
// https://github.com/chartjs/Chart.js/issues/2538
|
|
3873
|
-
style.display = style.display || 'block';
|
|
3874
|
-
|
|
3875
|
-
if (renderWidth === null || renderWidth === '') {
|
|
3876
|
-
var displayWidth = readUsedSize(canvas, 'width');
|
|
3877
|
-
if (displayWidth !== undefined) {
|
|
3878
|
-
canvas.width = displayWidth;
|
|
3879
|
-
}
|
|
3880
|
-
}
|
|
3881
|
-
|
|
3882
|
-
if (renderHeight === null || renderHeight === '') {
|
|
3883
|
-
if (canvas.style.height === '') {
|
|
3884
|
-
// If no explicit render height and style height, let's apply the aspect ratio,
|
|
3885
|
-
// which one can be specified by the user but also by charts as default option
|
|
3886
|
-
// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
|
|
3887
|
-
canvas.height = canvas.width / (config.options.aspectRatio || 2);
|
|
3888
|
-
} else {
|
|
3889
|
-
var displayHeight = readUsedSize(canvas, 'height');
|
|
3890
|
-
if (displayWidth !== undefined) {
|
|
3891
|
-
canvas.height = displayHeight;
|
|
3892
|
-
}
|
|
3893
|
-
}
|
|
3894
|
-
}
|
|
3895
|
-
|
|
3896
|
-
return canvas;
|
|
3897
|
-
}
|
|
3898
|
-
|
|
3899
|
-
/**
|
|
3900
|
-
* Restores the canvas initial state, such as render/display sizes and style.
|
|
3901
|
-
* TODO(SB) Move this method in the upcoming core.platform class.
|
|
3902
|
-
*/
|
|
3903
|
-
function releaseCanvas(canvas) {
|
|
3904
|
-
if (!canvas._chartjs) {
|
|
3905
|
-
return;
|
|
3906
|
-
}
|
|
3907
|
-
|
|
3908
|
-
var initial = canvas._chartjs.initial;
|
|
3909
|
-
['height', 'width'].forEach(function(prop) {
|
|
3910
|
-
var value = initial[prop];
|
|
3911
|
-
if (value === undefined || value === null) {
|
|
3912
|
-
canvas.removeAttribute(prop);
|
|
3913
|
-
} else {
|
|
3914
|
-
canvas.setAttribute(prop, value);
|
|
3915
|
-
}
|
|
3916
|
-
});
|
|
3917
|
-
|
|
3918
|
-
helpers.each(initial.style || {}, function(value, key) {
|
|
3919
|
-
canvas.style[key] = value;
|
|
3920
|
-
});
|
|
3921
|
-
|
|
3922
|
-
// The canvas render size might have been changed (and thus the state stack discarded),
|
|
3923
|
-
// we can't use save() and restore() to restore the initial state. So make sure that at
|
|
3924
|
-
// least the canvas context is reset to the default state by setting the canvas width.
|
|
3925
|
-
// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
|
|
3926
|
-
canvas.width = canvas.width;
|
|
3927
|
-
|
|
3928
|
-
delete canvas._chartjs;
|
|
3929
|
-
}
|
|
3930
|
-
|
|
3931
|
-
/**
|
|
3932
|
-
* TODO(SB) Move this method in the upcoming core.platform class.
|
|
3933
|
-
*/
|
|
3934
|
-
function acquireContext(item, config) {
|
|
3935
|
-
if (typeof item === 'string') {
|
|
3936
|
-
item = document.getElementById(item);
|
|
3937
|
-
} else if (item.length) {
|
|
3938
|
-
// Support for array based queries (such as jQuery)
|
|
3939
|
-
item = item[0];
|
|
3940
|
-
}
|
|
3941
|
-
|
|
3942
|
-
if (item && item.canvas) {
|
|
3943
|
-
// Support for any object associated to a canvas (including a context2d)
|
|
3944
|
-
item = item.canvas;
|
|
3945
|
-
}
|
|
3946
|
-
|
|
3947
|
-
if (item instanceof HTMLCanvasElement) {
|
|
3948
|
-
// To prevent canvas fingerprinting, some add-ons undefine the getContext
|
|
3949
|
-
// method, for example: https://github.com/kkapsner/CanvasBlocker
|
|
3950
|
-
// https://github.com/chartjs/Chart.js/issues/2807
|
|
3951
|
-
var context = item.getContext && item.getContext('2d');
|
|
3952
|
-
if (context instanceof CanvasRenderingContext2D) {
|
|
3953
|
-
initCanvas(item, config);
|
|
3954
|
-
return context;
|
|
3955
|
-
}
|
|
3956
|
-
}
|
|
3957
|
-
|
|
3958
|
-
return null;
|
|
3959
|
-
}
|
|
3960
|
-
|
|
3961
3842
|
/**
|
|
3962
3843
|
* Initializes the given config with global and chart default values.
|
|
3963
3844
|
*/
|
|
@@ -3978,6 +3859,26 @@ module.exports = function(Chart) {
|
|
|
3978
3859
|
return config;
|
|
3979
3860
|
}
|
|
3980
3861
|
|
|
3862
|
+
/**
|
|
3863
|
+
* Updates the config of the chart
|
|
3864
|
+
* @param chart {Chart.Controller} chart to update the options for
|
|
3865
|
+
*/
|
|
3866
|
+
function updateConfig(chart) {
|
|
3867
|
+
var newOptions = chart.options;
|
|
3868
|
+
|
|
3869
|
+
// Update Scale(s) with options
|
|
3870
|
+
if (newOptions.scale) {
|
|
3871
|
+
chart.scale.options = newOptions.scale;
|
|
3872
|
+
} else if (newOptions.scales) {
|
|
3873
|
+
newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) {
|
|
3874
|
+
chart.scales[scaleOptions.id].options = scaleOptions;
|
|
3875
|
+
});
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3878
|
+
// Tooltip
|
|
3879
|
+
chart.tooltip._options = newOptions.tooltips;
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3981
3882
|
/**
|
|
3982
3883
|
* @class Chart.Controller
|
|
3983
3884
|
* The main controller of a chart.
|
|
@@ -3987,7 +3888,7 @@ module.exports = function(Chart) {
|
|
|
3987
3888
|
|
|
3988
3889
|
config = initConfig(config);
|
|
3989
3890
|
|
|
3990
|
-
var context = acquireContext(item, config);
|
|
3891
|
+
var context = platform.acquireContext(item, config);
|
|
3991
3892
|
var canvas = context && context.canvas;
|
|
3992
3893
|
var height = canvas && canvas.height;
|
|
3993
3894
|
var width = canvas && canvas.width;
|
|
@@ -4023,47 +3924,35 @@ module.exports = function(Chart) {
|
|
|
4023
3924
|
return me;
|
|
4024
3925
|
}
|
|
4025
3926
|
|
|
4026
|
-
helpers.retinaScale(instance);
|
|
4027
|
-
|
|
4028
|
-
// Responsiveness is currently based on the use of an iframe, however this method causes
|
|
4029
|
-
// performance issues and could be troublesome when used with ad blockers. So make sure
|
|
4030
|
-
// that the user is still able to create a chart without iframe when responsive is false.
|
|
4031
|
-
// See https://github.com/chartjs/Chart.js/issues/2210
|
|
4032
|
-
if (me.options.responsive) {
|
|
4033
|
-
helpers.addResizeListener(canvas.parentNode, function() {
|
|
4034
|
-
me.resize();
|
|
4035
|
-
});
|
|
4036
|
-
|
|
4037
|
-
// Initial resize before chart draws (must be silent to preserve initial animations).
|
|
4038
|
-
me.resize(true);
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
3927
|
me.initialize();
|
|
3928
|
+
me.update();
|
|
4042
3929
|
|
|
4043
3930
|
return me;
|
|
4044
3931
|
};
|
|
4045
3932
|
|
|
4046
|
-
helpers.extend(Chart.Controller.prototype, /** @lends Chart.Controller */ {
|
|
3933
|
+
helpers.extend(Chart.Controller.prototype, /** @lends Chart.Controller.prototype */ {
|
|
4047
3934
|
initialize: function() {
|
|
4048
3935
|
var me = this;
|
|
4049
3936
|
|
|
4050
3937
|
// Before init plugin notification
|
|
4051
|
-
|
|
3938
|
+
plugins.notify(me, 'beforeInit');
|
|
3939
|
+
|
|
3940
|
+
helpers.retinaScale(me.chart);
|
|
4052
3941
|
|
|
4053
3942
|
me.bindEvents();
|
|
4054
3943
|
|
|
4055
|
-
|
|
4056
|
-
|
|
3944
|
+
if (me.options.responsive) {
|
|
3945
|
+
// Initial resize before chart draws (must be silent to preserve initial animations).
|
|
3946
|
+
me.resize(true);
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3949
|
+
// Make sure scales have IDs and are built before we build any controllers.
|
|
4057
3950
|
me.ensureScalesHaveIDs();
|
|
4058
|
-
me.buildOrUpdateControllers();
|
|
4059
3951
|
me.buildScales();
|
|
4060
|
-
me.updateLayout();
|
|
4061
|
-
me.resetElements();
|
|
4062
3952
|
me.initToolTip();
|
|
4063
|
-
me.update();
|
|
4064
3953
|
|
|
4065
3954
|
// After init plugin notification
|
|
4066
|
-
|
|
3955
|
+
plugins.notify(me, 'afterInit');
|
|
4067
3956
|
|
|
4068
3957
|
return me;
|
|
4069
3958
|
},
|
|
@@ -4102,16 +3991,16 @@ module.exports = function(Chart) {
|
|
|
4102
3991
|
|
|
4103
3992
|
helpers.retinaScale(chart);
|
|
4104
3993
|
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
3994
|
+
if (!silent) {
|
|
3995
|
+
// Notify any plugins about the resize
|
|
3996
|
+
var newSize = {width: newWidth, height: newHeight};
|
|
3997
|
+
plugins.notify(me, 'resize', [newSize]);
|
|
4108
3998
|
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
3999
|
+
// Notify of resize
|
|
4000
|
+
if (me.options.onResize) {
|
|
4001
|
+
me.options.onResize(me, newSize);
|
|
4002
|
+
}
|
|
4113
4003
|
|
|
4114
|
-
if (!silent) {
|
|
4115
4004
|
me.stop();
|
|
4116
4005
|
me.update(me.options.responsiveAnimationDuration);
|
|
4117
4006
|
}
|
|
@@ -4187,10 +4076,6 @@ module.exports = function(Chart) {
|
|
|
4187
4076
|
Chart.scaleService.addScalesToLayout(this);
|
|
4188
4077
|
},
|
|
4189
4078
|
|
|
4190
|
-
updateLayout: function() {
|
|
4191
|
-
Chart.layoutService.update(this, this.chart.width, this.chart.height);
|
|
4192
|
-
},
|
|
4193
|
-
|
|
4194
4079
|
buildOrUpdateControllers: function() {
|
|
4195
4080
|
var me = this;
|
|
4196
4081
|
var types = [];
|
|
@@ -4226,7 +4111,6 @@ module.exports = function(Chart) {
|
|
|
4226
4111
|
|
|
4227
4112
|
/**
|
|
4228
4113
|
* Reset the elements of all datasets
|
|
4229
|
-
* @method resetElements
|
|
4230
4114
|
* @private
|
|
4231
4115
|
*/
|
|
4232
4116
|
resetElements: function() {
|
|
@@ -4238,7 +4122,6 @@ module.exports = function(Chart) {
|
|
|
4238
4122
|
|
|
4239
4123
|
/**
|
|
4240
4124
|
* Resets the chart back to it's state before the initial animation
|
|
4241
|
-
* @method reset
|
|
4242
4125
|
*/
|
|
4243
4126
|
reset: function() {
|
|
4244
4127
|
this.resetElements();
|
|
@@ -4247,7 +4130,12 @@ module.exports = function(Chart) {
|
|
|
4247
4130
|
|
|
4248
4131
|
update: function(animationDuration, lazy) {
|
|
4249
4132
|
var me = this;
|
|
4250
|
-
|
|
4133
|
+
|
|
4134
|
+
updateConfig(me);
|
|
4135
|
+
|
|
4136
|
+
if (plugins.notify(me, 'beforeUpdate') === false) {
|
|
4137
|
+
return;
|
|
4138
|
+
}
|
|
4251
4139
|
|
|
4252
4140
|
// In case the entire data object changed
|
|
4253
4141
|
me.tooltip._data = me.data;
|
|
@@ -4260,10 +4148,7 @@ module.exports = function(Chart) {
|
|
|
4260
4148
|
me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
|
|
4261
4149
|
}, me);
|
|
4262
4150
|
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
// Apply changes to the datasets that require the scales to have been calculated i.e BorderColor changes
|
|
4266
|
-
Chart.plugins.notify('afterScaleUpdate', [me]);
|
|
4151
|
+
me.updateLayout();
|
|
4267
4152
|
|
|
4268
4153
|
// Can only reset the new controllers after the scales have been updated
|
|
4269
4154
|
helpers.each(newControllers, function(controller) {
|
|
@@ -4273,7 +4158,7 @@ module.exports = function(Chart) {
|
|
|
4273
4158
|
me.updateDatasets();
|
|
4274
4159
|
|
|
4275
4160
|
// Do this before render so that any plugins that need final scale updates can use it
|
|
4276
|
-
|
|
4161
|
+
plugins.notify(me, 'afterUpdate');
|
|
4277
4162
|
|
|
4278
4163
|
if (me._bufferedRender) {
|
|
4279
4164
|
me._bufferedRequest = {
|
|
@@ -4286,51 +4171,64 @@ module.exports = function(Chart) {
|
|
|
4286
4171
|
},
|
|
4287
4172
|
|
|
4288
4173
|
/**
|
|
4289
|
-
*
|
|
4290
|
-
*
|
|
4291
|
-
*
|
|
4292
|
-
* @param {Object} instance the chart instance being updated.
|
|
4293
|
-
* @returns {Boolean} false to cancel the datasets update.
|
|
4294
|
-
* @memberof Chart.PluginBase
|
|
4295
|
-
* @since version 2.1.5
|
|
4296
|
-
* @instance
|
|
4174
|
+
* Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
|
|
4175
|
+
* hook, in which case, plugins will not be called on `afterLayout`.
|
|
4176
|
+
* @private
|
|
4297
4177
|
*/
|
|
4178
|
+
updateLayout: function() {
|
|
4179
|
+
var me = this;
|
|
4298
4180
|
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4181
|
+
if (plugins.notify(me, 'beforeLayout') === false) {
|
|
4182
|
+
return;
|
|
4183
|
+
}
|
|
4184
|
+
|
|
4185
|
+
Chart.layoutService.update(this, this.chart.width, this.chart.height);
|
|
4186
|
+
|
|
4187
|
+
/**
|
|
4188
|
+
* Provided for backward compatibility, use `afterLayout` instead.
|
|
4189
|
+
* @method IPlugin#afterScaleUpdate
|
|
4190
|
+
* @deprecated since version 2.5.0
|
|
4191
|
+
* @todo remove at version 3
|
|
4192
|
+
*/
|
|
4193
|
+
plugins.notify(me, 'afterScaleUpdate');
|
|
4194
|
+
plugins.notify(me, 'afterLayout');
|
|
4195
|
+
},
|
|
4308
4196
|
|
|
4309
4197
|
/**
|
|
4310
|
-
* Updates all datasets unless a plugin returns false to the beforeDatasetsUpdate
|
|
4311
|
-
*
|
|
4312
|
-
*
|
|
4313
|
-
* @protected
|
|
4314
|
-
* @instance
|
|
4198
|
+
* Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
|
|
4199
|
+
* hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
|
|
4200
|
+
* @private
|
|
4315
4201
|
*/
|
|
4316
4202
|
updateDatasets: function() {
|
|
4317
4203
|
var me = this;
|
|
4318
|
-
var i, ilen;
|
|
4319
4204
|
|
|
4320
|
-
if (
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
}
|
|
4205
|
+
if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4324
4208
|
|
|
4325
|
-
|
|
4209
|
+
for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
|
|
4210
|
+
me.getDatasetMeta(i).controller.update();
|
|
4326
4211
|
}
|
|
4212
|
+
|
|
4213
|
+
plugins.notify(me, 'afterDatasetsUpdate');
|
|
4327
4214
|
},
|
|
4328
4215
|
|
|
4329
4216
|
render: function(duration, lazy) {
|
|
4330
4217
|
var me = this;
|
|
4331
|
-
|
|
4218
|
+
|
|
4219
|
+
if (plugins.notify(me, 'beforeRender') === false) {
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4332
4222
|
|
|
4333
4223
|
var animationOptions = me.options.animation;
|
|
4224
|
+
var onComplete = function() {
|
|
4225
|
+
plugins.notify(me, 'afterRender');
|
|
4226
|
+
var callback = animationOptions && animationOptions.onComplete;
|
|
4227
|
+
if (callback && callback.call) {
|
|
4228
|
+
callback.call(me);
|
|
4229
|
+
}
|
|
4230
|
+
};
|
|
4231
|
+
|
|
4334
4232
|
if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
|
|
4335
4233
|
var animation = new Chart.Animation();
|
|
4336
4234
|
animation.numSteps = (duration || animationOptions.duration) / 16.66; // 60 fps
|
|
@@ -4347,53 +4245,72 @@ module.exports = function(Chart) {
|
|
|
4347
4245
|
|
|
4348
4246
|
// user events
|
|
4349
4247
|
animation.onAnimationProgress = animationOptions.onProgress;
|
|
4350
|
-
animation.onAnimationComplete =
|
|
4248
|
+
animation.onAnimationComplete = onComplete;
|
|
4351
4249
|
|
|
4352
4250
|
Chart.animationService.addAnimation(me, animation, duration, lazy);
|
|
4353
4251
|
} else {
|
|
4354
4252
|
me.draw();
|
|
4355
|
-
|
|
4356
|
-
animationOptions.onComplete.call(me);
|
|
4357
|
-
}
|
|
4253
|
+
onComplete();
|
|
4358
4254
|
}
|
|
4255
|
+
|
|
4359
4256
|
return me;
|
|
4360
4257
|
},
|
|
4361
4258
|
|
|
4362
|
-
draw: function(
|
|
4259
|
+
draw: function(easingValue) {
|
|
4363
4260
|
var me = this;
|
|
4364
|
-
|
|
4261
|
+
|
|
4365
4262
|
me.clear();
|
|
4366
4263
|
|
|
4367
|
-
|
|
4264
|
+
if (easingValue === undefined || easingValue === null) {
|
|
4265
|
+
easingValue = 1;
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4268
|
+
if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4368
4271
|
|
|
4369
4272
|
// Draw all the scales
|
|
4370
4273
|
helpers.each(me.boxes, function(box) {
|
|
4371
4274
|
box.draw(me.chartArea);
|
|
4372
4275
|
}, me);
|
|
4276
|
+
|
|
4373
4277
|
if (me.scale) {
|
|
4374
4278
|
me.scale.draw();
|
|
4375
4279
|
}
|
|
4376
4280
|
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
// Draw each dataset via its respective controller (reversed to support proper line stacking)
|
|
4380
|
-
helpers.each(me.data.datasets, function(dataset, datasetIndex) {
|
|
4381
|
-
if (me.isDatasetVisible(datasetIndex)) {
|
|
4382
|
-
me.getDatasetMeta(datasetIndex).controller.draw(ease);
|
|
4383
|
-
}
|
|
4384
|
-
}, me, true);
|
|
4385
|
-
|
|
4386
|
-
Chart.plugins.notify('afterDatasetsDraw', [me, easingDecimal]);
|
|
4281
|
+
me.drawDatasets(easingValue);
|
|
4387
4282
|
|
|
4388
4283
|
// Finally draw the tooltip
|
|
4389
|
-
me.tooltip.transition(
|
|
4284
|
+
me.tooltip.transition(easingValue).draw();
|
|
4390
4285
|
|
|
4391
|
-
|
|
4286
|
+
plugins.notify(me, 'afterDraw', [easingValue]);
|
|
4392
4287
|
},
|
|
4393
4288
|
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4289
|
+
/**
|
|
4290
|
+
* Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
|
|
4291
|
+
* hook, in which case, plugins will not be called on `afterDatasetsDraw`.
|
|
4292
|
+
* @private
|
|
4293
|
+
*/
|
|
4294
|
+
drawDatasets: function(easingValue) {
|
|
4295
|
+
var me = this;
|
|
4296
|
+
|
|
4297
|
+
if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
|
|
4298
|
+
return;
|
|
4299
|
+
}
|
|
4300
|
+
|
|
4301
|
+
// Draw each dataset via its respective controller (reversed to support proper line stacking)
|
|
4302
|
+
helpers.each(me.data.datasets, function(dataset, datasetIndex) {
|
|
4303
|
+
if (me.isDatasetVisible(datasetIndex)) {
|
|
4304
|
+
me.getDatasetMeta(datasetIndex).controller.draw(easingValue);
|
|
4305
|
+
}
|
|
4306
|
+
}, me, true);
|
|
4307
|
+
|
|
4308
|
+
plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
|
|
4309
|
+
},
|
|
4310
|
+
|
|
4311
|
+
// Get the single element that was clicked on
|
|
4312
|
+
// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
|
|
4313
|
+
getElementAtEvent: function(e) {
|
|
4397
4314
|
return Chart.Interaction.modes.single(this, e);
|
|
4398
4315
|
},
|
|
4399
4316
|
|
|
@@ -4415,7 +4332,7 @@ module.exports = function(Chart) {
|
|
|
4415
4332
|
},
|
|
4416
4333
|
|
|
4417
4334
|
getDatasetAtEvent: function(e) {
|
|
4418
|
-
return Chart.Interaction.modes.dataset(this, e);
|
|
4335
|
+
return Chart.Interaction.modes.dataset(this, e, {intersect: true});
|
|
4419
4336
|
},
|
|
4420
4337
|
|
|
4421
4338
|
getDatasetMeta: function(datasetIndex) {
|
|
@@ -4480,15 +4397,14 @@ module.exports = function(Chart) {
|
|
|
4480
4397
|
}
|
|
4481
4398
|
|
|
4482
4399
|
if (canvas) {
|
|
4483
|
-
|
|
4484
|
-
helpers.removeResizeListener(canvas.parentNode);
|
|
4400
|
+
me.unbindEvents();
|
|
4485
4401
|
helpers.clear(me.chart);
|
|
4486
|
-
|
|
4402
|
+
platform.releaseContext(me.chart.ctx);
|
|
4487
4403
|
me.chart.canvas = null;
|
|
4488
4404
|
me.chart.ctx = null;
|
|
4489
4405
|
}
|
|
4490
4406
|
|
|
4491
|
-
|
|
4407
|
+
plugins.notify(me, 'destroy');
|
|
4492
4408
|
|
|
4493
4409
|
delete Chart.instances[me.id];
|
|
4494
4410
|
},
|
|
@@ -4508,10 +4424,48 @@ module.exports = function(Chart) {
|
|
|
4508
4424
|
me.tooltip.initialize();
|
|
4509
4425
|
},
|
|
4510
4426
|
|
|
4427
|
+
/**
|
|
4428
|
+
* @private
|
|
4429
|
+
*/
|
|
4511
4430
|
bindEvents: function() {
|
|
4512
4431
|
var me = this;
|
|
4513
|
-
|
|
4514
|
-
|
|
4432
|
+
var listeners = me._listeners = {};
|
|
4433
|
+
var listener = function() {
|
|
4434
|
+
me.eventHandler.apply(me, arguments);
|
|
4435
|
+
};
|
|
4436
|
+
|
|
4437
|
+
helpers.each(me.options.events, function(type) {
|
|
4438
|
+
platform.addEventListener(me, type, listener);
|
|
4439
|
+
listeners[type] = listener;
|
|
4440
|
+
});
|
|
4441
|
+
|
|
4442
|
+
// Responsiveness is currently based on the use of an iframe, however this method causes
|
|
4443
|
+
// performance issues and could be troublesome when used with ad blockers. So make sure
|
|
4444
|
+
// that the user is still able to create a chart without iframe when responsive is false.
|
|
4445
|
+
// See https://github.com/chartjs/Chart.js/issues/2210
|
|
4446
|
+
if (me.options.responsive) {
|
|
4447
|
+
listener = function() {
|
|
4448
|
+
me.resize();
|
|
4449
|
+
};
|
|
4450
|
+
|
|
4451
|
+
platform.addEventListener(me, 'resize', listener);
|
|
4452
|
+
listeners.resize = listener;
|
|
4453
|
+
}
|
|
4454
|
+
},
|
|
4455
|
+
|
|
4456
|
+
/**
|
|
4457
|
+
* @private
|
|
4458
|
+
*/
|
|
4459
|
+
unbindEvents: function() {
|
|
4460
|
+
var me = this;
|
|
4461
|
+
var listeners = me._listeners;
|
|
4462
|
+
if (!listeners) {
|
|
4463
|
+
return;
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
delete me._listeners;
|
|
4467
|
+
helpers.each(listeners, function(listener, type) {
|
|
4468
|
+
platform.removeEventListener(me, type, listener);
|
|
4515
4469
|
});
|
|
4516
4470
|
},
|
|
4517
4471
|
|
|
@@ -4527,20 +4481,26 @@ module.exports = function(Chart) {
|
|
|
4527
4481
|
}
|
|
4528
4482
|
},
|
|
4529
4483
|
|
|
4484
|
+
/**
|
|
4485
|
+
* @private
|
|
4486
|
+
*/
|
|
4530
4487
|
eventHandler: function(e) {
|
|
4531
4488
|
var me = this;
|
|
4532
|
-
var legend = me.legend;
|
|
4533
4489
|
var tooltip = me.tooltip;
|
|
4534
|
-
|
|
4490
|
+
|
|
4491
|
+
if (plugins.notify(me, 'beforeEvent', [e]) === false) {
|
|
4492
|
+
return;
|
|
4493
|
+
}
|
|
4535
4494
|
|
|
4536
4495
|
// Buffer any update calls so that renders do not occur
|
|
4537
4496
|
me._bufferedRender = true;
|
|
4538
4497
|
me._bufferedRequest = null;
|
|
4539
4498
|
|
|
4540
4499
|
var changed = me.handleEvent(e);
|
|
4541
|
-
changed |= legend && legend.handleEvent(e);
|
|
4542
4500
|
changed |= tooltip && tooltip.handleEvent(e);
|
|
4543
4501
|
|
|
4502
|
+
plugins.notify(me, 'afterEvent', [e]);
|
|
4503
|
+
|
|
4544
4504
|
var bufferedRequest = me._bufferedRequest;
|
|
4545
4505
|
if (bufferedRequest) {
|
|
4546
4506
|
// If we have an update that was triggered, we need to do a normal render
|
|
@@ -4551,7 +4511,7 @@ module.exports = function(Chart) {
|
|
|
4551
4511
|
|
|
4552
4512
|
// We only need to render at this point. Updating will cause scales to be
|
|
4553
4513
|
// recomputed generating flicker & using more memory than necessary.
|
|
4554
|
-
me.render(
|
|
4514
|
+
me.render(me.options.hover.animationDuration, true);
|
|
4555
4515
|
}
|
|
4556
4516
|
|
|
4557
4517
|
me._bufferedRender = false;
|
|
@@ -4563,7 +4523,7 @@ module.exports = function(Chart) {
|
|
|
4563
4523
|
/**
|
|
4564
4524
|
* Handle an event
|
|
4565
4525
|
* @private
|
|
4566
|
-
* param
|
|
4526
|
+
* @param {IEvent} event the event to handle
|
|
4567
4527
|
* @return {Boolean} true if the chart needs to re-render
|
|
4568
4528
|
*/
|
|
4569
4529
|
handleEvent: function(e) {
|
|
@@ -4583,12 +4543,14 @@ module.exports = function(Chart) {
|
|
|
4583
4543
|
|
|
4584
4544
|
// On Hover hook
|
|
4585
4545
|
if (hoverOptions.onHover) {
|
|
4586
|
-
|
|
4546
|
+
// Need to call with native event here to not break backwards compatibility
|
|
4547
|
+
hoverOptions.onHover.call(me, e.native, me.active);
|
|
4587
4548
|
}
|
|
4588
4549
|
|
|
4589
4550
|
if (e.type === 'mouseup' || e.type === 'click') {
|
|
4590
4551
|
if (options.onClick) {
|
|
4591
|
-
|
|
4552
|
+
// Use e.native here for backwards compatibility
|
|
4553
|
+
options.onClick.call(me, e.native, me.active);
|
|
4592
4554
|
}
|
|
4593
4555
|
}
|
|
4594
4556
|
|
|
@@ -5261,6 +5223,10 @@ module.exports = function(Chart) {
|
|
|
5261
5223
|
helpers.almostEquals = function(x, y, epsilon) {
|
|
5262
5224
|
return Math.abs(x - y) < epsilon;
|
|
5263
5225
|
};
|
|
5226
|
+
helpers.almostWhole = function(x, epsilon) {
|
|
5227
|
+
var rounded = Math.round(x);
|
|
5228
|
+
return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
|
|
5229
|
+
};
|
|
5264
5230
|
helpers.max = function(array) {
|
|
5265
5231
|
return array.reduce(function(max, value) {
|
|
5266
5232
|
if (!isNaN(value)) {
|
|
@@ -5385,7 +5351,10 @@ module.exports = function(Chart) {
|
|
|
5385
5351
|
pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
|
|
5386
5352
|
pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
|
|
5387
5353
|
if (pointAfter && !pointAfter.model.skip) {
|
|
5388
|
-
|
|
5354
|
+
var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
|
|
5355
|
+
|
|
5356
|
+
// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
|
|
5357
|
+
pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
|
|
5389
5358
|
}
|
|
5390
5359
|
|
|
5391
5360
|
if (!pointBefore || pointBefore.model.skip) {
|
|
@@ -5695,16 +5664,6 @@ module.exports = function(Chart) {
|
|
|
5695
5664
|
return window.setTimeout(callback, 1000 / 60);
|
|
5696
5665
|
};
|
|
5697
5666
|
}());
|
|
5698
|
-
helpers.cancelAnimFrame = (function() {
|
|
5699
|
-
return window.cancelAnimationFrame ||
|
|
5700
|
-
window.webkitCancelAnimationFrame ||
|
|
5701
|
-
window.mozCancelAnimationFrame ||
|
|
5702
|
-
window.oCancelAnimationFrame ||
|
|
5703
|
-
window.msCancelAnimationFrame ||
|
|
5704
|
-
function(callback) {
|
|
5705
|
-
return window.clearTimeout(callback, 1000 / 60);
|
|
5706
|
-
};
|
|
5707
|
-
}());
|
|
5708
5667
|
// -- DOM methods
|
|
5709
5668
|
helpers.getRelativePosition = function(evt, chart) {
|
|
5710
5669
|
var mouseX, mouseY;
|
|
@@ -5761,23 +5720,6 @@ module.exports = function(Chart) {
|
|
|
5761
5720
|
node['on' + eventType] = helpers.noop;
|
|
5762
5721
|
}
|
|
5763
5722
|
};
|
|
5764
|
-
helpers.bindEvents = function(chartInstance, arrayOfEvents, handler) {
|
|
5765
|
-
// Create the events object if it's not already present
|
|
5766
|
-
var events = chartInstance.events = chartInstance.events || {};
|
|
5767
|
-
|
|
5768
|
-
helpers.each(arrayOfEvents, function(eventName) {
|
|
5769
|
-
events[eventName] = function() {
|
|
5770
|
-
handler.apply(chartInstance, arguments);
|
|
5771
|
-
};
|
|
5772
|
-
helpers.addEvent(chartInstance.chart.canvas, eventName, events[eventName]);
|
|
5773
|
-
});
|
|
5774
|
-
};
|
|
5775
|
-
helpers.unbindEvents = function(chartInstance, arrayOfEvents) {
|
|
5776
|
-
var canvas = chartInstance.chart.canvas;
|
|
5777
|
-
helpers.each(arrayOfEvents, function(handler, eventName) {
|
|
5778
|
-
helpers.removeEvent(canvas, eventName, handler);
|
|
5779
|
-
});
|
|
5780
|
-
};
|
|
5781
5723
|
|
|
5782
5724
|
// Private helper function to convert max-width/max-height values that may be percentages into a number
|
|
5783
5725
|
function parseMaxStyle(styleValue, node, parentProperty) {
|
|
@@ -5968,73 +5910,6 @@ module.exports = function(Chart) {
|
|
|
5968
5910
|
|
|
5969
5911
|
return color(c);
|
|
5970
5912
|
};
|
|
5971
|
-
helpers.addResizeListener = function(node, callback) {
|
|
5972
|
-
var iframe = document.createElement('iframe');
|
|
5973
|
-
iframe.className = 'chartjs-hidden-iframe';
|
|
5974
|
-
iframe.style.cssText =
|
|
5975
|
-
'display:block;'+
|
|
5976
|
-
'overflow:hidden;'+
|
|
5977
|
-
'border:0;'+
|
|
5978
|
-
'margin:0;'+
|
|
5979
|
-
'top:0;'+
|
|
5980
|
-
'left:0;'+
|
|
5981
|
-
'bottom:0;'+
|
|
5982
|
-
'right:0;'+
|
|
5983
|
-
'height:100%;'+
|
|
5984
|
-
'width:100%;'+
|
|
5985
|
-
'position:absolute;'+
|
|
5986
|
-
'pointer-events:none;'+
|
|
5987
|
-
'z-index:-1;';
|
|
5988
|
-
|
|
5989
|
-
// Prevent the iframe to gain focus on tab.
|
|
5990
|
-
// https://github.com/chartjs/Chart.js/issues/3090
|
|
5991
|
-
iframe.tabIndex = -1;
|
|
5992
|
-
|
|
5993
|
-
// Let's keep track of this added iframe and thus avoid DOM query when removing it.
|
|
5994
|
-
var stub = node._chartjs = {
|
|
5995
|
-
resizer: iframe,
|
|
5996
|
-
ticking: false
|
|
5997
|
-
};
|
|
5998
|
-
|
|
5999
|
-
// Throttle the callback notification until the next animation frame.
|
|
6000
|
-
var notify = function() {
|
|
6001
|
-
if (!stub.ticking) {
|
|
6002
|
-
stub.ticking = true;
|
|
6003
|
-
helpers.requestAnimFrame.call(window, function() {
|
|
6004
|
-
if (stub.resizer) {
|
|
6005
|
-
stub.ticking = false;
|
|
6006
|
-
return callback();
|
|
6007
|
-
}
|
|
6008
|
-
});
|
|
6009
|
-
}
|
|
6010
|
-
};
|
|
6011
|
-
|
|
6012
|
-
// If the iframe is re-attached to the DOM, the resize listener is removed because the
|
|
6013
|
-
// content is reloaded, so make sure to install the handler after the iframe is loaded.
|
|
6014
|
-
// https://github.com/chartjs/Chart.js/issues/3521
|
|
6015
|
-
helpers.addEvent(iframe, 'load', function() {
|
|
6016
|
-
helpers.addEvent(iframe.contentWindow || iframe, 'resize', notify);
|
|
6017
|
-
|
|
6018
|
-
// The iframe size might have changed while loading, which can also
|
|
6019
|
-
// happen if the size has been changed while detached from the DOM.
|
|
6020
|
-
notify();
|
|
6021
|
-
});
|
|
6022
|
-
|
|
6023
|
-
node.insertBefore(iframe, node.firstChild);
|
|
6024
|
-
};
|
|
6025
|
-
helpers.removeResizeListener = function(node) {
|
|
6026
|
-
if (!node || !node._chartjs) {
|
|
6027
|
-
return;
|
|
6028
|
-
}
|
|
6029
|
-
|
|
6030
|
-
var iframe = node._chartjs.resizer;
|
|
6031
|
-
if (iframe) {
|
|
6032
|
-
iframe.parentNode.removeChild(iframe);
|
|
6033
|
-
node._chartjs.resizer = null;
|
|
6034
|
-
}
|
|
6035
|
-
|
|
6036
|
-
delete node._chartjs;
|
|
6037
|
-
};
|
|
6038
5913
|
helpers.isArray = Array.isArray?
|
|
6039
5914
|
function(obj) {
|
|
6040
5915
|
return Array.isArray(obj);
|
|
@@ -6085,6 +5960,23 @@ module.exports = function(Chart) {
|
|
|
6085
5960
|
module.exports = function(Chart) {
|
|
6086
5961
|
var helpers = Chart.helpers;
|
|
6087
5962
|
|
|
5963
|
+
/**
|
|
5964
|
+
* Helper function to get relative position for an event
|
|
5965
|
+
* @param {Event|IEvent} event - The event to get the position for
|
|
5966
|
+
* @param {Chart} chart - The chart
|
|
5967
|
+
* @returns {Point} the event position
|
|
5968
|
+
*/
|
|
5969
|
+
function getRelativePosition(e, chart) {
|
|
5970
|
+
if (e.native) {
|
|
5971
|
+
return {
|
|
5972
|
+
x: e.x,
|
|
5973
|
+
y: e.y
|
|
5974
|
+
};
|
|
5975
|
+
}
|
|
5976
|
+
|
|
5977
|
+
return helpers.getRelativePosition(e, chart);
|
|
5978
|
+
}
|
|
5979
|
+
|
|
6088
5980
|
/**
|
|
6089
5981
|
* Helper function to traverse all of the visible elements in the chart
|
|
6090
5982
|
* @param chart {chart} the chart
|
|
@@ -6164,7 +6056,7 @@ module.exports = function(Chart) {
|
|
|
6164
6056
|
}
|
|
6165
6057
|
|
|
6166
6058
|
function indexMode(chart, e, options) {
|
|
6167
|
-
var position =
|
|
6059
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6168
6060
|
var distanceMetric = function(pt1, pt2) {
|
|
6169
6061
|
return Math.abs(pt1.x - pt2.x);
|
|
6170
6062
|
};
|
|
@@ -6200,14 +6092,14 @@ module.exports = function(Chart) {
|
|
|
6200
6092
|
*/
|
|
6201
6093
|
|
|
6202
6094
|
/**
|
|
6203
|
-
* @namespace Chart.Interaction
|
|
6204
6095
|
* Contains interaction related functions
|
|
6096
|
+
* @namespace Chart.Interaction
|
|
6205
6097
|
*/
|
|
6206
6098
|
Chart.Interaction = {
|
|
6207
6099
|
// Helper function for different modes
|
|
6208
6100
|
modes: {
|
|
6209
6101
|
single: function(chart, e) {
|
|
6210
|
-
var position =
|
|
6102
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6211
6103
|
var elements = [];
|
|
6212
6104
|
|
|
6213
6105
|
parseVisibleItems(chart, function(element) {
|
|
@@ -6248,7 +6140,7 @@ module.exports = function(Chart) {
|
|
|
6248
6140
|
* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
|
|
6249
6141
|
*/
|
|
6250
6142
|
dataset: function(chart, e, options) {
|
|
6251
|
-
var position =
|
|
6143
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6252
6144
|
var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);
|
|
6253
6145
|
|
|
6254
6146
|
if (items.length > 0) {
|
|
@@ -6275,7 +6167,7 @@ module.exports = function(Chart) {
|
|
|
6275
6167
|
* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
|
|
6276
6168
|
*/
|
|
6277
6169
|
point: function(chart, e) {
|
|
6278
|
-
var position =
|
|
6170
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6279
6171
|
return getIntersectItems(chart, position);
|
|
6280
6172
|
},
|
|
6281
6173
|
|
|
@@ -6288,7 +6180,7 @@ module.exports = function(Chart) {
|
|
|
6288
6180
|
* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
|
|
6289
6181
|
*/
|
|
6290
6182
|
nearest: function(chart, e, options) {
|
|
6291
|
-
var position =
|
|
6183
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6292
6184
|
var nearestItems = getNearestItems(chart, position, options.intersect);
|
|
6293
6185
|
|
|
6294
6186
|
// We have multiple items at the same distance from the event. Now sort by smallest
|
|
@@ -6320,7 +6212,7 @@ module.exports = function(Chart) {
|
|
|
6320
6212
|
* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
|
|
6321
6213
|
*/
|
|
6322
6214
|
x: function(chart, e, options) {
|
|
6323
|
-
var position =
|
|
6215
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6324
6216
|
var items = [];
|
|
6325
6217
|
var intersectsItem = false;
|
|
6326
6218
|
|
|
@@ -6351,7 +6243,7 @@ module.exports = function(Chart) {
|
|
|
6351
6243
|
* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
|
|
6352
6244
|
*/
|
|
6353
6245
|
y: function(chart, e, options) {
|
|
6354
|
-
var position =
|
|
6246
|
+
var position = getRelativePosition(e, chart.chart);
|
|
6355
6247
|
var items = [];
|
|
6356
6248
|
var intersectsItem = false;
|
|
6357
6249
|
|
|
@@ -6585,15 +6477,36 @@ module.exports = function(Chart) {
|
|
|
6585
6477
|
minBoxSizes.push({
|
|
6586
6478
|
horizontal: isHorizontal,
|
|
6587
6479
|
minSize: minSize,
|
|
6588
|
-
box: box
|
|
6480
|
+
box: box,
|
|
6589
6481
|
});
|
|
6590
6482
|
}
|
|
6591
6483
|
|
|
6592
6484
|
helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
|
|
6593
6485
|
|
|
6486
|
+
// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
|
|
6487
|
+
var maxHorizontalLeftPadding = 0;
|
|
6488
|
+
var maxHorizontalRightPadding = 0;
|
|
6489
|
+
var maxVerticalTopPadding = 0;
|
|
6490
|
+
var maxVerticalBottomPadding = 0;
|
|
6491
|
+
|
|
6492
|
+
helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
|
|
6493
|
+
if (horizontalBox.getPadding) {
|
|
6494
|
+
var boxPadding = horizontalBox.getPadding();
|
|
6495
|
+
maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
|
|
6496
|
+
maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
|
|
6497
|
+
}
|
|
6498
|
+
});
|
|
6499
|
+
|
|
6500
|
+
helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
|
|
6501
|
+
if (verticalBox.getPadding) {
|
|
6502
|
+
var boxPadding = verticalBox.getPadding();
|
|
6503
|
+
maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
|
|
6504
|
+
maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
|
|
6505
|
+
}
|
|
6506
|
+
});
|
|
6507
|
+
|
|
6594
6508
|
// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
|
|
6595
6509
|
// be if the axes are drawn at their minimum sizes.
|
|
6596
|
-
|
|
6597
6510
|
// Steps 5 & 6
|
|
6598
6511
|
var totalLeftBoxesWidth = leftPadding;
|
|
6599
6512
|
var totalRightBoxesWidth = rightPadding;
|
|
@@ -6609,8 +6522,8 @@ module.exports = function(Chart) {
|
|
|
6609
6522
|
if (minBoxSize) {
|
|
6610
6523
|
if (box.isHorizontal()) {
|
|
6611
6524
|
var scaleMargin = {
|
|
6612
|
-
left: totalLeftBoxesWidth,
|
|
6613
|
-
right: totalRightBoxesWidth,
|
|
6525
|
+
left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
|
|
6526
|
+
right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
|
|
6614
6527
|
top: 0,
|
|
6615
6528
|
bottom: 0
|
|
6616
6529
|
};
|
|
@@ -6688,6 +6601,15 @@ module.exports = function(Chart) {
|
|
|
6688
6601
|
totalBottomBoxesHeight += box.height;
|
|
6689
6602
|
});
|
|
6690
6603
|
|
|
6604
|
+
// We may be adding some padding to account for rotated x axis labels
|
|
6605
|
+
var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
|
|
6606
|
+
totalLeftBoxesWidth += leftPaddingAddition;
|
|
6607
|
+
totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
|
|
6608
|
+
|
|
6609
|
+
var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
|
|
6610
|
+
totalTopBoxesHeight += topPaddingAddition;
|
|
6611
|
+
totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
|
|
6612
|
+
|
|
6691
6613
|
// Figure out if our chart area changed. This would occur if the dataset layout label rotation
|
|
6692
6614
|
// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
|
|
6693
6615
|
// without calling `fit` again
|
|
@@ -6720,8 +6642,8 @@ module.exports = function(Chart) {
|
|
|
6720
6642
|
}
|
|
6721
6643
|
|
|
6722
6644
|
// Step 7 - Position the boxes
|
|
6723
|
-
var left = leftPadding;
|
|
6724
|
-
var top = topPadding;
|
|
6645
|
+
var left = leftPadding + leftPaddingAddition;
|
|
6646
|
+
var top = topPadding + topPaddingAddition;
|
|
6725
6647
|
|
|
6726
6648
|
function placeBox(box) {
|
|
6727
6649
|
if (box.isHorizontal()) {
|
|
@@ -6940,10 +6862,20 @@ module.exports = function(Chart) {
|
|
|
6940
6862
|
beforeBuildLabels: noop,
|
|
6941
6863
|
buildLabels: function() {
|
|
6942
6864
|
var me = this;
|
|
6943
|
-
|
|
6865
|
+
var labelOpts = me.options.labels;
|
|
6866
|
+
var legendItems = labelOpts.generateLabels.call(me, me.chart);
|
|
6867
|
+
|
|
6868
|
+
if (labelOpts.filter) {
|
|
6869
|
+
legendItems = legendItems.filter(function(item) {
|
|
6870
|
+
return labelOpts.filter(item, me.chart.data);
|
|
6871
|
+
});
|
|
6872
|
+
}
|
|
6873
|
+
|
|
6944
6874
|
if (me.options.reverse) {
|
|
6945
|
-
|
|
6875
|
+
legendItems.reverse();
|
|
6946
6876
|
}
|
|
6877
|
+
|
|
6878
|
+
me.legendItems = legendItems;
|
|
6947
6879
|
},
|
|
6948
6880
|
afterBuildLabels: noop,
|
|
6949
6881
|
|
|
@@ -7182,7 +7114,7 @@ module.exports = function(Chart) {
|
|
|
7182
7114
|
}
|
|
7183
7115
|
} else if (y + itemHeight > me.bottom) {
|
|
7184
7116
|
x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
|
|
7185
|
-
y = cursor.y = me.top;
|
|
7117
|
+
y = cursor.y = me.top + labelOpts.padding;
|
|
7186
7118
|
cursor.line++;
|
|
7187
7119
|
}
|
|
7188
7120
|
|
|
@@ -7207,7 +7139,7 @@ module.exports = function(Chart) {
|
|
|
7207
7139
|
/**
|
|
7208
7140
|
* Handle an event
|
|
7209
7141
|
* @private
|
|
7210
|
-
* @param
|
|
7142
|
+
* @param {IEvent} event - The event to handle
|
|
7211
7143
|
* @return {Boolean} true if a change occured
|
|
7212
7144
|
*/
|
|
7213
7145
|
handleEvent: function(e) {
|
|
@@ -7228,9 +7160,9 @@ module.exports = function(Chart) {
|
|
|
7228
7160
|
return;
|
|
7229
7161
|
}
|
|
7230
7162
|
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
y =
|
|
7163
|
+
// Chart event already has relative position in it
|
|
7164
|
+
var x = e.x,
|
|
7165
|
+
y = e.y;
|
|
7234
7166
|
|
|
7235
7167
|
if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
|
|
7236
7168
|
// See if we are touching one of the dataset boxes
|
|
@@ -7241,11 +7173,13 @@ module.exports = function(Chart) {
|
|
|
7241
7173
|
if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
|
|
7242
7174
|
// Touching an element
|
|
7243
7175
|
if (type === 'click') {
|
|
7244
|
-
|
|
7176
|
+
// use e.native for backwards compatibility
|
|
7177
|
+
opts.onClick.call(me, e.native, me.legendItems[i]);
|
|
7245
7178
|
changed = true;
|
|
7246
7179
|
break;
|
|
7247
7180
|
} else if (type === 'mousemove') {
|
|
7248
|
-
|
|
7181
|
+
// use e.native for backwards compatibility
|
|
7182
|
+
opts.onHover.call(me, e.native, me.legendItems[i]);
|
|
7249
7183
|
changed = true;
|
|
7250
7184
|
break;
|
|
7251
7185
|
}
|
|
@@ -7257,20 +7191,45 @@ module.exports = function(Chart) {
|
|
|
7257
7191
|
}
|
|
7258
7192
|
});
|
|
7259
7193
|
|
|
7194
|
+
function createNewLegendAndAttach(chartInstance, legendOpts) {
|
|
7195
|
+
var legend = new Chart.Legend({
|
|
7196
|
+
ctx: chartInstance.chart.ctx,
|
|
7197
|
+
options: legendOpts,
|
|
7198
|
+
chart: chartInstance
|
|
7199
|
+
});
|
|
7200
|
+
chartInstance.legend = legend;
|
|
7201
|
+
Chart.layoutService.addBox(chartInstance, legend);
|
|
7202
|
+
}
|
|
7203
|
+
|
|
7260
7204
|
// Register the legend plugin
|
|
7261
7205
|
Chart.plugins.register({
|
|
7262
7206
|
beforeInit: function(chartInstance) {
|
|
7263
|
-
var
|
|
7264
|
-
var legendOpts = opts.legend;
|
|
7207
|
+
var legendOpts = chartInstance.options.legend;
|
|
7265
7208
|
|
|
7266
7209
|
if (legendOpts) {
|
|
7267
|
-
chartInstance
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7210
|
+
createNewLegendAndAttach(chartInstance, legendOpts);
|
|
7211
|
+
}
|
|
7212
|
+
},
|
|
7213
|
+
beforeUpdate: function(chartInstance) {
|
|
7214
|
+
var legendOpts = chartInstance.options.legend;
|
|
7272
7215
|
|
|
7273
|
-
|
|
7216
|
+
if (legendOpts) {
|
|
7217
|
+
legendOpts = helpers.configMerge(Chart.defaults.global.legend, legendOpts);
|
|
7218
|
+
|
|
7219
|
+
if (chartInstance.legend) {
|
|
7220
|
+
chartInstance.legend.options = legendOpts;
|
|
7221
|
+
} else {
|
|
7222
|
+
createNewLegendAndAttach(chartInstance, legendOpts);
|
|
7223
|
+
}
|
|
7224
|
+
} else {
|
|
7225
|
+
Chart.layoutService.removeBox(chartInstance, chartInstance.legend);
|
|
7226
|
+
delete chartInstance.legend;
|
|
7227
|
+
}
|
|
7228
|
+
},
|
|
7229
|
+
afterEvent: function(chartInstance, e) {
|
|
7230
|
+
var legend = chartInstance.legend;
|
|
7231
|
+
if (legend) {
|
|
7232
|
+
legend.handleEvent(e);
|
|
7274
7233
|
}
|
|
7275
7234
|
}
|
|
7276
7235
|
});
|
|
@@ -7281,7 +7240,9 @@ module.exports = function(Chart) {
|
|
|
7281
7240
|
|
|
7282
7241
|
module.exports = function(Chart) {
|
|
7283
7242
|
|
|
7284
|
-
var
|
|
7243
|
+
var helpers = Chart.helpers;
|
|
7244
|
+
|
|
7245
|
+
Chart.defaults.global.plugins = {};
|
|
7285
7246
|
|
|
7286
7247
|
/**
|
|
7287
7248
|
* The plugin service singleton
|
|
@@ -7289,8 +7250,20 @@ module.exports = function(Chart) {
|
|
|
7289
7250
|
* @since 2.1.0
|
|
7290
7251
|
*/
|
|
7291
7252
|
Chart.plugins = {
|
|
7253
|
+
/**
|
|
7254
|
+
* Globally registered plugins.
|
|
7255
|
+
* @private
|
|
7256
|
+
*/
|
|
7292
7257
|
_plugins: [],
|
|
7293
7258
|
|
|
7259
|
+
/**
|
|
7260
|
+
* This identifier is used to invalidate the descriptors cache attached to each chart
|
|
7261
|
+
* when a global plugin is registered or unregistered. In this case, the cache ID is
|
|
7262
|
+
* incremented and descriptors are regenerated during following API calls.
|
|
7263
|
+
* @private
|
|
7264
|
+
*/
|
|
7265
|
+
_cacheId: 0,
|
|
7266
|
+
|
|
7294
7267
|
/**
|
|
7295
7268
|
* Registers the given plugin(s) if not already registered.
|
|
7296
7269
|
* @param {Array|Object} plugins plugin instance(s).
|
|
@@ -7302,6 +7275,8 @@ module.exports = function(Chart) {
|
|
|
7302
7275
|
p.push(plugin);
|
|
7303
7276
|
}
|
|
7304
7277
|
});
|
|
7278
|
+
|
|
7279
|
+
this._cacheId++;
|
|
7305
7280
|
},
|
|
7306
7281
|
|
|
7307
7282
|
/**
|
|
@@ -7316,6 +7291,8 @@ module.exports = function(Chart) {
|
|
|
7316
7291
|
p.splice(idx, 1);
|
|
7317
7292
|
}
|
|
7318
7293
|
});
|
|
7294
|
+
|
|
7295
|
+
this._cacheId++;
|
|
7319
7296
|
},
|
|
7320
7297
|
|
|
7321
7298
|
/**
|
|
@@ -7324,6 +7301,7 @@ module.exports = function(Chart) {
|
|
|
7324
7301
|
*/
|
|
7325
7302
|
clear: function() {
|
|
7326
7303
|
this._plugins = [];
|
|
7304
|
+
this._cacheId++;
|
|
7327
7305
|
},
|
|
7328
7306
|
|
|
7329
7307
|
/**
|
|
@@ -7345,66 +7323,243 @@ module.exports = function(Chart) {
|
|
|
7345
7323
|
},
|
|
7346
7324
|
|
|
7347
7325
|
/**
|
|
7348
|
-
* Calls
|
|
7349
|
-
* method immediately returns as soon as a plugin explicitly returns false. The
|
|
7326
|
+
* Calls enabled plugins for `chart` on the specified hook and with the given args.
|
|
7327
|
+
* This method immediately returns as soon as a plugin explicitly returns false. The
|
|
7350
7328
|
* returned value can be used, for instance, to interrupt the current action.
|
|
7351
|
-
* @param {
|
|
7352
|
-
* @param {
|
|
7329
|
+
* @param {Object} chart - The chart instance for which plugins should be called.
|
|
7330
|
+
* @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
|
|
7331
|
+
* @param {Array} [args] - Extra arguments to apply to the hook call.
|
|
7353
7332
|
* @returns {Boolean} false if any of the plugins return false, else returns true.
|
|
7354
7333
|
*/
|
|
7355
|
-
notify: function(
|
|
7356
|
-
var
|
|
7357
|
-
var ilen =
|
|
7358
|
-
var i, plugin;
|
|
7334
|
+
notify: function(chart, hook, args) {
|
|
7335
|
+
var descriptors = this.descriptors(chart);
|
|
7336
|
+
var ilen = descriptors.length;
|
|
7337
|
+
var i, descriptor, plugin, params, method;
|
|
7359
7338
|
|
|
7360
7339
|
for (i=0; i<ilen; ++i) {
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7340
|
+
descriptor = descriptors[i];
|
|
7341
|
+
plugin = descriptor.plugin;
|
|
7342
|
+
method = plugin[hook];
|
|
7343
|
+
if (typeof method === 'function') {
|
|
7344
|
+
params = [chart].concat(args || []);
|
|
7345
|
+
params.push(descriptor.options);
|
|
7346
|
+
if (method.apply(plugin, params) === false) {
|
|
7364
7347
|
return false;
|
|
7365
7348
|
}
|
|
7366
7349
|
}
|
|
7367
7350
|
}
|
|
7368
7351
|
|
|
7369
7352
|
return true;
|
|
7370
|
-
}
|
|
7371
|
-
};
|
|
7353
|
+
},
|
|
7372
7354
|
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7355
|
+
/**
|
|
7356
|
+
* Returns descriptors of enabled plugins for the given chart.
|
|
7357
|
+
* @returns {Array} [{ plugin, options }]
|
|
7358
|
+
* @private
|
|
7359
|
+
*/
|
|
7360
|
+
descriptors: function(chart) {
|
|
7361
|
+
var cache = chart._plugins || (chart._plugins = {});
|
|
7362
|
+
if (cache.id === this._cacheId) {
|
|
7363
|
+
return cache.descriptors;
|
|
7364
|
+
}
|
|
7381
7365
|
|
|
7382
|
-
|
|
7383
|
-
|
|
7366
|
+
var plugins = [];
|
|
7367
|
+
var descriptors = [];
|
|
7368
|
+
var config = (chart && chart.config) || {};
|
|
7369
|
+
var defaults = Chart.defaults.global.plugins;
|
|
7370
|
+
var options = (config.options && config.options.plugins) || {};
|
|
7384
7371
|
|
|
7385
|
-
|
|
7386
|
-
|
|
7372
|
+
this._plugins.concat(config.plugins || []).forEach(function(plugin) {
|
|
7373
|
+
var idx = plugins.indexOf(plugin);
|
|
7374
|
+
if (idx !== -1) {
|
|
7375
|
+
return;
|
|
7376
|
+
}
|
|
7387
7377
|
|
|
7388
|
-
|
|
7389
|
-
|
|
7378
|
+
var id = plugin.id;
|
|
7379
|
+
var opts = options[id];
|
|
7380
|
+
if (opts === false) {
|
|
7381
|
+
return;
|
|
7382
|
+
}
|
|
7390
7383
|
|
|
7391
|
-
|
|
7392
|
-
|
|
7384
|
+
if (opts === true) {
|
|
7385
|
+
opts = helpers.clone(defaults[id]);
|
|
7386
|
+
}
|
|
7393
7387
|
|
|
7394
|
-
|
|
7395
|
-
|
|
7388
|
+
plugins.push(plugin);
|
|
7389
|
+
descriptors.push({
|
|
7390
|
+
plugin: plugin,
|
|
7391
|
+
options: opts || {}
|
|
7392
|
+
});
|
|
7393
|
+
});
|
|
7396
7394
|
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7395
|
+
cache.descriptors = descriptors;
|
|
7396
|
+
cache.id = this._cacheId;
|
|
7397
|
+
return descriptors;
|
|
7398
|
+
}
|
|
7399
|
+
};
|
|
7400
|
+
|
|
7401
|
+
/**
|
|
7402
|
+
* Plugin extension hooks.
|
|
7403
|
+
* @interface IPlugin
|
|
7404
|
+
* @since 2.1.0
|
|
7405
|
+
*/
|
|
7406
|
+
/**
|
|
7407
|
+
* @method IPlugin#beforeInit
|
|
7408
|
+
* @desc Called before initializing `chart`.
|
|
7409
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7410
|
+
* @param {Object} options - The plugin options.
|
|
7411
|
+
*/
|
|
7412
|
+
/**
|
|
7413
|
+
* @method IPlugin#afterInit
|
|
7414
|
+
* @desc Called after `chart` has been initialized and before the first update.
|
|
7415
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7416
|
+
* @param {Object} options - The plugin options.
|
|
7417
|
+
*/
|
|
7418
|
+
/**
|
|
7419
|
+
* @method IPlugin#beforeUpdate
|
|
7420
|
+
* @desc Called before updating `chart`. If any plugin returns `false`, the update
|
|
7421
|
+
* is cancelled (and thus subsequent render(s)) until another `update` is triggered.
|
|
7422
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7423
|
+
* @param {Object} options - The plugin options.
|
|
7424
|
+
* @returns {Boolean} `false` to cancel the chart update.
|
|
7425
|
+
*/
|
|
7426
|
+
/**
|
|
7427
|
+
* @method IPlugin#afterUpdate
|
|
7428
|
+
* @desc Called after `chart` has been updated and before rendering. Note that this
|
|
7429
|
+
* hook will not be called if the chart update has been previously cancelled.
|
|
7430
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7431
|
+
* @param {Object} options - The plugin options.
|
|
7432
|
+
*/
|
|
7433
|
+
/**
|
|
7434
|
+
* @method IPlugin#beforeDatasetsUpdate
|
|
7435
|
+
* @desc Called before updating the `chart` datasets. If any plugin returns `false`,
|
|
7436
|
+
* the datasets update is cancelled until another `update` is triggered.
|
|
7437
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7438
|
+
* @param {Object} options - The plugin options.
|
|
7439
|
+
* @returns {Boolean} false to cancel the datasets update.
|
|
7440
|
+
* @since version 2.1.5
|
|
7441
|
+
*/
|
|
7442
|
+
/**
|
|
7443
|
+
* @method IPlugin#afterDatasetsUpdate
|
|
7444
|
+
* @desc Called after the `chart` datasets have been updated. Note that this hook
|
|
7445
|
+
* will not be called if the datasets update has been previously cancelled.
|
|
7446
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7447
|
+
* @param {Object} options - The plugin options.
|
|
7448
|
+
* @since version 2.1.5
|
|
7449
|
+
*/
|
|
7450
|
+
/**
|
|
7451
|
+
* @method IPlugin#beforeLayout
|
|
7452
|
+
* @desc Called before laying out `chart`. If any plugin returns `false`,
|
|
7453
|
+
* the layout update is cancelled until another `update` is triggered.
|
|
7454
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7455
|
+
* @param {Object} options - The plugin options.
|
|
7456
|
+
* @returns {Boolean} `false` to cancel the chart layout.
|
|
7457
|
+
*/
|
|
7458
|
+
/**
|
|
7459
|
+
* @method IPlugin#afterLayout
|
|
7460
|
+
* @desc Called after the `chart` has been layed out. Note that this hook will not
|
|
7461
|
+
* be called if the layout update has been previously cancelled.
|
|
7462
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7463
|
+
* @param {Object} options - The plugin options.
|
|
7464
|
+
*/
|
|
7465
|
+
/**
|
|
7466
|
+
* @method IPlugin#beforeRender
|
|
7467
|
+
* @desc Called before rendering `chart`. If any plugin returns `false`,
|
|
7468
|
+
* the rendering is cancelled until another `render` is triggered.
|
|
7469
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7470
|
+
* @param {Object} options - The plugin options.
|
|
7471
|
+
* @returns {Boolean} `false` to cancel the chart rendering.
|
|
7472
|
+
*/
|
|
7473
|
+
/**
|
|
7474
|
+
* @method IPlugin#afterRender
|
|
7475
|
+
* @desc Called after the `chart` has been fully rendered (and animation completed). Note
|
|
7476
|
+
* that this hook will not be called if the rendering has been previously cancelled.
|
|
7477
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7478
|
+
* @param {Object} options - The plugin options.
|
|
7479
|
+
*/
|
|
7480
|
+
/**
|
|
7481
|
+
* @method IPlugin#beforeDraw
|
|
7482
|
+
* @desc Called before drawing `chart` at every animation frame specified by the given
|
|
7483
|
+
* easing value. If any plugin returns `false`, the frame drawing is cancelled until
|
|
7484
|
+
* another `render` is triggered.
|
|
7485
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7486
|
+
* @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
|
|
7487
|
+
* @param {Object} options - The plugin options.
|
|
7488
|
+
* @returns {Boolean} `false` to cancel the chart drawing.
|
|
7489
|
+
*/
|
|
7490
|
+
/**
|
|
7491
|
+
* @method IPlugin#afterDraw
|
|
7492
|
+
* @desc Called after the `chart` has been drawn for the specific easing value. Note
|
|
7493
|
+
* that this hook will not be called if the drawing has been previously cancelled.
|
|
7494
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7495
|
+
* @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
|
|
7496
|
+
* @param {Object} options - The plugin options.
|
|
7497
|
+
*/
|
|
7498
|
+
/**
|
|
7499
|
+
* @method IPlugin#beforeDatasetsDraw
|
|
7500
|
+
* @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
|
|
7501
|
+
* the datasets drawing is cancelled until another `render` is triggered.
|
|
7502
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7503
|
+
* @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
|
|
7504
|
+
* @param {Object} options - The plugin options.
|
|
7505
|
+
* @returns {Boolean} `false` to cancel the chart datasets drawing.
|
|
7506
|
+
*/
|
|
7507
|
+
/**
|
|
7508
|
+
* @method IPlugin#afterDatasetsDraw
|
|
7509
|
+
* @desc Called after the `chart` datasets have been drawn. Note that this hook
|
|
7510
|
+
* will not be called if the datasets drawing has been previously cancelled.
|
|
7511
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7512
|
+
* @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
|
|
7513
|
+
* @param {Object} options - The plugin options.
|
|
7514
|
+
*/
|
|
7515
|
+
/**
|
|
7516
|
+
* @method IPlugin#beforeEvent
|
|
7517
|
+
* @desc Called before processing the specified `event`. If any plugin returns `false`,
|
|
7518
|
+
* the event will be discarded.
|
|
7519
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7520
|
+
* @param {IEvent} event - The event object.
|
|
7521
|
+
* @param {Object} options - The plugin options.
|
|
7522
|
+
*/
|
|
7523
|
+
/**
|
|
7524
|
+
* @method IPlugin#afterEvent
|
|
7525
|
+
* @desc Called after the `event` has been consumed. Note that this hook
|
|
7526
|
+
* will not be called if the `event` has been previously discarded.
|
|
7527
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7528
|
+
* @param {IEvent} event - The event object.
|
|
7529
|
+
* @param {Object} options - The plugin options.
|
|
7530
|
+
*/
|
|
7531
|
+
/**
|
|
7532
|
+
* @method IPlugin#resize
|
|
7533
|
+
* @desc Called after the chart as been resized.
|
|
7534
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7535
|
+
* @param {Number} size - The new canvas display size (eq. canvas.style width & height).
|
|
7536
|
+
* @param {Object} options - The plugin options.
|
|
7537
|
+
*/
|
|
7538
|
+
/**
|
|
7539
|
+
* @method IPlugin#destroy
|
|
7540
|
+
* @desc Called after the chart as been destroyed.
|
|
7541
|
+
* @param {Chart.Controller} chart - The chart instance.
|
|
7542
|
+
* @param {Object} options - The plugin options.
|
|
7543
|
+
*/
|
|
7400
7544
|
|
|
7401
7545
|
/**
|
|
7402
7546
|
* Provided for backward compatibility, use Chart.plugins instead
|
|
7403
7547
|
* @namespace Chart.pluginService
|
|
7404
7548
|
* @deprecated since version 2.1.5
|
|
7405
|
-
* @todo remove
|
|
7549
|
+
* @todo remove at version 3
|
|
7550
|
+
* @private
|
|
7406
7551
|
*/
|
|
7407
7552
|
Chart.pluginService = Chart.plugins;
|
|
7553
|
+
|
|
7554
|
+
/**
|
|
7555
|
+
* Provided for backward compatibility, inheriting from Chart.PlugingBase has no
|
|
7556
|
+
* effect, instead simply create/register plugins via plain JavaScript objects.
|
|
7557
|
+
* @interface Chart.PluginBase
|
|
7558
|
+
* @deprecated since version 2.5.0
|
|
7559
|
+
* @todo remove at version 3
|
|
7560
|
+
* @private
|
|
7561
|
+
*/
|
|
7562
|
+
Chart.PluginBase = helpers.inherits({});
|
|
7408
7563
|
};
|
|
7409
7564
|
|
|
7410
7565
|
},{}],32:[function(require,module,exports){
|
|
@@ -7449,7 +7604,7 @@ module.exports = function(Chart) {
|
|
|
7449
7604
|
minRotation: 0,
|
|
7450
7605
|
maxRotation: 50,
|
|
7451
7606
|
mirror: false,
|
|
7452
|
-
padding:
|
|
7607
|
+
padding: 0,
|
|
7453
7608
|
reverse: false,
|
|
7454
7609
|
display: true,
|
|
7455
7610
|
autoSkip: true,
|
|
@@ -7460,9 +7615,45 @@ module.exports = function(Chart) {
|
|
|
7460
7615
|
}
|
|
7461
7616
|
};
|
|
7462
7617
|
|
|
7618
|
+
function computeTextSize(context, tick, font) {
|
|
7619
|
+
return helpers.isArray(tick) ?
|
|
7620
|
+
helpers.longestText(context, font, tick) :
|
|
7621
|
+
context.measureText(tick).width;
|
|
7622
|
+
}
|
|
7623
|
+
|
|
7624
|
+
function parseFontOptions(options) {
|
|
7625
|
+
var getValueOrDefault = helpers.getValueOrDefault;
|
|
7626
|
+
var globalDefaults = Chart.defaults.global;
|
|
7627
|
+
var size = getValueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
|
|
7628
|
+
var style = getValueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
|
|
7629
|
+
var family = getValueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
|
|
7630
|
+
|
|
7631
|
+
return {
|
|
7632
|
+
size: size,
|
|
7633
|
+
style: style,
|
|
7634
|
+
family: family,
|
|
7635
|
+
font: helpers.fontString(size, style, family)
|
|
7636
|
+
};
|
|
7637
|
+
}
|
|
7638
|
+
|
|
7463
7639
|
Chart.Scale = Chart.Element.extend({
|
|
7640
|
+
/**
|
|
7641
|
+
* Get the padding needed for the scale
|
|
7642
|
+
* @method getPadding
|
|
7643
|
+
* @private
|
|
7644
|
+
* @returns {Padding} the necessary padding
|
|
7645
|
+
*/
|
|
7646
|
+
getPadding: function() {
|
|
7647
|
+
var me = this;
|
|
7648
|
+
return {
|
|
7649
|
+
left: me.paddingLeft || 0,
|
|
7650
|
+
top: me.paddingTop || 0,
|
|
7651
|
+
right: me.paddingRight || 0,
|
|
7652
|
+
bottom: me.paddingBottom || 0
|
|
7653
|
+
};
|
|
7654
|
+
},
|
|
7464
7655
|
|
|
7465
|
-
// These methods are ordered by
|
|
7656
|
+
// These methods are ordered by lifecyle. Utilities then follow.
|
|
7466
7657
|
// Any function defined here is inherited by all scale types.
|
|
7467
7658
|
// Any function can be extended by the scale type
|
|
7468
7659
|
|
|
@@ -7484,6 +7675,7 @@ module.exports = function(Chart) {
|
|
|
7484
7675
|
top: 0,
|
|
7485
7676
|
bottom: 0
|
|
7486
7677
|
}, margins);
|
|
7678
|
+
me.longestTextCache = me.longestTextCache || {};
|
|
7487
7679
|
|
|
7488
7680
|
// Dimensions
|
|
7489
7681
|
me.beforeSetDimensions();
|
|
@@ -7592,72 +7784,42 @@ module.exports = function(Chart) {
|
|
|
7592
7784
|
calculateTickRotation: function() {
|
|
7593
7785
|
var me = this;
|
|
7594
7786
|
var context = me.ctx;
|
|
7595
|
-
var
|
|
7596
|
-
var optionTicks = me.options.ticks;
|
|
7787
|
+
var tickOpts = me.options.ticks;
|
|
7597
7788
|
|
|
7598
7789
|
// Get the width of each grid by calculating the difference
|
|
7599
7790
|
// between x offsets between 0 and 1.
|
|
7600
|
-
var
|
|
7601
|
-
|
|
7602
|
-
var tickFontFamily = helpers.getValueOrDefault(optionTicks.fontFamily, globalDefaults.defaultFontFamily);
|
|
7603
|
-
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
|
7604
|
-
context.font = tickLabelFont;
|
|
7791
|
+
var tickFont = parseFontOptions(tickOpts);
|
|
7792
|
+
context.font = tickFont.font;
|
|
7605
7793
|
|
|
7606
|
-
var
|
|
7607
|
-
var lastWidth = context.measureText(me.ticks[me.ticks.length - 1]).width;
|
|
7608
|
-
var firstRotated;
|
|
7794
|
+
var labelRotation = tickOpts.minRotation || 0;
|
|
7609
7795
|
|
|
7610
|
-
me.
|
|
7611
|
-
|
|
7612
|
-
|
|
7796
|
+
if (me.options.display && me.isHorizontal()) {
|
|
7797
|
+
var originalLabelWidth = helpers.longestText(context, tickFont.font, me.ticks, me.longestTextCache);
|
|
7798
|
+
var labelWidth = originalLabelWidth;
|
|
7799
|
+
var cosRotation;
|
|
7800
|
+
var sinRotation;
|
|
7613
7801
|
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
me.paddingRight = lastWidth / 2 + 3;
|
|
7617
|
-
me.paddingLeft = firstWidth / 2 + 3;
|
|
7802
|
+
// Allow 3 pixels x2 padding either side for label readability
|
|
7803
|
+
var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
|
|
7618
7804
|
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
var cosRotation;
|
|
7625
|
-
var sinRotation;
|
|
7626
|
-
|
|
7627
|
-
// Allow 3 pixels x2 padding either side for label readability
|
|
7628
|
-
// only the index matters for a dataset scale, but we want a consistent interface between scales
|
|
7629
|
-
var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
|
|
7630
|
-
|
|
7631
|
-
// Max label rotation can be set or default to 90 - also act as a loop counter
|
|
7632
|
-
while (labelWidth > tickWidth && me.labelRotation < optionTicks.maxRotation) {
|
|
7633
|
-
cosRotation = Math.cos(helpers.toRadians(me.labelRotation));
|
|
7634
|
-
sinRotation = Math.sin(helpers.toRadians(me.labelRotation));
|
|
7635
|
-
|
|
7636
|
-
firstRotated = cosRotation * firstWidth;
|
|
7637
|
-
|
|
7638
|
-
// We're right aligning the text now.
|
|
7639
|
-
if (firstRotated + tickFontSize / 2 > me.yLabelWidth) {
|
|
7640
|
-
me.paddingLeft = firstRotated + tickFontSize / 2;
|
|
7641
|
-
}
|
|
7642
|
-
|
|
7643
|
-
me.paddingRight = tickFontSize / 2;
|
|
7644
|
-
|
|
7645
|
-
if (sinRotation * originalLabelWidth > me.maxHeight) {
|
|
7646
|
-
// go back one step
|
|
7647
|
-
me.labelRotation--;
|
|
7648
|
-
break;
|
|
7649
|
-
}
|
|
7805
|
+
// Max label rotation can be set or default to 90 - also act as a loop counter
|
|
7806
|
+
while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
|
|
7807
|
+
var angleRadians = helpers.toRadians(labelRotation);
|
|
7808
|
+
cosRotation = Math.cos(angleRadians);
|
|
7809
|
+
sinRotation = Math.sin(angleRadians);
|
|
7650
7810
|
|
|
7651
|
-
|
|
7652
|
-
|
|
7811
|
+
if (sinRotation * originalLabelWidth > me.maxHeight) {
|
|
7812
|
+
// go back one step
|
|
7813
|
+
labelRotation--;
|
|
7814
|
+
break;
|
|
7653
7815
|
}
|
|
7816
|
+
|
|
7817
|
+
labelRotation++;
|
|
7818
|
+
labelWidth = cosRotation * originalLabelWidth;
|
|
7654
7819
|
}
|
|
7655
7820
|
}
|
|
7656
7821
|
|
|
7657
|
-
|
|
7658
|
-
me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
|
|
7659
|
-
me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
|
|
7660
|
-
}
|
|
7822
|
+
me.labelRotation = labelRotation;
|
|
7661
7823
|
},
|
|
7662
7824
|
afterCalculateTickRotation: function() {
|
|
7663
7825
|
helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
|
|
@@ -7677,20 +7839,14 @@ module.exports = function(Chart) {
|
|
|
7677
7839
|
};
|
|
7678
7840
|
|
|
7679
7841
|
var opts = me.options;
|
|
7680
|
-
var globalDefaults = Chart.defaults.global;
|
|
7681
7842
|
var tickOpts = opts.ticks;
|
|
7682
7843
|
var scaleLabelOpts = opts.scaleLabel;
|
|
7683
7844
|
var gridLineOpts = opts.gridLines;
|
|
7684
7845
|
var display = opts.display;
|
|
7685
7846
|
var isHorizontal = me.isHorizontal();
|
|
7686
7847
|
|
|
7687
|
-
var
|
|
7688
|
-
var
|
|
7689
|
-
var tickFontFamily = helpers.getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
|
|
7690
|
-
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
|
7691
|
-
|
|
7692
|
-
var scaleLabelFontSize = helpers.getValueOrDefault(scaleLabelOpts.fontSize, globalDefaults.defaultFontSize);
|
|
7693
|
-
|
|
7848
|
+
var tickFont = parseFontOptions(tickOpts);
|
|
7849
|
+
var scaleLabelFontSize = parseFontOptions(scaleLabelOpts).size * 1.5;
|
|
7694
7850
|
var tickMarkLength = opts.gridLines.tickMarkLength;
|
|
7695
7851
|
|
|
7696
7852
|
// Width
|
|
@@ -7711,78 +7867,84 @@ module.exports = function(Chart) {
|
|
|
7711
7867
|
// Are we showing a title for the scale?
|
|
7712
7868
|
if (scaleLabelOpts.display && display) {
|
|
7713
7869
|
if (isHorizontal) {
|
|
7714
|
-
minSize.height +=
|
|
7870
|
+
minSize.height += scaleLabelFontSize;
|
|
7715
7871
|
} else {
|
|
7716
|
-
minSize.width +=
|
|
7872
|
+
minSize.width += scaleLabelFontSize;
|
|
7717
7873
|
}
|
|
7718
7874
|
}
|
|
7719
7875
|
|
|
7876
|
+
// Don't bother fitting the ticks if we are not showing them
|
|
7720
7877
|
if (tickOpts.display && display) {
|
|
7721
|
-
|
|
7722
|
-
if (!me.longestTextCache) {
|
|
7723
|
-
me.longestTextCache = {};
|
|
7724
|
-
}
|
|
7725
|
-
|
|
7726
|
-
var largestTextWidth = helpers.longestText(me.ctx, tickLabelFont, me.ticks, me.longestTextCache);
|
|
7878
|
+
var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, me.ticks, me.longestTextCache);
|
|
7727
7879
|
var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
|
|
7728
|
-
var lineSpace =
|
|
7880
|
+
var lineSpace = tickFont.size * 0.5;
|
|
7729
7881
|
|
|
7730
7882
|
if (isHorizontal) {
|
|
7731
7883
|
// A horizontal axis is more constrained by the height.
|
|
7732
7884
|
me.longestLabelWidth = largestTextWidth;
|
|
7733
7885
|
|
|
7886
|
+
var angleRadians = helpers.toRadians(me.labelRotation);
|
|
7887
|
+
var cosRotation = Math.cos(angleRadians);
|
|
7888
|
+
var sinRotation = Math.sin(angleRadians);
|
|
7889
|
+
|
|
7734
7890
|
// TODO - improve this calculation
|
|
7735
|
-
var labelHeight = (
|
|
7891
|
+
var labelHeight = (sinRotation * largestTextWidth)
|
|
7892
|
+
+ (tickFont.size * tallestLabelHeightInLines)
|
|
7893
|
+
+ (lineSpace * tallestLabelHeightInLines);
|
|
7736
7894
|
|
|
7737
7895
|
minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
|
|
7738
|
-
me.ctx.font =
|
|
7896
|
+
me.ctx.font = tickFont.font;
|
|
7739
7897
|
|
|
7740
|
-
var
|
|
7741
|
-
var
|
|
7898
|
+
var firstTick = me.ticks[0];
|
|
7899
|
+
var firstLabelWidth = computeTextSize(me.ctx, firstTick, tickFont.font);
|
|
7900
|
+
|
|
7901
|
+
var lastTick = me.ticks[me.ticks.length - 1];
|
|
7902
|
+
var lastLabelWidth = computeTextSize(me.ctx, lastTick, tickFont.font);
|
|
7742
7903
|
|
|
7743
7904
|
// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
|
|
7744
7905
|
// by the font height
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7906
|
+
if (me.labelRotation !== 0) {
|
|
7907
|
+
me.paddingLeft = opts.position === 'bottom'? (cosRotation * firstLabelWidth) + 3: (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
|
|
7908
|
+
me.paddingRight = opts.position === 'bottom'? (cosRotation * lineSpace) + 3: (cosRotation * lastLabelWidth) + 3;
|
|
7909
|
+
} else {
|
|
7910
|
+
me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
|
|
7911
|
+
me.paddingRight = lastLabelWidth / 2 + 3;
|
|
7912
|
+
}
|
|
7749
7913
|
} else {
|
|
7750
7914
|
// A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
|
|
7751
|
-
var maxLabelWidth = me.maxWidth - minSize.width;
|
|
7752
|
-
|
|
7753
7915
|
// Account for padding
|
|
7754
|
-
var mirror = tickOpts.mirror;
|
|
7755
|
-
if (!mirror) {
|
|
7756
|
-
largestTextWidth += me.options.ticks.padding;
|
|
7757
|
-
} else {
|
|
7758
|
-
// If mirrored text is on the inside so don't expand
|
|
7759
|
-
largestTextWidth = 0;
|
|
7760
|
-
}
|
|
7761
7916
|
|
|
7762
|
-
if (
|
|
7763
|
-
|
|
7764
|
-
minSize.width += largestTextWidth;
|
|
7917
|
+
if (tickOpts.mirror) {
|
|
7918
|
+
largestTextWidth = 0;
|
|
7765
7919
|
} else {
|
|
7766
|
-
|
|
7767
|
-
minSize.width = me.maxWidth;
|
|
7920
|
+
largestTextWidth += me.options.ticks.padding;
|
|
7768
7921
|
}
|
|
7769
|
-
|
|
7770
|
-
me.paddingTop =
|
|
7771
|
-
me.paddingBottom =
|
|
7922
|
+
minSize.width += largestTextWidth;
|
|
7923
|
+
me.paddingTop = tickFont.size / 2;
|
|
7924
|
+
me.paddingBottom = tickFont.size / 2;
|
|
7772
7925
|
}
|
|
7773
7926
|
}
|
|
7774
7927
|
|
|
7928
|
+
me.handleMargins();
|
|
7929
|
+
|
|
7930
|
+
me.width = minSize.width;
|
|
7931
|
+
me.height = minSize.height;
|
|
7932
|
+
},
|
|
7933
|
+
|
|
7934
|
+
/**
|
|
7935
|
+
* Handle margins and padding interactions
|
|
7936
|
+
* @private
|
|
7937
|
+
*/
|
|
7938
|
+
handleMargins: function() {
|
|
7939
|
+
var me = this;
|
|
7775
7940
|
if (me.margins) {
|
|
7776
7941
|
me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
|
|
7777
7942
|
me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
|
|
7778
7943
|
me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
|
|
7779
7944
|
me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
|
|
7780
7945
|
}
|
|
7781
|
-
|
|
7782
|
-
me.width = minSize.width;
|
|
7783
|
-
me.height = minSize.height;
|
|
7784
|
-
|
|
7785
7946
|
},
|
|
7947
|
+
|
|
7786
7948
|
afterFit: function() {
|
|
7787
7949
|
helpers.callCallback(this.options.afterFit, [this]);
|
|
7788
7950
|
},
|
|
@@ -7862,15 +8024,18 @@ module.exports = function(Chart) {
|
|
|
7862
8024
|
},
|
|
7863
8025
|
|
|
7864
8026
|
getBasePixel: function() {
|
|
8027
|
+
return this.getPixelForValue(this.getBaseValue());
|
|
8028
|
+
},
|
|
8029
|
+
|
|
8030
|
+
getBaseValue: function() {
|
|
7865
8031
|
var me = this;
|
|
7866
8032
|
var min = me.min;
|
|
7867
8033
|
var max = me.max;
|
|
7868
8034
|
|
|
7869
|
-
return me.
|
|
7870
|
-
me.beginAtZero? 0:
|
|
8035
|
+
return me.beginAtZero ? 0:
|
|
7871
8036
|
min < 0 && max < 0? max :
|
|
7872
8037
|
min > 0 && max > 0? min :
|
|
7873
|
-
0
|
|
8038
|
+
0;
|
|
7874
8039
|
},
|
|
7875
8040
|
|
|
7876
8041
|
// Actually draw the scale on the canvas
|
|
@@ -7900,19 +8065,14 @@ module.exports = function(Chart) {
|
|
|
7900
8065
|
}
|
|
7901
8066
|
|
|
7902
8067
|
var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
|
|
7903
|
-
var
|
|
7904
|
-
|
|
7905
|
-
var
|
|
7906
|
-
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
|
7907
|
-
var tl = gridLines.tickMarkLength;
|
|
8068
|
+
var tickFont = parseFontOptions(optionTicks);
|
|
8069
|
+
|
|
8070
|
+
var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
|
|
7908
8071
|
var borderDash = helpers.getValueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
|
|
7909
8072
|
var borderDashOffset = helpers.getValueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
|
|
7910
8073
|
|
|
7911
8074
|
var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
|
|
7912
|
-
var
|
|
7913
|
-
var scaleLabelFontStyle = helpers.getValueOrDefault(scaleLabel.fontStyle, globalDefaults.defaultFontStyle);
|
|
7914
|
-
var scaleLabelFontFamily = helpers.getValueOrDefault(scaleLabel.fontFamily, globalDefaults.defaultFontFamily);
|
|
7915
|
-
var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
|
|
8075
|
+
var scaleLabelFont = parseFontOptions(scaleLabel);
|
|
7916
8076
|
|
|
7917
8077
|
var labelRotationRadians = helpers.toRadians(me.labelRotation);
|
|
7918
8078
|
var cosRotation = Math.cos(labelRotationRadians);
|
|
@@ -7988,15 +8148,21 @@ module.exports = function(Chart) {
|
|
|
7988
8148
|
var textBaseline = 'middle';
|
|
7989
8149
|
|
|
7990
8150
|
if (isHorizontal) {
|
|
7991
|
-
if (!isRotated) {
|
|
7992
|
-
textBaseline = options.position === 'top' ? 'bottom' : 'top';
|
|
7993
|
-
}
|
|
7994
8151
|
|
|
7995
|
-
|
|
8152
|
+
if (options.position === 'bottom') {
|
|
8153
|
+
// bottom
|
|
8154
|
+
textBaseline = !isRotated? 'top':'middle';
|
|
8155
|
+
textAlign = !isRotated? 'center': 'right';
|
|
8156
|
+
labelY = me.top + tl;
|
|
8157
|
+
} else {
|
|
8158
|
+
// top
|
|
8159
|
+
textBaseline = !isRotated? 'bottom':'middle';
|
|
8160
|
+
textAlign = !isRotated? 'center': 'left';
|
|
8161
|
+
labelY = me.bottom - tl;
|
|
8162
|
+
}
|
|
7996
8163
|
|
|
7997
8164
|
var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines
|
|
7998
8165
|
labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
|
|
7999
|
-
labelY = (isRotated) ? me.top + 12 : options.position === 'top' ? me.bottom - tl : me.top + tl;
|
|
8000
8166
|
|
|
8001
8167
|
tx1 = tx2 = x1 = x2 = xLineValue;
|
|
8002
8168
|
ty1 = yTickStart;
|
|
@@ -8004,23 +8170,20 @@ module.exports = function(Chart) {
|
|
|
8004
8170
|
y1 = chartArea.top;
|
|
8005
8171
|
y2 = chartArea.bottom;
|
|
8006
8172
|
} else {
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
}
|
|
8015
|
-
// right side
|
|
8016
|
-
} else if (optionTicks.mirror) {
|
|
8017
|
-
labelX = me.left - optionTicks.padding;
|
|
8018
|
-
textAlign = 'right';
|
|
8173
|
+
var isLeft = options.position === 'left';
|
|
8174
|
+
var tickPadding = optionTicks.padding;
|
|
8175
|
+
var labelXOffset;
|
|
8176
|
+
|
|
8177
|
+
if (optionTicks.mirror) {
|
|
8178
|
+
textAlign = isLeft ? 'left' : 'right';
|
|
8179
|
+
labelXOffset = tickPadding;
|
|
8019
8180
|
} else {
|
|
8020
|
-
|
|
8021
|
-
|
|
8181
|
+
textAlign = isLeft ? 'right' : 'left';
|
|
8182
|
+
labelXOffset = tl + tickPadding;
|
|
8022
8183
|
}
|
|
8023
8184
|
|
|
8185
|
+
labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
|
|
8186
|
+
|
|
8024
8187
|
var yLineValue = me.getPixelForTick(index); // xvalues for grid lines
|
|
8025
8188
|
yLineValue += helpers.aliasPixel(lineWidth);
|
|
8026
8189
|
labelY = me.getPixelForTick(index, gridLines.offsetGridLines);
|
|
@@ -8085,17 +8248,17 @@ module.exports = function(Chart) {
|
|
|
8085
8248
|
context.save();
|
|
8086
8249
|
context.translate(itemToDraw.labelX, itemToDraw.labelY);
|
|
8087
8250
|
context.rotate(itemToDraw.rotation);
|
|
8088
|
-
context.font =
|
|
8251
|
+
context.font = tickFont.font;
|
|
8089
8252
|
context.textBaseline = itemToDraw.textBaseline;
|
|
8090
8253
|
context.textAlign = itemToDraw.textAlign;
|
|
8091
8254
|
|
|
8092
8255
|
var label = itemToDraw.label;
|
|
8093
8256
|
if (helpers.isArray(label)) {
|
|
8094
|
-
for (var i = 0, y =
|
|
8257
|
+
for (var i = 0, y = 0; i < label.length; ++i) {
|
|
8095
8258
|
// We just make sure the multiline element is a string here..
|
|
8096
8259
|
context.fillText('' + label[i], 0, y);
|
|
8097
8260
|
// apply same lineSpacing as calculated @ L#320
|
|
8098
|
-
y += (
|
|
8261
|
+
y += (tickFont.size * 1.5);
|
|
8099
8262
|
}
|
|
8100
8263
|
} else {
|
|
8101
8264
|
context.fillText(label, 0, 0);
|
|
@@ -8112,10 +8275,10 @@ module.exports = function(Chart) {
|
|
|
8112
8275
|
|
|
8113
8276
|
if (isHorizontal) {
|
|
8114
8277
|
scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
|
|
8115
|
-
scaleLabelY = options.position === 'bottom' ? me.bottom - (
|
|
8278
|
+
scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFont.size / 2) : me.top + (scaleLabelFont.size / 2);
|
|
8116
8279
|
} else {
|
|
8117
8280
|
var isLeft = options.position === 'left';
|
|
8118
|
-
scaleLabelX = isLeft ? me.left + (
|
|
8281
|
+
scaleLabelX = isLeft ? me.left + (scaleLabelFont.size / 2) : me.right - (scaleLabelFont.size / 2);
|
|
8119
8282
|
scaleLabelY = me.top + ((me.bottom - me.top) / 2);
|
|
8120
8283
|
rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
|
|
8121
8284
|
}
|
|
@@ -8126,7 +8289,7 @@ module.exports = function(Chart) {
|
|
|
8126
8289
|
context.textAlign = 'center';
|
|
8127
8290
|
context.textBaseline = 'middle';
|
|
8128
8291
|
context.fillStyle = scaleLabelFontColor; // render in correct colour
|
|
8129
|
-
context.font = scaleLabelFont;
|
|
8292
|
+
context.font = scaleLabelFont.font;
|
|
8130
8293
|
context.fillText(scaleLabel.labelString, 0, 0);
|
|
8131
8294
|
context.restore();
|
|
8132
8295
|
}
|
|
@@ -8272,8 +8435,8 @@ module.exports = function(Chart) {
|
|
|
8272
8435
|
|
|
8273
8436
|
// If min, max and stepSize is set and they make an evenly spaced scale use it.
|
|
8274
8437
|
if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
|
|
8275
|
-
|
|
8276
|
-
if (
|
|
8438
|
+
// If very close to our whole number, use it.
|
|
8439
|
+
if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
|
|
8277
8440
|
niceMin = generationOptions.min;
|
|
8278
8441
|
niceMax = generationOptions.max;
|
|
8279
8442
|
}
|
|
@@ -8314,27 +8477,33 @@ module.exports = function(Chart) {
|
|
|
8314
8477
|
// the graph
|
|
8315
8478
|
var tickVal = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
|
|
8316
8479
|
|
|
8317
|
-
|
|
8318
|
-
|
|
8480
|
+
var endExp = Math.floor(helpers.log10(dataRange.max));
|
|
8481
|
+
var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
|
|
8482
|
+
var exp;
|
|
8483
|
+
var significand;
|
|
8319
8484
|
|
|
8320
|
-
|
|
8321
|
-
|
|
8485
|
+
if (tickVal === 0) {
|
|
8486
|
+
exp = Math.floor(helpers.log10(dataRange.minNotZero));
|
|
8487
|
+
significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
|
|
8322
8488
|
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8489
|
+
ticks.push(tickVal);
|
|
8490
|
+
tickVal = significand * Math.pow(10, exp);
|
|
8491
|
+
} else {
|
|
8492
|
+
exp = Math.floor(helpers.log10(tickVal));
|
|
8493
|
+
significand = Math.floor(tickVal / Math.pow(10, exp));
|
|
8494
|
+
}
|
|
8495
|
+
|
|
8496
|
+
do {
|
|
8497
|
+
ticks.push(tickVal);
|
|
8330
8498
|
|
|
8499
|
+
++significand;
|
|
8331
8500
|
if (significand === 10) {
|
|
8332
8501
|
significand = 1;
|
|
8333
8502
|
++exp;
|
|
8334
8503
|
}
|
|
8335
8504
|
|
|
8336
8505
|
tickVal = significand * Math.pow(10, exp);
|
|
8337
|
-
}
|
|
8506
|
+
} while (exp < endExp || (exp === endExp && significand < endSignificand));
|
|
8338
8507
|
|
|
8339
8508
|
var lastTick = getValueOrDefault(generationOptions.max, tickVal);
|
|
8340
8509
|
ticks.push(lastTick);
|
|
@@ -8431,7 +8600,6 @@ module.exports = function(Chart) {
|
|
|
8431
8600
|
initialize: function(config) {
|
|
8432
8601
|
var me = this;
|
|
8433
8602
|
helpers.extend(me, config);
|
|
8434
|
-
me.options = helpers.configMerge(Chart.defaults.global.title, config.options);
|
|
8435
8603
|
|
|
8436
8604
|
// Contains hit boxes for each dataset (in dataset order)
|
|
8437
8605
|
me.legendHitBoxes = [];
|
|
@@ -8439,12 +8607,7 @@ module.exports = function(Chart) {
|
|
|
8439
8607
|
|
|
8440
8608
|
// These methods are ordered by lifecycle. Utilities then follow.
|
|
8441
8609
|
|
|
8442
|
-
beforeUpdate:
|
|
8443
|
-
var chartOpts = this.chart.options;
|
|
8444
|
-
if (chartOpts && chartOpts.title) {
|
|
8445
|
-
this.options = helpers.configMerge(Chart.defaults.global.title, chartOpts.title);
|
|
8446
|
-
}
|
|
8447
|
-
},
|
|
8610
|
+
beforeUpdate: noop,
|
|
8448
8611
|
update: function(maxWidth, maxHeight, margins) {
|
|
8449
8612
|
var me = this;
|
|
8450
8613
|
|
|
@@ -8596,20 +8759,39 @@ module.exports = function(Chart) {
|
|
|
8596
8759
|
}
|
|
8597
8760
|
});
|
|
8598
8761
|
|
|
8762
|
+
function createNewTitleBlockAndAttach(chartInstance, titleOpts) {
|
|
8763
|
+
var title = new Chart.Title({
|
|
8764
|
+
ctx: chartInstance.chart.ctx,
|
|
8765
|
+
options: titleOpts,
|
|
8766
|
+
chart: chartInstance
|
|
8767
|
+
});
|
|
8768
|
+
chartInstance.titleBlock = title;
|
|
8769
|
+
Chart.layoutService.addBox(chartInstance, title);
|
|
8770
|
+
}
|
|
8771
|
+
|
|
8599
8772
|
// Register the title plugin
|
|
8600
8773
|
Chart.plugins.register({
|
|
8601
8774
|
beforeInit: function(chartInstance) {
|
|
8602
|
-
var
|
|
8603
|
-
var titleOpts = opts.title;
|
|
8775
|
+
var titleOpts = chartInstance.options.title;
|
|
8604
8776
|
|
|
8605
8777
|
if (titleOpts) {
|
|
8606
|
-
chartInstance
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8778
|
+
createNewTitleBlockAndAttach(chartInstance, titleOpts);
|
|
8779
|
+
}
|
|
8780
|
+
},
|
|
8781
|
+
beforeUpdate: function(chartInstance) {
|
|
8782
|
+
var titleOpts = chartInstance.options.title;
|
|
8611
8783
|
|
|
8612
|
-
|
|
8784
|
+
if (titleOpts) {
|
|
8785
|
+
titleOpts = helpers.configMerge(Chart.defaults.global.title, titleOpts);
|
|
8786
|
+
|
|
8787
|
+
if (chartInstance.titleBlock) {
|
|
8788
|
+
chartInstance.titleBlock.options = titleOpts;
|
|
8789
|
+
} else {
|
|
8790
|
+
createNewTitleBlockAndAttach(chartInstance, titleOpts);
|
|
8791
|
+
}
|
|
8792
|
+
} else {
|
|
8793
|
+
Chart.layoutService.removeBox(chartInstance, chartInstance.titleBlock);
|
|
8794
|
+
delete chartInstance.titleBlock;
|
|
8613
8795
|
}
|
|
8614
8796
|
}
|
|
8615
8797
|
});
|
|
@@ -9381,7 +9563,7 @@ module.exports = function(Chart) {
|
|
|
9381
9563
|
/**
|
|
9382
9564
|
* Handle an event
|
|
9383
9565
|
* @private
|
|
9384
|
-
* @param
|
|
9566
|
+
* @param {IEvent} event - The event to handle
|
|
9385
9567
|
* @returns {Boolean} true if the tooltip changed
|
|
9386
9568
|
*/
|
|
9387
9569
|
handleEvent: function(e) {
|
|
@@ -9403,7 +9585,10 @@ module.exports = function(Chart) {
|
|
|
9403
9585
|
me._lastActive = me._active;
|
|
9404
9586
|
|
|
9405
9587
|
if (options.enabled || options.custom) {
|
|
9406
|
-
me._eventPosition =
|
|
9588
|
+
me._eventPosition = {
|
|
9589
|
+
x: e.x,
|
|
9590
|
+
y: e.y
|
|
9591
|
+
};
|
|
9407
9592
|
|
|
9408
9593
|
var model = me._model;
|
|
9409
9594
|
me.update(true);
|
|
@@ -9845,13 +10030,17 @@ module.exports = function(Chart) {
|
|
|
9845
10030
|
padding: vm.radius + vm.borderWidth
|
|
9846
10031
|
};
|
|
9847
10032
|
},
|
|
9848
|
-
draw: function() {
|
|
10033
|
+
draw: function(chartArea) {
|
|
9849
10034
|
var vm = this._view;
|
|
10035
|
+
var model = this._model;
|
|
9850
10036
|
var ctx = this._chart.ctx;
|
|
9851
10037
|
var pointStyle = vm.pointStyle;
|
|
9852
10038
|
var radius = vm.radius;
|
|
9853
10039
|
var x = vm.x;
|
|
9854
10040
|
var y = vm.y;
|
|
10041
|
+
var color = Chart.helpers.color;
|
|
10042
|
+
var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
|
|
10043
|
+
var ratio = 0;
|
|
9855
10044
|
|
|
9856
10045
|
if (vm.skip) {
|
|
9857
10046
|
return;
|
|
@@ -9861,6 +10050,24 @@ module.exports = function(Chart) {
|
|
|
9861
10050
|
ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
|
|
9862
10051
|
ctx.fillStyle = vm.backgroundColor || defaultColor;
|
|
9863
10052
|
|
|
10053
|
+
// Cliping for Points.
|
|
10054
|
+
// going out from inner charArea?
|
|
10055
|
+
if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right*errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom*errMargin < model.y))) {
|
|
10056
|
+
// Point fade out
|
|
10057
|
+
if (model.x < chartArea.left) {
|
|
10058
|
+
ratio = (x - model.x) / (chartArea.left - model.x);
|
|
10059
|
+
} else if (chartArea.right*errMargin < model.x) {
|
|
10060
|
+
ratio = (model.x - x) / (model.x - chartArea.right);
|
|
10061
|
+
} else if (model.y < chartArea.top) {
|
|
10062
|
+
ratio = (y - model.y) / (chartArea.top - model.y);
|
|
10063
|
+
} else if (chartArea.bottom*errMargin < model.y) {
|
|
10064
|
+
ratio = (model.y - y) / (model.y - chartArea.bottom);
|
|
10065
|
+
}
|
|
10066
|
+
ratio = Math.round(ratio*100) / 100;
|
|
10067
|
+
ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
|
|
10068
|
+
ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
|
|
10069
|
+
}
|
|
10070
|
+
|
|
9864
10071
|
Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
|
|
9865
10072
|
}
|
|
9866
10073
|
});
|
|
@@ -9922,39 +10129,71 @@ module.exports = function(Chart) {
|
|
|
9922
10129
|
draw: function() {
|
|
9923
10130
|
var ctx = this._chart.ctx;
|
|
9924
10131
|
var vm = this._view;
|
|
9925
|
-
|
|
9926
|
-
var
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
10132
|
+
var left, right, top, bottom, signX, signY, borderSkipped;
|
|
10133
|
+
var borderWidth = vm.borderWidth;
|
|
10134
|
+
|
|
10135
|
+
if (!vm.horizontal) {
|
|
10136
|
+
// bar
|
|
10137
|
+
left = vm.x - vm.width / 2;
|
|
10138
|
+
right = vm.x + vm.width / 2;
|
|
10139
|
+
top = vm.y;
|
|
10140
|
+
bottom = vm.base;
|
|
10141
|
+
signX = 1;
|
|
10142
|
+
signY = bottom > top? 1: -1;
|
|
10143
|
+
borderSkipped = vm.borderSkipped || 'bottom';
|
|
10144
|
+
} else {
|
|
10145
|
+
// horizontal bar
|
|
10146
|
+
left = vm.base;
|
|
10147
|
+
right = vm.x;
|
|
10148
|
+
top = vm.y - vm.height / 2;
|
|
10149
|
+
bottom = vm.y + vm.height / 2;
|
|
10150
|
+
signX = right > left? 1: -1;
|
|
10151
|
+
signY = 1;
|
|
10152
|
+
borderSkipped = vm.borderSkipped || 'left';
|
|
10153
|
+
}
|
|
9931
10154
|
|
|
9932
10155
|
// Canvas doesn't allow us to stroke inside the width so we can
|
|
9933
10156
|
// adjust the sizes to fit if we're setting a stroke on the line
|
|
9934
|
-
if (
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
10157
|
+
if (borderWidth) {
|
|
10158
|
+
// borderWidth shold be less than bar width and bar height.
|
|
10159
|
+
var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
|
|
10160
|
+
borderWidth = borderWidth > barSize? barSize: borderWidth;
|
|
10161
|
+
var halfStroke = borderWidth / 2;
|
|
10162
|
+
// Adjust borderWidth when bar top position is near vm.base(zero).
|
|
10163
|
+
var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
|
|
10164
|
+
var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
|
|
10165
|
+
var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
|
|
10166
|
+
var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
|
|
10167
|
+
// not become a vertical line?
|
|
10168
|
+
if (borderLeft !== borderRight) {
|
|
10169
|
+
top = borderTop;
|
|
10170
|
+
bottom = borderBottom;
|
|
10171
|
+
}
|
|
10172
|
+
// not become a horizontal line?
|
|
10173
|
+
if (borderTop !== borderBottom) {
|
|
10174
|
+
left = borderLeft;
|
|
10175
|
+
right = borderRight;
|
|
10176
|
+
}
|
|
9938
10177
|
}
|
|
9939
10178
|
|
|
9940
10179
|
ctx.beginPath();
|
|
9941
10180
|
ctx.fillStyle = vm.backgroundColor;
|
|
9942
10181
|
ctx.strokeStyle = vm.borderColor;
|
|
9943
|
-
ctx.lineWidth =
|
|
10182
|
+
ctx.lineWidth = borderWidth;
|
|
9944
10183
|
|
|
9945
10184
|
// Corner points, from bottom-left to bottom-right clockwise
|
|
9946
10185
|
// | 1 2 |
|
|
9947
10186
|
// | 0 3 |
|
|
9948
10187
|
var corners = [
|
|
9949
|
-
[
|
|
9950
|
-
[
|
|
9951
|
-
[
|
|
9952
|
-
[
|
|
10188
|
+
[left, bottom],
|
|
10189
|
+
[left, top],
|
|
10190
|
+
[right, top],
|
|
10191
|
+
[right, bottom]
|
|
9953
10192
|
];
|
|
9954
10193
|
|
|
9955
10194
|
// Find first (starting) corner with fallback to 'bottom'
|
|
9956
10195
|
var borders = ['bottom', 'left', 'top', 'right'];
|
|
9957
|
-
var startCorner = borders.indexOf(
|
|
10196
|
+
var startCorner = borders.indexOf(borderSkipped, 0);
|
|
9958
10197
|
if (startCorner === -1) {
|
|
9959
10198
|
startCorner = 0;
|
|
9960
10199
|
}
|
|
@@ -9973,7 +10212,7 @@ module.exports = function(Chart) {
|
|
|
9973
10212
|
}
|
|
9974
10213
|
|
|
9975
10214
|
ctx.fill();
|
|
9976
|
-
if (
|
|
10215
|
+
if (borderWidth) {
|
|
9977
10216
|
ctx.stroke();
|
|
9978
10217
|
}
|
|
9979
10218
|
},
|
|
@@ -10047,6 +10286,356 @@ module.exports = function(Chart) {
|
|
|
10047
10286
|
},{}],41:[function(require,module,exports){
|
|
10048
10287
|
'use strict';
|
|
10049
10288
|
|
|
10289
|
+
// Chart.Platform implementation for targeting a web browser
|
|
10290
|
+
module.exports = function(Chart) {
|
|
10291
|
+
var helpers = Chart.helpers;
|
|
10292
|
+
|
|
10293
|
+
// DOM event types -> Chart.js event types.
|
|
10294
|
+
// Note: only events with different types are mapped.
|
|
10295
|
+
// https://developer.mozilla.org/en-US/docs/Web/Events
|
|
10296
|
+
var eventTypeMap = {
|
|
10297
|
+
// Touch events
|
|
10298
|
+
touchstart: 'mousedown',
|
|
10299
|
+
touchmove: 'mousemove',
|
|
10300
|
+
touchend: 'mouseup',
|
|
10301
|
+
|
|
10302
|
+
// Pointer events
|
|
10303
|
+
pointerenter: 'mouseenter',
|
|
10304
|
+
pointerdown: 'mousedown',
|
|
10305
|
+
pointermove: 'mousemove',
|
|
10306
|
+
pointerup: 'mouseup',
|
|
10307
|
+
pointerleave: 'mouseout',
|
|
10308
|
+
pointerout: 'mouseout'
|
|
10309
|
+
};
|
|
10310
|
+
|
|
10311
|
+
/**
|
|
10312
|
+
* The "used" size is the final value of a dimension property after all calculations have
|
|
10313
|
+
* been performed. This method uses the computed style of `element` but returns undefined
|
|
10314
|
+
* if the computed style is not expressed in pixels. That can happen in some cases where
|
|
10315
|
+
* `element` has a size relative to its parent and this last one is not yet displayed,
|
|
10316
|
+
* for example because of `display: none` on a parent node.
|
|
10317
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
|
|
10318
|
+
* @returns {Number} Size in pixels or undefined if unknown.
|
|
10319
|
+
*/
|
|
10320
|
+
function readUsedSize(element, property) {
|
|
10321
|
+
var value = helpers.getStyle(element, property);
|
|
10322
|
+
var matches = value && value.match(/(\d+)px/);
|
|
10323
|
+
return matches? Number(matches[1]) : undefined;
|
|
10324
|
+
}
|
|
10325
|
+
|
|
10326
|
+
/**
|
|
10327
|
+
* Initializes the canvas style and render size without modifying the canvas display size,
|
|
10328
|
+
* since responsiveness is handled by the controller.resize() method. The config is used
|
|
10329
|
+
* to determine the aspect ratio to apply in case no explicit height has been specified.
|
|
10330
|
+
*/
|
|
10331
|
+
function initCanvas(canvas, config) {
|
|
10332
|
+
var style = canvas.style;
|
|
10333
|
+
|
|
10334
|
+
// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
|
|
10335
|
+
// returns null or '' if no explicit value has been set to the canvas attribute.
|
|
10336
|
+
var renderHeight = canvas.getAttribute('height');
|
|
10337
|
+
var renderWidth = canvas.getAttribute('width');
|
|
10338
|
+
|
|
10339
|
+
// Chart.js modifies some canvas values that we want to restore on destroy
|
|
10340
|
+
canvas._chartjs = {
|
|
10341
|
+
initial: {
|
|
10342
|
+
height: renderHeight,
|
|
10343
|
+
width: renderWidth,
|
|
10344
|
+
style: {
|
|
10345
|
+
display: style.display,
|
|
10346
|
+
height: style.height,
|
|
10347
|
+
width: style.width
|
|
10348
|
+
}
|
|
10349
|
+
}
|
|
10350
|
+
};
|
|
10351
|
+
|
|
10352
|
+
// Force canvas to display as block to avoid extra space caused by inline
|
|
10353
|
+
// elements, which would interfere with the responsive resize process.
|
|
10354
|
+
// https://github.com/chartjs/Chart.js/issues/2538
|
|
10355
|
+
style.display = style.display || 'block';
|
|
10356
|
+
|
|
10357
|
+
if (renderWidth === null || renderWidth === '') {
|
|
10358
|
+
var displayWidth = readUsedSize(canvas, 'width');
|
|
10359
|
+
if (displayWidth !== undefined) {
|
|
10360
|
+
canvas.width = displayWidth;
|
|
10361
|
+
}
|
|
10362
|
+
}
|
|
10363
|
+
|
|
10364
|
+
if (renderHeight === null || renderHeight === '') {
|
|
10365
|
+
if (canvas.style.height === '') {
|
|
10366
|
+
// If no explicit render height and style height, let's apply the aspect ratio,
|
|
10367
|
+
// which one can be specified by the user but also by charts as default option
|
|
10368
|
+
// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
|
|
10369
|
+
canvas.height = canvas.width / (config.options.aspectRatio || 2);
|
|
10370
|
+
} else {
|
|
10371
|
+
var displayHeight = readUsedSize(canvas, 'height');
|
|
10372
|
+
if (displayWidth !== undefined) {
|
|
10373
|
+
canvas.height = displayHeight;
|
|
10374
|
+
}
|
|
10375
|
+
}
|
|
10376
|
+
}
|
|
10377
|
+
|
|
10378
|
+
return canvas;
|
|
10379
|
+
}
|
|
10380
|
+
|
|
10381
|
+
function createEvent(type, chart, x, y, native) {
|
|
10382
|
+
return {
|
|
10383
|
+
type: type,
|
|
10384
|
+
chart: chart,
|
|
10385
|
+
native: native || null,
|
|
10386
|
+
x: x !== undefined? x : null,
|
|
10387
|
+
y: y !== undefined? y : null,
|
|
10388
|
+
};
|
|
10389
|
+
}
|
|
10390
|
+
|
|
10391
|
+
function fromNativeEvent(event, chart) {
|
|
10392
|
+
var type = eventTypeMap[event.type] || event.type;
|
|
10393
|
+
var pos = helpers.getRelativePosition(event, chart);
|
|
10394
|
+
return createEvent(type, chart, pos.x, pos.y, event);
|
|
10395
|
+
}
|
|
10396
|
+
|
|
10397
|
+
function createResizer(handler) {
|
|
10398
|
+
var iframe = document.createElement('iframe');
|
|
10399
|
+
iframe.className = 'chartjs-hidden-iframe';
|
|
10400
|
+
iframe.style.cssText =
|
|
10401
|
+
'display:block;'+
|
|
10402
|
+
'overflow:hidden;'+
|
|
10403
|
+
'border:0;'+
|
|
10404
|
+
'margin:0;'+
|
|
10405
|
+
'top:0;'+
|
|
10406
|
+
'left:0;'+
|
|
10407
|
+
'bottom:0;'+
|
|
10408
|
+
'right:0;'+
|
|
10409
|
+
'height:100%;'+
|
|
10410
|
+
'width:100%;'+
|
|
10411
|
+
'position:absolute;'+
|
|
10412
|
+
'pointer-events:none;'+
|
|
10413
|
+
'z-index:-1;';
|
|
10414
|
+
|
|
10415
|
+
// Prevent the iframe to gain focus on tab.
|
|
10416
|
+
// https://github.com/chartjs/Chart.js/issues/3090
|
|
10417
|
+
iframe.tabIndex = -1;
|
|
10418
|
+
|
|
10419
|
+
// If the iframe is re-attached to the DOM, the resize listener is removed because the
|
|
10420
|
+
// content is reloaded, so make sure to install the handler after the iframe is loaded.
|
|
10421
|
+
// https://github.com/chartjs/Chart.js/issues/3521
|
|
10422
|
+
helpers.addEvent(iframe, 'load', function() {
|
|
10423
|
+
helpers.addEvent(iframe.contentWindow || iframe, 'resize', handler);
|
|
10424
|
+
|
|
10425
|
+
// The iframe size might have changed while loading, which can also
|
|
10426
|
+
// happen if the size has been changed while detached from the DOM.
|
|
10427
|
+
handler();
|
|
10428
|
+
});
|
|
10429
|
+
|
|
10430
|
+
return iframe;
|
|
10431
|
+
}
|
|
10432
|
+
|
|
10433
|
+
function addResizeListener(node, listener, chart) {
|
|
10434
|
+
var stub = node._chartjs = {
|
|
10435
|
+
ticking: false
|
|
10436
|
+
};
|
|
10437
|
+
|
|
10438
|
+
// Throttle the callback notification until the next animation frame.
|
|
10439
|
+
var notify = function() {
|
|
10440
|
+
if (!stub.ticking) {
|
|
10441
|
+
stub.ticking = true;
|
|
10442
|
+
helpers.requestAnimFrame.call(window, function() {
|
|
10443
|
+
if (stub.resizer) {
|
|
10444
|
+
stub.ticking = false;
|
|
10445
|
+
return listener(createEvent('resize', chart));
|
|
10446
|
+
}
|
|
10447
|
+
});
|
|
10448
|
+
}
|
|
10449
|
+
};
|
|
10450
|
+
|
|
10451
|
+
// Let's keep track of this added iframe and thus avoid DOM query when removing it.
|
|
10452
|
+
stub.resizer = createResizer(notify);
|
|
10453
|
+
|
|
10454
|
+
node.insertBefore(stub.resizer, node.firstChild);
|
|
10455
|
+
}
|
|
10456
|
+
|
|
10457
|
+
function removeResizeListener(node) {
|
|
10458
|
+
if (!node || !node._chartjs) {
|
|
10459
|
+
return;
|
|
10460
|
+
}
|
|
10461
|
+
|
|
10462
|
+
var resizer = node._chartjs.resizer;
|
|
10463
|
+
if (resizer) {
|
|
10464
|
+
resizer.parentNode.removeChild(resizer);
|
|
10465
|
+
node._chartjs.resizer = null;
|
|
10466
|
+
}
|
|
10467
|
+
|
|
10468
|
+
delete node._chartjs;
|
|
10469
|
+
}
|
|
10470
|
+
|
|
10471
|
+
return {
|
|
10472
|
+
acquireContext: function(item, config) {
|
|
10473
|
+
if (typeof item === 'string') {
|
|
10474
|
+
item = document.getElementById(item);
|
|
10475
|
+
} else if (item.length) {
|
|
10476
|
+
// Support for array based queries (such as jQuery)
|
|
10477
|
+
item = item[0];
|
|
10478
|
+
}
|
|
10479
|
+
|
|
10480
|
+
if (item && item.canvas) {
|
|
10481
|
+
// Support for any object associated to a canvas (including a context2d)
|
|
10482
|
+
item = item.canvas;
|
|
10483
|
+
}
|
|
10484
|
+
|
|
10485
|
+
if (item instanceof HTMLCanvasElement) {
|
|
10486
|
+
// To prevent canvas fingerprinting, some add-ons undefine the getContext
|
|
10487
|
+
// method, for example: https://github.com/kkapsner/CanvasBlocker
|
|
10488
|
+
// https://github.com/chartjs/Chart.js/issues/2807
|
|
10489
|
+
var context = item.getContext && item.getContext('2d');
|
|
10490
|
+
if (context instanceof CanvasRenderingContext2D) {
|
|
10491
|
+
initCanvas(item, config);
|
|
10492
|
+
return context;
|
|
10493
|
+
}
|
|
10494
|
+
}
|
|
10495
|
+
|
|
10496
|
+
return null;
|
|
10497
|
+
},
|
|
10498
|
+
|
|
10499
|
+
releaseContext: function(context) {
|
|
10500
|
+
var canvas = context.canvas;
|
|
10501
|
+
if (!canvas._chartjs) {
|
|
10502
|
+
return;
|
|
10503
|
+
}
|
|
10504
|
+
|
|
10505
|
+
var initial = canvas._chartjs.initial;
|
|
10506
|
+
['height', 'width'].forEach(function(prop) {
|
|
10507
|
+
var value = initial[prop];
|
|
10508
|
+
if (value === undefined || value === null) {
|
|
10509
|
+
canvas.removeAttribute(prop);
|
|
10510
|
+
} else {
|
|
10511
|
+
canvas.setAttribute(prop, value);
|
|
10512
|
+
}
|
|
10513
|
+
});
|
|
10514
|
+
|
|
10515
|
+
helpers.each(initial.style || {}, function(value, key) {
|
|
10516
|
+
canvas.style[key] = value;
|
|
10517
|
+
});
|
|
10518
|
+
|
|
10519
|
+
// The canvas render size might have been changed (and thus the state stack discarded),
|
|
10520
|
+
// we can't use save() and restore() to restore the initial state. So make sure that at
|
|
10521
|
+
// least the canvas context is reset to the default state by setting the canvas width.
|
|
10522
|
+
// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
|
|
10523
|
+
canvas.width = canvas.width;
|
|
10524
|
+
|
|
10525
|
+
delete canvas._chartjs;
|
|
10526
|
+
},
|
|
10527
|
+
|
|
10528
|
+
addEventListener: function(chart, type, listener) {
|
|
10529
|
+
var canvas = chart.chart.canvas;
|
|
10530
|
+
if (type === 'resize') {
|
|
10531
|
+
// Note: the resize event is not supported on all browsers.
|
|
10532
|
+
addResizeListener(canvas.parentNode, listener, chart.chart);
|
|
10533
|
+
return;
|
|
10534
|
+
}
|
|
10535
|
+
|
|
10536
|
+
var stub = listener._chartjs || (listener._chartjs = {});
|
|
10537
|
+
var proxies = stub.proxies || (stub.proxies = {});
|
|
10538
|
+
var proxy = proxies[chart.id + '_' + type] = function(event) {
|
|
10539
|
+
listener(fromNativeEvent(event, chart.chart));
|
|
10540
|
+
};
|
|
10541
|
+
|
|
10542
|
+
helpers.addEvent(canvas, type, proxy);
|
|
10543
|
+
},
|
|
10544
|
+
|
|
10545
|
+
removeEventListener: function(chart, type, listener) {
|
|
10546
|
+
var canvas = chart.chart.canvas;
|
|
10547
|
+
if (type === 'resize') {
|
|
10548
|
+
// Note: the resize event is not supported on all browsers.
|
|
10549
|
+
removeResizeListener(canvas.parentNode, listener);
|
|
10550
|
+
return;
|
|
10551
|
+
}
|
|
10552
|
+
|
|
10553
|
+
var stub = listener._chartjs || {};
|
|
10554
|
+
var proxies = stub.proxies || {};
|
|
10555
|
+
var proxy = proxies[chart.id + '_' + type];
|
|
10556
|
+
if (!proxy) {
|
|
10557
|
+
return;
|
|
10558
|
+
}
|
|
10559
|
+
|
|
10560
|
+
helpers.removeEvent(canvas, type, proxy);
|
|
10561
|
+
}
|
|
10562
|
+
};
|
|
10563
|
+
};
|
|
10564
|
+
|
|
10565
|
+
},{}],42:[function(require,module,exports){
|
|
10566
|
+
'use strict';
|
|
10567
|
+
|
|
10568
|
+
// By default, select the browser (DOM) platform.
|
|
10569
|
+
// @TODO Make possible to select another platform at build time.
|
|
10570
|
+
var implementation = require(41);
|
|
10571
|
+
|
|
10572
|
+
module.exports = function(Chart) {
|
|
10573
|
+
/**
|
|
10574
|
+
* @namespace Chart.platform
|
|
10575
|
+
* @see https://chartjs.gitbooks.io/proposals/content/Platform.html
|
|
10576
|
+
* @since 2.4.0
|
|
10577
|
+
*/
|
|
10578
|
+
Chart.platform = {
|
|
10579
|
+
/**
|
|
10580
|
+
* Called at chart construction time, returns a context2d instance implementing
|
|
10581
|
+
* the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
|
|
10582
|
+
* @param {*} item - The native item from which to acquire context (platform specific)
|
|
10583
|
+
* @param {Object} options - The chart options
|
|
10584
|
+
* @returns {CanvasRenderingContext2D} context2d instance
|
|
10585
|
+
*/
|
|
10586
|
+
acquireContext: function() {},
|
|
10587
|
+
|
|
10588
|
+
/**
|
|
10589
|
+
* Called at chart destruction time, releases any resources associated to the context
|
|
10590
|
+
* previously returned by the acquireContext() method.
|
|
10591
|
+
* @param {CanvasRenderingContext2D} context - The context2d instance
|
|
10592
|
+
* @returns {Boolean} true if the method succeeded, else false
|
|
10593
|
+
*/
|
|
10594
|
+
releaseContext: function() {},
|
|
10595
|
+
|
|
10596
|
+
/**
|
|
10597
|
+
* Registers the specified listener on the given chart.
|
|
10598
|
+
* @param {Chart} chart - Chart from which to listen for event
|
|
10599
|
+
* @param {String} type - The ({@link IEvent}) type to listen for
|
|
10600
|
+
* @param {Function} listener - Receives a notification (an object that implements
|
|
10601
|
+
* the {@link IEvent} interface) when an event of the specified type occurs.
|
|
10602
|
+
*/
|
|
10603
|
+
addEventListener: function() {},
|
|
10604
|
+
|
|
10605
|
+
/**
|
|
10606
|
+
* Removes the specified listener previously registered with addEventListener.
|
|
10607
|
+
* @param {Chart} chart -Chart from which to remove the listener
|
|
10608
|
+
* @param {String} type - The ({@link IEvent}) type to remove
|
|
10609
|
+
* @param {Function} listener - The listener function to remove from the event target.
|
|
10610
|
+
*/
|
|
10611
|
+
removeEventListener: function() {}
|
|
10612
|
+
};
|
|
10613
|
+
|
|
10614
|
+
/**
|
|
10615
|
+
* @interface IPlatform
|
|
10616
|
+
* Allows abstracting platform dependencies away from the chart
|
|
10617
|
+
* @borrows Chart.platform.acquireContext as acquireContext
|
|
10618
|
+
* @borrows Chart.platform.releaseContext as releaseContext
|
|
10619
|
+
* @borrows Chart.platform.addEventListener as addEventListener
|
|
10620
|
+
* @borrows Chart.platform.removeEventListener as removeEventListener
|
|
10621
|
+
*/
|
|
10622
|
+
|
|
10623
|
+
/**
|
|
10624
|
+
* @interface IEvent
|
|
10625
|
+
* @prop {String} type - The event type name, possible values are:
|
|
10626
|
+
* 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
|
|
10627
|
+
* 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
|
|
10628
|
+
* @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
|
|
10629
|
+
* @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
|
|
10630
|
+
* @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
|
|
10631
|
+
*/
|
|
10632
|
+
|
|
10633
|
+
Chart.helpers.extend(Chart.platform, implementation(Chart));
|
|
10634
|
+
};
|
|
10635
|
+
|
|
10636
|
+
},{"41":41}],43:[function(require,module,exports){
|
|
10637
|
+
'use strict';
|
|
10638
|
+
|
|
10050
10639
|
module.exports = function(Chart) {
|
|
10051
10640
|
|
|
10052
10641
|
var helpers = Chart.helpers;
|
|
@@ -10101,10 +10690,10 @@ module.exports = function(Chart) {
|
|
|
10101
10690
|
var data = me.chart.data;
|
|
10102
10691
|
var isHorizontal = me.isHorizontal();
|
|
10103
10692
|
|
|
10104
|
-
if (
|
|
10693
|
+
if (data.yLabels && !isHorizontal) {
|
|
10105
10694
|
return me.getRightValue(data.datasets[datasetIndex].data[index]);
|
|
10106
10695
|
}
|
|
10107
|
-
return me.ticks[index];
|
|
10696
|
+
return me.ticks[index - me.minIndex];
|
|
10108
10697
|
},
|
|
10109
10698
|
|
|
10110
10699
|
// Used to get data value locations. Value can either be an index or a numerical value
|
|
@@ -10120,9 +10709,8 @@ module.exports = function(Chart) {
|
|
|
10120
10709
|
}
|
|
10121
10710
|
|
|
10122
10711
|
if (me.isHorizontal()) {
|
|
10123
|
-
var
|
|
10124
|
-
var
|
|
10125
|
-
var widthOffset = (valueWidth * (index - me.minIndex)) + me.paddingLeft;
|
|
10712
|
+
var valueWidth = me.width / offsetAmt;
|
|
10713
|
+
var widthOffset = (valueWidth * (index - me.minIndex));
|
|
10126
10714
|
|
|
10127
10715
|
if (me.options.gridLines.offsetGridLines && includeOffset || me.maxIndex === me.minIndex && includeOffset) {
|
|
10128
10716
|
widthOffset += (valueWidth / 2);
|
|
@@ -10130,9 +10718,8 @@ module.exports = function(Chart) {
|
|
|
10130
10718
|
|
|
10131
10719
|
return me.left + Math.round(widthOffset);
|
|
10132
10720
|
}
|
|
10133
|
-
var
|
|
10134
|
-
var
|
|
10135
|
-
var heightOffset = (valueHeight * (index - me.minIndex)) + me.paddingTop;
|
|
10721
|
+
var valueHeight = me.height / offsetAmt;
|
|
10722
|
+
var heightOffset = (valueHeight * (index - me.minIndex));
|
|
10136
10723
|
|
|
10137
10724
|
if (me.options.gridLines.offsetGridLines && includeOffset) {
|
|
10138
10725
|
heightOffset += (valueHeight / 2);
|
|
@@ -10148,15 +10735,13 @@ module.exports = function(Chart) {
|
|
|
10148
10735
|
var value;
|
|
10149
10736
|
var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
|
|
10150
10737
|
var horz = me.isHorizontal();
|
|
10151
|
-
var
|
|
10152
|
-
var valueDimension = innerDimension / offsetAmt;
|
|
10738
|
+
var valueDimension = (horz ? me.width : me.height) / offsetAmt;
|
|
10153
10739
|
|
|
10154
10740
|
pixel -= horz ? me.left : me.top;
|
|
10155
10741
|
|
|
10156
10742
|
if (me.options.gridLines.offsetGridLines) {
|
|
10157
10743
|
pixel -= (valueDimension / 2);
|
|
10158
10744
|
}
|
|
10159
|
-
pixel -= horz ? me.paddingLeft : me.paddingTop;
|
|
10160
10745
|
|
|
10161
10746
|
if (pixel <= 0) {
|
|
10162
10747
|
value = 0;
|
|
@@ -10175,7 +10760,7 @@ module.exports = function(Chart) {
|
|
|
10175
10760
|
|
|
10176
10761
|
};
|
|
10177
10762
|
|
|
10178
|
-
},{}],
|
|
10763
|
+
},{}],44:[function(require,module,exports){
|
|
10179
10764
|
'use strict';
|
|
10180
10765
|
|
|
10181
10766
|
module.exports = function(Chart) {
|
|
@@ -10206,21 +10791,43 @@ module.exports = function(Chart) {
|
|
|
10206
10791
|
me.min = null;
|
|
10207
10792
|
me.max = null;
|
|
10208
10793
|
|
|
10209
|
-
|
|
10210
|
-
|
|
10794
|
+
var hasStacks = opts.stacked;
|
|
10795
|
+
if (hasStacks === undefined) {
|
|
10796
|
+
helpers.each(datasets, function(dataset, datasetIndex) {
|
|
10797
|
+
if (hasStacks) {
|
|
10798
|
+
return;
|
|
10799
|
+
}
|
|
10800
|
+
|
|
10801
|
+
var meta = chart.getDatasetMeta(datasetIndex);
|
|
10802
|
+
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
|
|
10803
|
+
meta.stack !== undefined) {
|
|
10804
|
+
hasStacks = true;
|
|
10805
|
+
}
|
|
10806
|
+
});
|
|
10807
|
+
}
|
|
10808
|
+
|
|
10809
|
+
if (opts.stacked || hasStacks) {
|
|
10810
|
+
var valuesPerStack = {};
|
|
10211
10811
|
|
|
10212
10812
|
helpers.each(datasets, function(dataset, datasetIndex) {
|
|
10213
10813
|
var meta = chart.getDatasetMeta(datasetIndex);
|
|
10214
|
-
|
|
10215
|
-
|
|
10814
|
+
var key = [
|
|
10815
|
+
meta.type,
|
|
10816
|
+
// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
|
|
10817
|
+
((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
|
|
10818
|
+
meta.stack
|
|
10819
|
+
].join('.');
|
|
10820
|
+
|
|
10821
|
+
if (valuesPerStack[key] === undefined) {
|
|
10822
|
+
valuesPerStack[key] = {
|
|
10216
10823
|
positiveValues: [],
|
|
10217
10824
|
negativeValues: []
|
|
10218
10825
|
};
|
|
10219
10826
|
}
|
|
10220
10827
|
|
|
10221
10828
|
// Store these per type
|
|
10222
|
-
var positiveValues =
|
|
10223
|
-
var negativeValues =
|
|
10829
|
+
var positiveValues = valuesPerStack[key].positiveValues;
|
|
10830
|
+
var negativeValues = valuesPerStack[key].negativeValues;
|
|
10224
10831
|
|
|
10225
10832
|
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
|
|
10226
10833
|
helpers.each(dataset.data, function(rawValue, index) {
|
|
@@ -10243,7 +10850,7 @@ module.exports = function(Chart) {
|
|
|
10243
10850
|
}
|
|
10244
10851
|
});
|
|
10245
10852
|
|
|
10246
|
-
helpers.each(
|
|
10853
|
+
helpers.each(valuesPerStack, function(valuesForType) {
|
|
10247
10854
|
var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
|
|
10248
10855
|
var minVal = helpers.min(values);
|
|
10249
10856
|
var maxVal = helpers.max(values);
|
|
@@ -10310,31 +10917,25 @@ module.exports = function(Chart) {
|
|
|
10310
10917
|
// This must be called after fit has been run so that
|
|
10311
10918
|
// this.left, this.top, this.right, and this.bottom have been defined
|
|
10312
10919
|
var me = this;
|
|
10313
|
-
var paddingLeft = me.paddingLeft;
|
|
10314
|
-
var paddingBottom = me.paddingBottom;
|
|
10315
10920
|
var start = me.start;
|
|
10316
10921
|
|
|
10317
10922
|
var rightValue = +me.getRightValue(value);
|
|
10318
10923
|
var pixel;
|
|
10319
|
-
var innerDimension;
|
|
10320
10924
|
var range = me.end - start;
|
|
10321
10925
|
|
|
10322
10926
|
if (me.isHorizontal()) {
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
return Math.round(pixel + paddingLeft);
|
|
10927
|
+
pixel = me.left + (me.width / range * (rightValue - start));
|
|
10928
|
+
return Math.round(pixel);
|
|
10326
10929
|
}
|
|
10327
|
-
|
|
10328
|
-
pixel =
|
|
10930
|
+
|
|
10931
|
+
pixel = me.bottom - (me.height / range * (rightValue - start));
|
|
10329
10932
|
return Math.round(pixel);
|
|
10330
10933
|
},
|
|
10331
10934
|
getValueForPixel: function(pixel) {
|
|
10332
10935
|
var me = this;
|
|
10333
10936
|
var isHorizontal = me.isHorizontal();
|
|
10334
|
-
var
|
|
10335
|
-
var
|
|
10336
|
-
var innerDimension = isHorizontal ? me.width - (paddingLeft + me.paddingRight) : me.height - (me.paddingTop + paddingBottom);
|
|
10337
|
-
var offset = (isHorizontal ? pixel - me.left - paddingLeft : me.bottom - paddingBottom - pixel) / innerDimension;
|
|
10937
|
+
var innerDimension = isHorizontal ? me.width : me.height;
|
|
10938
|
+
var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
|
|
10338
10939
|
return me.start + ((me.end - me.start) * offset);
|
|
10339
10940
|
},
|
|
10340
10941
|
getPixelForTick: function(index) {
|
|
@@ -10345,7 +10946,7 @@ module.exports = function(Chart) {
|
|
|
10345
10946
|
|
|
10346
10947
|
};
|
|
10347
10948
|
|
|
10348
|
-
},{}],
|
|
10949
|
+
},{}],45:[function(require,module,exports){
|
|
10349
10950
|
'use strict';
|
|
10350
10951
|
|
|
10351
10952
|
module.exports = function(Chart) {
|
|
@@ -10445,7 +11046,7 @@ module.exports = function(Chart) {
|
|
|
10445
11046
|
});
|
|
10446
11047
|
};
|
|
10447
11048
|
|
|
10448
|
-
},{}],
|
|
11049
|
+
},{}],46:[function(require,module,exports){
|
|
10449
11050
|
'use strict';
|
|
10450
11051
|
|
|
10451
11052
|
module.exports = function(Chart) {
|
|
@@ -10480,18 +11081,40 @@ module.exports = function(Chart) {
|
|
|
10480
11081
|
me.max = null;
|
|
10481
11082
|
me.minNotZero = null;
|
|
10482
11083
|
|
|
10483
|
-
|
|
10484
|
-
|
|
11084
|
+
var hasStacks = opts.stacked;
|
|
11085
|
+
if (hasStacks === undefined) {
|
|
11086
|
+
helpers.each(datasets, function(dataset, datasetIndex) {
|
|
11087
|
+
if (hasStacks) {
|
|
11088
|
+
return;
|
|
11089
|
+
}
|
|
11090
|
+
|
|
11091
|
+
var meta = chart.getDatasetMeta(datasetIndex);
|
|
11092
|
+
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
|
|
11093
|
+
meta.stack !== undefined) {
|
|
11094
|
+
hasStacks = true;
|
|
11095
|
+
}
|
|
11096
|
+
});
|
|
11097
|
+
}
|
|
11098
|
+
|
|
11099
|
+
if (opts.stacked || hasStacks) {
|
|
11100
|
+
var valuesPerStack = {};
|
|
10485
11101
|
|
|
10486
11102
|
helpers.each(datasets, function(dataset, datasetIndex) {
|
|
10487
11103
|
var meta = chart.getDatasetMeta(datasetIndex);
|
|
11104
|
+
var key = [
|
|
11105
|
+
meta.type,
|
|
11106
|
+
// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
|
|
11107
|
+
((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
|
|
11108
|
+
meta.stack
|
|
11109
|
+
].join('.');
|
|
11110
|
+
|
|
10488
11111
|
if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
|
|
10489
|
-
if (
|
|
10490
|
-
|
|
11112
|
+
if (valuesPerStack[key] === undefined) {
|
|
11113
|
+
valuesPerStack[key] = [];
|
|
10491
11114
|
}
|
|
10492
11115
|
|
|
10493
11116
|
helpers.each(dataset.data, function(rawValue, index) {
|
|
10494
|
-
var values =
|
|
11117
|
+
var values = valuesPerStack[key];
|
|
10495
11118
|
var value = +me.getRightValue(rawValue);
|
|
10496
11119
|
if (isNaN(value) || meta.data[index].hidden) {
|
|
10497
11120
|
return;
|
|
@@ -10509,7 +11132,7 @@ module.exports = function(Chart) {
|
|
|
10509
11132
|
}
|
|
10510
11133
|
});
|
|
10511
11134
|
|
|
10512
|
-
helpers.each(
|
|
11135
|
+
helpers.each(valuesPerStack, function(valuesForType) {
|
|
10513
11136
|
var minVal = helpers.min(valuesForType);
|
|
10514
11137
|
var maxVal = helpers.max(valuesForType);
|
|
10515
11138
|
me.min = me.min === null ? minVal : Math.min(me.min, minVal);
|
|
@@ -10610,46 +11233,42 @@ module.exports = function(Chart) {
|
|
|
10610
11233
|
var start = me.start;
|
|
10611
11234
|
var newVal = +me.getRightValue(value);
|
|
10612
11235
|
var range;
|
|
10613
|
-
var paddingTop = me.paddingTop;
|
|
10614
|
-
var paddingBottom = me.paddingBottom;
|
|
10615
|
-
var paddingLeft = me.paddingLeft;
|
|
10616
11236
|
var opts = me.options;
|
|
10617
11237
|
var tickOpts = opts.ticks;
|
|
10618
11238
|
|
|
10619
11239
|
if (me.isHorizontal()) {
|
|
10620
11240
|
range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
|
|
10621
11241
|
if (newVal === 0) {
|
|
10622
|
-
pixel = me.left
|
|
11242
|
+
pixel = me.left;
|
|
10623
11243
|
} else {
|
|
10624
|
-
innerDimension = me.width
|
|
11244
|
+
innerDimension = me.width;
|
|
10625
11245
|
pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
|
|
10626
|
-
pixel += paddingLeft;
|
|
10627
11246
|
}
|
|
10628
11247
|
} else {
|
|
10629
11248
|
// Bottom - top since pixels increase downward on a screen
|
|
10630
|
-
innerDimension = me.height
|
|
11249
|
+
innerDimension = me.height;
|
|
10631
11250
|
if (start === 0 && !tickOpts.reverse) {
|
|
10632
11251
|
range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
|
|
10633
11252
|
if (newVal === start) {
|
|
10634
|
-
pixel = me.bottom
|
|
11253
|
+
pixel = me.bottom;
|
|
10635
11254
|
} else if (newVal === me.minNotZero) {
|
|
10636
|
-
pixel = me.bottom -
|
|
11255
|
+
pixel = me.bottom - innerDimension * 0.02;
|
|
10637
11256
|
} else {
|
|
10638
|
-
pixel = me.bottom -
|
|
11257
|
+
pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
|
|
10639
11258
|
}
|
|
10640
11259
|
} else if (me.end === 0 && tickOpts.reverse) {
|
|
10641
11260
|
range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
|
|
10642
11261
|
if (newVal === me.end) {
|
|
10643
|
-
pixel = me.top
|
|
11262
|
+
pixel = me.top;
|
|
10644
11263
|
} else if (newVal === me.minNotZero) {
|
|
10645
|
-
pixel = me.top +
|
|
11264
|
+
pixel = me.top + innerDimension * 0.02;
|
|
10646
11265
|
} else {
|
|
10647
|
-
pixel = me.top +
|
|
11266
|
+
pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
|
|
10648
11267
|
}
|
|
10649
11268
|
} else {
|
|
10650
11269
|
range = helpers.log10(me.end) - helpers.log10(start);
|
|
10651
|
-
innerDimension = me.height
|
|
10652
|
-
pixel =
|
|
11270
|
+
innerDimension = me.height;
|
|
11271
|
+
pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
|
|
10653
11272
|
}
|
|
10654
11273
|
}
|
|
10655
11274
|
return pixel;
|
|
@@ -10660,11 +11279,11 @@ module.exports = function(Chart) {
|
|
|
10660
11279
|
var value, innerDimension;
|
|
10661
11280
|
|
|
10662
11281
|
if (me.isHorizontal()) {
|
|
10663
|
-
innerDimension = me.width
|
|
10664
|
-
value = me.start * Math.pow(10, (pixel - me.left
|
|
11282
|
+
innerDimension = me.width;
|
|
11283
|
+
value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
|
|
10665
11284
|
} else { // todo: if start === 0
|
|
10666
|
-
innerDimension = me.height
|
|
10667
|
-
value = Math.pow(10, (me.bottom -
|
|
11285
|
+
innerDimension = me.height;
|
|
11286
|
+
value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
|
|
10668
11287
|
}
|
|
10669
11288
|
return value;
|
|
10670
11289
|
}
|
|
@@ -10673,7 +11292,7 @@ module.exports = function(Chart) {
|
|
|
10673
11292
|
|
|
10674
11293
|
};
|
|
10675
11294
|
|
|
10676
|
-
},{}],
|
|
11295
|
+
},{}],47:[function(require,module,exports){
|
|
10677
11296
|
'use strict';
|
|
10678
11297
|
|
|
10679
11298
|
module.exports = function(Chart) {
|
|
@@ -10723,10 +11342,266 @@ module.exports = function(Chart) {
|
|
|
10723
11342
|
}
|
|
10724
11343
|
};
|
|
10725
11344
|
|
|
11345
|
+
function getValueCount(scale) {
|
|
11346
|
+
return !scale.options.lineArc ? scale.chart.data.labels.length : 0;
|
|
11347
|
+
}
|
|
11348
|
+
|
|
11349
|
+
function getPointLabelFontOptions(scale) {
|
|
11350
|
+
var pointLabelOptions = scale.options.pointLabels;
|
|
11351
|
+
var fontSize = helpers.getValueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
|
|
11352
|
+
var fontStyle = helpers.getValueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
|
|
11353
|
+
var fontFamily = helpers.getValueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
|
|
11354
|
+
var font = helpers.fontString(fontSize, fontStyle, fontFamily);
|
|
11355
|
+
|
|
11356
|
+
return {
|
|
11357
|
+
size: fontSize,
|
|
11358
|
+
style: fontStyle,
|
|
11359
|
+
family: fontFamily,
|
|
11360
|
+
font: font
|
|
11361
|
+
};
|
|
11362
|
+
}
|
|
11363
|
+
|
|
11364
|
+
function measureLabelSize(ctx, fontSize, label) {
|
|
11365
|
+
if (helpers.isArray(label)) {
|
|
11366
|
+
return {
|
|
11367
|
+
w: helpers.longestText(ctx, ctx.font, label),
|
|
11368
|
+
h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
|
|
11369
|
+
};
|
|
11370
|
+
}
|
|
11371
|
+
|
|
11372
|
+
return {
|
|
11373
|
+
w: ctx.measureText(label).width,
|
|
11374
|
+
h: fontSize
|
|
11375
|
+
};
|
|
11376
|
+
}
|
|
11377
|
+
|
|
11378
|
+
function determineLimits(angle, pos, size, min, max) {
|
|
11379
|
+
if (angle === min || angle === max) {
|
|
11380
|
+
return {
|
|
11381
|
+
start: pos - (size / 2),
|
|
11382
|
+
end: pos + (size / 2)
|
|
11383
|
+
};
|
|
11384
|
+
} else if (angle < min || angle > max) {
|
|
11385
|
+
return {
|
|
11386
|
+
start: pos - size - 5,
|
|
11387
|
+
end: pos
|
|
11388
|
+
};
|
|
11389
|
+
}
|
|
11390
|
+
|
|
11391
|
+
return {
|
|
11392
|
+
start: pos,
|
|
11393
|
+
end: pos + size + 5
|
|
11394
|
+
};
|
|
11395
|
+
}
|
|
11396
|
+
|
|
11397
|
+
/**
|
|
11398
|
+
* Helper function to fit a radial linear scale with point labels
|
|
11399
|
+
*/
|
|
11400
|
+
function fitWithPointLabels(scale) {
|
|
11401
|
+
/*
|
|
11402
|
+
* Right, this is really confusing and there is a lot of maths going on here
|
|
11403
|
+
* The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
|
|
11404
|
+
*
|
|
11405
|
+
* Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
|
|
11406
|
+
*
|
|
11407
|
+
* Solution:
|
|
11408
|
+
*
|
|
11409
|
+
* We assume the radius of the polygon is half the size of the canvas at first
|
|
11410
|
+
* at each index we check if the text overlaps.
|
|
11411
|
+
*
|
|
11412
|
+
* Where it does, we store that angle and that index.
|
|
11413
|
+
*
|
|
11414
|
+
* After finding the largest index and angle we calculate how much we need to remove
|
|
11415
|
+
* from the shape radius to move the point inwards by that x.
|
|
11416
|
+
*
|
|
11417
|
+
* We average the left and right distances to get the maximum shape radius that can fit in the box
|
|
11418
|
+
* along with labels.
|
|
11419
|
+
*
|
|
11420
|
+
* Once we have that, we can find the centre point for the chart, by taking the x text protrusion
|
|
11421
|
+
* on each side, removing that from the size, halving it and adding the left x protrusion width.
|
|
11422
|
+
*
|
|
11423
|
+
* This will mean we have a shape fitted to the canvas, as large as it can be with the labels
|
|
11424
|
+
* and position it in the most space efficient manner
|
|
11425
|
+
*
|
|
11426
|
+
* https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
|
|
11427
|
+
*/
|
|
11428
|
+
|
|
11429
|
+
var plFont = getPointLabelFontOptions(scale);
|
|
11430
|
+
|
|
11431
|
+
// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
|
|
11432
|
+
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
|
|
11433
|
+
var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
|
|
11434
|
+
var furthestLimits = {
|
|
11435
|
+
l: scale.width,
|
|
11436
|
+
r: 0,
|
|
11437
|
+
t: scale.height,
|
|
11438
|
+
b: 0
|
|
11439
|
+
};
|
|
11440
|
+
var furthestAngles = {};
|
|
11441
|
+
var i;
|
|
11442
|
+
var textSize;
|
|
11443
|
+
var pointPosition;
|
|
11444
|
+
|
|
11445
|
+
scale.ctx.font = plFont.font;
|
|
11446
|
+
scale._pointLabelSizes = [];
|
|
11447
|
+
|
|
11448
|
+
var valueCount = getValueCount(scale);
|
|
11449
|
+
for (i = 0; i < valueCount; i++) {
|
|
11450
|
+
pointPosition = scale.getPointPosition(i, largestPossibleRadius);
|
|
11451
|
+
textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
|
|
11452
|
+
scale._pointLabelSizes[i] = textSize;
|
|
11453
|
+
|
|
11454
|
+
// Add quarter circle to make degree 0 mean top of circle
|
|
11455
|
+
var angleRadians = scale.getIndexAngle(i);
|
|
11456
|
+
var angle = helpers.toDegrees(angleRadians) % 360;
|
|
11457
|
+
var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
|
|
11458
|
+
var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
|
|
11459
|
+
|
|
11460
|
+
if (hLimits.start < furthestLimits.l) {
|
|
11461
|
+
furthestLimits.l = hLimits.start;
|
|
11462
|
+
furthestAngles.l = angleRadians;
|
|
11463
|
+
}
|
|
11464
|
+
|
|
11465
|
+
if (hLimits.end > furthestLimits.r) {
|
|
11466
|
+
furthestLimits.r = hLimits.end;
|
|
11467
|
+
furthestAngles.r = angleRadians;
|
|
11468
|
+
}
|
|
11469
|
+
|
|
11470
|
+
if (vLimits.start < furthestLimits.t) {
|
|
11471
|
+
furthestLimits.t = vLimits.start;
|
|
11472
|
+
furthestAngles.t = angleRadians;
|
|
11473
|
+
}
|
|
11474
|
+
|
|
11475
|
+
if (vLimits.end > furthestLimits.b) {
|
|
11476
|
+
furthestLimits.b = vLimits.end;
|
|
11477
|
+
furthestAngles.b = angleRadians;
|
|
11478
|
+
}
|
|
11479
|
+
}
|
|
11480
|
+
|
|
11481
|
+
scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
|
|
11482
|
+
}
|
|
11483
|
+
|
|
11484
|
+
/**
|
|
11485
|
+
* Helper function to fit a radial linear scale with no point labels
|
|
11486
|
+
*/
|
|
11487
|
+
function fit(scale) {
|
|
11488
|
+
var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
|
|
11489
|
+
scale.drawingArea = Math.round(largestPossibleRadius);
|
|
11490
|
+
scale.setCenterPoint(0, 0, 0, 0);
|
|
11491
|
+
}
|
|
11492
|
+
|
|
11493
|
+
function getTextAlignForAngle(angle) {
|
|
11494
|
+
if (angle === 0 || angle === 180) {
|
|
11495
|
+
return 'center';
|
|
11496
|
+
} else if (angle < 180) {
|
|
11497
|
+
return 'left';
|
|
11498
|
+
}
|
|
11499
|
+
|
|
11500
|
+
return 'right';
|
|
11501
|
+
}
|
|
11502
|
+
|
|
11503
|
+
function fillText(ctx, text, position, fontSize) {
|
|
11504
|
+
if (helpers.isArray(text)) {
|
|
11505
|
+
var y = position.y;
|
|
11506
|
+
var spacing = 1.5 * fontSize;
|
|
11507
|
+
|
|
11508
|
+
for (var i = 0; i < text.length; ++i) {
|
|
11509
|
+
ctx.fillText(text[i], position.x, y);
|
|
11510
|
+
y+= spacing;
|
|
11511
|
+
}
|
|
11512
|
+
} else {
|
|
11513
|
+
ctx.fillText(text, position.x, position.y);
|
|
11514
|
+
}
|
|
11515
|
+
}
|
|
11516
|
+
|
|
11517
|
+
function adjustPointPositionForLabelHeight(angle, textSize, position) {
|
|
11518
|
+
if (angle === 90 || angle === 270) {
|
|
11519
|
+
position.y -= (textSize.h / 2);
|
|
11520
|
+
} else if (angle > 270 || angle < 90) {
|
|
11521
|
+
position.y -= textSize.h;
|
|
11522
|
+
}
|
|
11523
|
+
}
|
|
11524
|
+
|
|
11525
|
+
function drawPointLabels(scale) {
|
|
11526
|
+
var ctx = scale.ctx;
|
|
11527
|
+
var getValueOrDefault = helpers.getValueOrDefault;
|
|
11528
|
+
var opts = scale.options;
|
|
11529
|
+
var angleLineOpts = opts.angleLines;
|
|
11530
|
+
var pointLabelOpts = opts.pointLabels;
|
|
11531
|
+
|
|
11532
|
+
ctx.lineWidth = angleLineOpts.lineWidth;
|
|
11533
|
+
ctx.strokeStyle = angleLineOpts.color;
|
|
11534
|
+
|
|
11535
|
+
var outerDistance = scale.getDistanceFromCenterForValue(opts.reverse ? scale.min : scale.max);
|
|
11536
|
+
|
|
11537
|
+
// Point Label Font
|
|
11538
|
+
var plFont = getPointLabelFontOptions(scale);
|
|
11539
|
+
|
|
11540
|
+
ctx.textBaseline = 'top';
|
|
11541
|
+
|
|
11542
|
+
for (var i = getValueCount(scale) - 1; i >= 0; i--) {
|
|
11543
|
+
if (angleLineOpts.display) {
|
|
11544
|
+
var outerPosition = scale.getPointPosition(i, outerDistance);
|
|
11545
|
+
ctx.beginPath();
|
|
11546
|
+
ctx.moveTo(scale.xCenter, scale.yCenter);
|
|
11547
|
+
ctx.lineTo(outerPosition.x, outerPosition.y);
|
|
11548
|
+
ctx.stroke();
|
|
11549
|
+
ctx.closePath();
|
|
11550
|
+
}
|
|
11551
|
+
// Extra 3px out for some label spacing
|
|
11552
|
+
var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
|
|
11553
|
+
|
|
11554
|
+
// Keep this in loop since we may support array properties here
|
|
11555
|
+
var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
|
|
11556
|
+
ctx.font = plFont.font;
|
|
11557
|
+
ctx.fillStyle = pointLabelFontColor;
|
|
11558
|
+
|
|
11559
|
+
var angleRadians = scale.getIndexAngle(i);
|
|
11560
|
+
var angle = helpers.toDegrees(angleRadians);
|
|
11561
|
+
ctx.textAlign = getTextAlignForAngle(angle);
|
|
11562
|
+
adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
|
|
11563
|
+
fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
|
|
11564
|
+
}
|
|
11565
|
+
}
|
|
11566
|
+
|
|
11567
|
+
function drawRadiusLine(scale, gridLineOpts, radius, index) {
|
|
11568
|
+
var ctx = scale.ctx;
|
|
11569
|
+
ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
|
|
11570
|
+
ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
|
|
11571
|
+
|
|
11572
|
+
if (scale.options.lineArc) {
|
|
11573
|
+
// Draw circular arcs between the points
|
|
11574
|
+
ctx.beginPath();
|
|
11575
|
+
ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
|
|
11576
|
+
ctx.closePath();
|
|
11577
|
+
ctx.stroke();
|
|
11578
|
+
} else {
|
|
11579
|
+
// Draw straight lines connecting each index
|
|
11580
|
+
var valueCount = getValueCount(scale);
|
|
11581
|
+
|
|
11582
|
+
if (valueCount === 0) {
|
|
11583
|
+
return;
|
|
11584
|
+
}
|
|
11585
|
+
|
|
11586
|
+
ctx.beginPath();
|
|
11587
|
+
var pointPosition = scale.getPointPosition(0, radius);
|
|
11588
|
+
ctx.moveTo(pointPosition.x, pointPosition.y);
|
|
11589
|
+
|
|
11590
|
+
for (var i = 1; i < valueCount; i++) {
|
|
11591
|
+
pointPosition = scale.getPointPosition(i, radius);
|
|
11592
|
+
ctx.lineTo(pointPosition.x, pointPosition.y);
|
|
11593
|
+
}
|
|
11594
|
+
|
|
11595
|
+
ctx.closePath();
|
|
11596
|
+
ctx.stroke();
|
|
11597
|
+
}
|
|
11598
|
+
}
|
|
11599
|
+
|
|
11600
|
+
function numberOrZero(param) {
|
|
11601
|
+
return helpers.isNumber(param) ? param : 0;
|
|
11602
|
+
}
|
|
11603
|
+
|
|
10726
11604
|
var LinearRadialScale = Chart.LinearScaleBase.extend({
|
|
10727
|
-
getValueCount: function() {
|
|
10728
|
-
return this.chart.data.labels.length;
|
|
10729
|
-
},
|
|
10730
11605
|
setDimensions: function() {
|
|
10731
11606
|
var me = this;
|
|
10732
11607
|
var opts = me.options;
|
|
@@ -10744,9 +11619,8 @@ module.exports = function(Chart) {
|
|
|
10744
11619
|
determineDataLimits: function() {
|
|
10745
11620
|
var me = this;
|
|
10746
11621
|
var chart = me.chart;
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
11622
|
+
var min = Number.POSITIVE_INFINITY;
|
|
11623
|
+
var max = Number.NEGATIVE_INFINITY;
|
|
10750
11624
|
|
|
10751
11625
|
helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
|
|
10752
11626
|
if (chart.isDatasetVisible(datasetIndex)) {
|
|
@@ -10758,21 +11632,15 @@ module.exports = function(Chart) {
|
|
|
10758
11632
|
return;
|
|
10759
11633
|
}
|
|
10760
11634
|
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
} else if (value < me.min) {
|
|
10764
|
-
me.min = value;
|
|
10765
|
-
}
|
|
10766
|
-
|
|
10767
|
-
if (me.max === null) {
|
|
10768
|
-
me.max = value;
|
|
10769
|
-
} else if (value > me.max) {
|
|
10770
|
-
me.max = value;
|
|
10771
|
-
}
|
|
11635
|
+
min = Math.min(value, min);
|
|
11636
|
+
max = Math.max(value, max);
|
|
10772
11637
|
});
|
|
10773
11638
|
}
|
|
10774
11639
|
});
|
|
10775
11640
|
|
|
11641
|
+
me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
|
|
11642
|
+
me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
|
|
11643
|
+
|
|
10776
11644
|
// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
|
|
10777
11645
|
me.handleTickRangeOptions();
|
|
10778
11646
|
},
|
|
@@ -10792,122 +11660,46 @@ module.exports = function(Chart) {
|
|
|
10792
11660
|
return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
|
|
10793
11661
|
},
|
|
10794
11662
|
fit: function() {
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
* Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
|
|
10800
|
-
*
|
|
10801
|
-
* Solution:
|
|
10802
|
-
*
|
|
10803
|
-
* We assume the radius of the polygon is half the size of the canvas at first
|
|
10804
|
-
* at each index we check if the text overlaps.
|
|
10805
|
-
*
|
|
10806
|
-
* Where it does, we store that angle and that index.
|
|
10807
|
-
*
|
|
10808
|
-
* After finding the largest index and angle we calculate how much we need to remove
|
|
10809
|
-
* from the shape radius to move the point inwards by that x.
|
|
10810
|
-
*
|
|
10811
|
-
* We average the left and right distances to get the maximum shape radius that can fit in the box
|
|
10812
|
-
* along with labels.
|
|
10813
|
-
*
|
|
10814
|
-
* Once we have that, we can find the centre point for the chart, by taking the x text protrusion
|
|
10815
|
-
* on each side, removing that from the size, halving it and adding the left x protrusion width.
|
|
10816
|
-
*
|
|
10817
|
-
* This will mean we have a shape fitted to the canvas, as large as it can be with the labels
|
|
10818
|
-
* and position it in the most space efficient manner
|
|
10819
|
-
*
|
|
10820
|
-
* https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
|
|
10821
|
-
*/
|
|
10822
|
-
|
|
10823
|
-
var pointLabels = this.options.pointLabels;
|
|
10824
|
-
var pointLabelFontSize = helpers.getValueOrDefault(pointLabels.fontSize, globalDefaults.defaultFontSize);
|
|
10825
|
-
var pointLabeFontStyle = helpers.getValueOrDefault(pointLabels.fontStyle, globalDefaults.defaultFontStyle);
|
|
10826
|
-
var pointLabeFontFamily = helpers.getValueOrDefault(pointLabels.fontFamily, globalDefaults.defaultFontFamily);
|
|
10827
|
-
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
|
|
10828
|
-
|
|
10829
|
-
// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
|
|
10830
|
-
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
|
|
10831
|
-
var largestPossibleRadius = helpers.min([(this.height / 2 - pointLabelFontSize - 5), this.width / 2]),
|
|
10832
|
-
pointPosition,
|
|
10833
|
-
i,
|
|
10834
|
-
textWidth,
|
|
10835
|
-
halfTextWidth,
|
|
10836
|
-
furthestRight = this.width,
|
|
10837
|
-
furthestRightIndex,
|
|
10838
|
-
furthestRightAngle,
|
|
10839
|
-
furthestLeft = 0,
|
|
10840
|
-
furthestLeftIndex,
|
|
10841
|
-
furthestLeftAngle,
|
|
10842
|
-
xProtrusionLeft,
|
|
10843
|
-
xProtrusionRight,
|
|
10844
|
-
radiusReductionRight,
|
|
10845
|
-
radiusReductionLeft;
|
|
10846
|
-
this.ctx.font = pointLabeFont;
|
|
10847
|
-
|
|
10848
|
-
for (i = 0; i < this.getValueCount(); i++) {
|
|
10849
|
-
// 5px to space the text slightly out - similar to what we do in the draw function.
|
|
10850
|
-
pointPosition = this.getPointPosition(i, largestPossibleRadius);
|
|
10851
|
-
textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5;
|
|
10852
|
-
|
|
10853
|
-
// Add quarter circle to make degree 0 mean top of circle
|
|
10854
|
-
var angleRadians = this.getIndexAngle(i) + (Math.PI / 2);
|
|
10855
|
-
var angle = (angleRadians * 360 / (2 * Math.PI)) % 360;
|
|
10856
|
-
|
|
10857
|
-
if (angle === 0 || angle === 180) {
|
|
10858
|
-
// At angle 0 and 180, we're at exactly the top/bottom
|
|
10859
|
-
// of the radar chart, so text will be aligned centrally, so we'll half it and compare
|
|
10860
|
-
// w/left and right text sizes
|
|
10861
|
-
halfTextWidth = textWidth / 2;
|
|
10862
|
-
if (pointPosition.x + halfTextWidth > furthestRight) {
|
|
10863
|
-
furthestRight = pointPosition.x + halfTextWidth;
|
|
10864
|
-
furthestRightIndex = i;
|
|
10865
|
-
}
|
|
10866
|
-
if (pointPosition.x - halfTextWidth < furthestLeft) {
|
|
10867
|
-
furthestLeft = pointPosition.x - halfTextWidth;
|
|
10868
|
-
furthestLeftIndex = i;
|
|
10869
|
-
}
|
|
10870
|
-
} else if (angle < 180) {
|
|
10871
|
-
// Less than half the values means we'll left align the text
|
|
10872
|
-
if (pointPosition.x + textWidth > furthestRight) {
|
|
10873
|
-
furthestRight = pointPosition.x + textWidth;
|
|
10874
|
-
furthestRightIndex = i;
|
|
10875
|
-
}
|
|
10876
|
-
// More than half the values means we'll right align the text
|
|
10877
|
-
} else if (pointPosition.x - textWidth < furthestLeft) {
|
|
10878
|
-
furthestLeft = pointPosition.x - textWidth;
|
|
10879
|
-
furthestLeftIndex = i;
|
|
10880
|
-
}
|
|
11663
|
+
if (this.options.lineArc) {
|
|
11664
|
+
fit(this);
|
|
11665
|
+
} else {
|
|
11666
|
+
fitWithPointLabels(this);
|
|
10881
11667
|
}
|
|
10882
|
-
|
|
10883
|
-
xProtrusionLeft = furthestLeft;
|
|
10884
|
-
xProtrusionRight = Math.ceil(furthestRight - this.width);
|
|
10885
|
-
|
|
10886
|
-
furthestRightAngle = this.getIndexAngle(furthestRightIndex);
|
|
10887
|
-
furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
|
|
10888
|
-
|
|
10889
|
-
radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2);
|
|
10890
|
-
radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2);
|
|
10891
|
-
|
|
10892
|
-
// Ensure we actually need to reduce the size of the chart
|
|
10893
|
-
radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
|
|
10894
|
-
radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
|
|
10895
|
-
|
|
10896
|
-
this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2);
|
|
10897
|
-
this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
|
|
10898
11668
|
},
|
|
10899
|
-
|
|
11669
|
+
/**
|
|
11670
|
+
* Set radius reductions and determine new radius and center point
|
|
11671
|
+
* @private
|
|
11672
|
+
*/
|
|
11673
|
+
setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
|
|
11674
|
+
var me = this;
|
|
11675
|
+
var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
|
|
11676
|
+
var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
|
|
11677
|
+
var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
|
|
11678
|
+
var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
|
|
11679
|
+
|
|
11680
|
+
radiusReductionLeft = numberOrZero(radiusReductionLeft);
|
|
11681
|
+
radiusReductionRight = numberOrZero(radiusReductionRight);
|
|
11682
|
+
radiusReductionTop = numberOrZero(radiusReductionTop);
|
|
11683
|
+
radiusReductionBottom = numberOrZero(radiusReductionBottom);
|
|
11684
|
+
|
|
11685
|
+
me.drawingArea = Math.min(
|
|
11686
|
+
Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
|
|
11687
|
+
Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
|
|
11688
|
+
me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
|
|
11689
|
+
},
|
|
11690
|
+
setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
|
|
10900
11691
|
var me = this;
|
|
10901
11692
|
var maxRight = me.width - rightMovement - me.drawingArea,
|
|
10902
|
-
maxLeft = leftMovement + me.drawingArea
|
|
11693
|
+
maxLeft = leftMovement + me.drawingArea,
|
|
11694
|
+
maxTop = topMovement + me.drawingArea,
|
|
11695
|
+
maxBottom = me.height - bottomMovement - me.drawingArea;
|
|
10903
11696
|
|
|
10904
11697
|
me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
|
|
10905
|
-
|
|
10906
|
-
me.yCenter = Math.round((me.height / 2) + me.top);
|
|
11698
|
+
me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
|
|
10907
11699
|
},
|
|
10908
11700
|
|
|
10909
11701
|
getIndexAngle: function(index) {
|
|
10910
|
-
var angleMultiplier = (Math.PI * 2) /
|
|
11702
|
+
var angleMultiplier = (Math.PI * 2) / getValueCount(this);
|
|
10911
11703
|
var startAngle = this.chart.options && this.chart.options.startAngle ?
|
|
10912
11704
|
this.chart.options.startAngle :
|
|
10913
11705
|
0;
|
|
@@ -10915,7 +11707,7 @@ module.exports = function(Chart) {
|
|
|
10915
11707
|
var startAngleRadians = startAngle * Math.PI * 2 / 360;
|
|
10916
11708
|
|
|
10917
11709
|
// Start from the top instead of right, so remove a quarter of the circle
|
|
10918
|
-
return index * angleMultiplier
|
|
11710
|
+
return index * angleMultiplier + startAngleRadians;
|
|
10919
11711
|
},
|
|
10920
11712
|
getDistanceFromCenterForValue: function(value) {
|
|
10921
11713
|
var me = this;
|
|
@@ -10933,7 +11725,7 @@ module.exports = function(Chart) {
|
|
|
10933
11725
|
},
|
|
10934
11726
|
getPointPosition: function(index, distanceFromCenter) {
|
|
10935
11727
|
var me = this;
|
|
10936
|
-
var thisAngle = me.getIndexAngle(index);
|
|
11728
|
+
var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
|
|
10937
11729
|
return {
|
|
10938
11730
|
x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
|
|
10939
11731
|
y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
|
|
@@ -10960,8 +11752,6 @@ module.exports = function(Chart) {
|
|
|
10960
11752
|
var opts = me.options;
|
|
10961
11753
|
var gridLineOpts = opts.gridLines;
|
|
10962
11754
|
var tickOpts = opts.ticks;
|
|
10963
|
-
var angleLineOpts = opts.angleLines;
|
|
10964
|
-
var pointLabelOpts = opts.pointLabels;
|
|
10965
11755
|
var getValueOrDefault = helpers.getValueOrDefault;
|
|
10966
11756
|
|
|
10967
11757
|
if (opts.display) {
|
|
@@ -10981,29 +11771,7 @@ module.exports = function(Chart) {
|
|
|
10981
11771
|
|
|
10982
11772
|
// Draw circular lines around the scale
|
|
10983
11773
|
if (gridLineOpts.display && index !== 0) {
|
|
10984
|
-
|
|
10985
|
-
ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
|
|
10986
|
-
|
|
10987
|
-
if (opts.lineArc) {
|
|
10988
|
-
// Draw circular arcs between the points
|
|
10989
|
-
ctx.beginPath();
|
|
10990
|
-
ctx.arc(me.xCenter, me.yCenter, yCenterOffset, 0, Math.PI * 2);
|
|
10991
|
-
ctx.closePath();
|
|
10992
|
-
ctx.stroke();
|
|
10993
|
-
} else {
|
|
10994
|
-
// Draw straight lines connecting each index
|
|
10995
|
-
ctx.beginPath();
|
|
10996
|
-
for (var i = 0; i < me.getValueCount(); i++) {
|
|
10997
|
-
var pointPosition = me.getPointPosition(i, yCenterOffset);
|
|
10998
|
-
if (i === 0) {
|
|
10999
|
-
ctx.moveTo(pointPosition.x, pointPosition.y);
|
|
11000
|
-
} else {
|
|
11001
|
-
ctx.lineTo(pointPosition.x, pointPosition.y);
|
|
11002
|
-
}
|
|
11003
|
-
}
|
|
11004
|
-
ctx.closePath();
|
|
11005
|
-
ctx.stroke();
|
|
11006
|
-
}
|
|
11774
|
+
drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
|
|
11007
11775
|
}
|
|
11008
11776
|
|
|
11009
11777
|
if (tickOpts.display) {
|
|
@@ -11030,59 +11798,7 @@ module.exports = function(Chart) {
|
|
|
11030
11798
|
});
|
|
11031
11799
|
|
|
11032
11800
|
if (!opts.lineArc) {
|
|
11033
|
-
|
|
11034
|
-
ctx.strokeStyle = angleLineOpts.color;
|
|
11035
|
-
|
|
11036
|
-
var outerDistance = me.getDistanceFromCenterForValue(opts.reverse ? me.min : me.max);
|
|
11037
|
-
|
|
11038
|
-
// Point Label Font
|
|
11039
|
-
var pointLabelFontSize = getValueOrDefault(pointLabelOpts.fontSize, globalDefaults.defaultFontSize);
|
|
11040
|
-
var pointLabeFontStyle = getValueOrDefault(pointLabelOpts.fontStyle, globalDefaults.defaultFontStyle);
|
|
11041
|
-
var pointLabeFontFamily = getValueOrDefault(pointLabelOpts.fontFamily, globalDefaults.defaultFontFamily);
|
|
11042
|
-
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
|
|
11043
|
-
|
|
11044
|
-
for (var i = me.getValueCount() - 1; i >= 0; i--) {
|
|
11045
|
-
if (angleLineOpts.display) {
|
|
11046
|
-
var outerPosition = me.getPointPosition(i, outerDistance);
|
|
11047
|
-
ctx.beginPath();
|
|
11048
|
-
ctx.moveTo(me.xCenter, me.yCenter);
|
|
11049
|
-
ctx.lineTo(outerPosition.x, outerPosition.y);
|
|
11050
|
-
ctx.stroke();
|
|
11051
|
-
ctx.closePath();
|
|
11052
|
-
}
|
|
11053
|
-
// Extra 3px out for some label spacing
|
|
11054
|
-
var pointLabelPosition = me.getPointPosition(i, outerDistance + 5);
|
|
11055
|
-
|
|
11056
|
-
// Keep this in loop since we may support array properties here
|
|
11057
|
-
var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
|
|
11058
|
-
ctx.font = pointLabeFont;
|
|
11059
|
-
ctx.fillStyle = pointLabelFontColor;
|
|
11060
|
-
|
|
11061
|
-
var pointLabels = me.pointLabels;
|
|
11062
|
-
|
|
11063
|
-
// Add quarter circle to make degree 0 mean top of circle
|
|
11064
|
-
var angleRadians = this.getIndexAngle(i) + (Math.PI / 2);
|
|
11065
|
-
var angle = (angleRadians * 360 / (2 * Math.PI)) % 360;
|
|
11066
|
-
|
|
11067
|
-
if (angle === 0 || angle === 180) {
|
|
11068
|
-
ctx.textAlign = 'center';
|
|
11069
|
-
} else if (angle < 180) {
|
|
11070
|
-
ctx.textAlign = 'left';
|
|
11071
|
-
} else {
|
|
11072
|
-
ctx.textAlign = 'right';
|
|
11073
|
-
}
|
|
11074
|
-
|
|
11075
|
-
// Set the correct text baseline based on outer positioning
|
|
11076
|
-
if (angle === 90 || angle === 270) {
|
|
11077
|
-
ctx.textBaseline = 'middle';
|
|
11078
|
-
} else if (angle > 270 || angle < 90) {
|
|
11079
|
-
ctx.textBaseline = 'bottom';
|
|
11080
|
-
} else {
|
|
11081
|
-
ctx.textBaseline = 'top';
|
|
11082
|
-
}
|
|
11083
|
-
|
|
11084
|
-
ctx.fillText(pointLabels[i] ? pointLabels[i] : '', pointLabelPosition.x, pointLabelPosition.y);
|
|
11085
|
-
}
|
|
11801
|
+
drawPointLabels(me);
|
|
11086
11802
|
}
|
|
11087
11803
|
}
|
|
11088
11804
|
}
|
|
@@ -11091,7 +11807,7 @@ module.exports = function(Chart) {
|
|
|
11091
11807
|
|
|
11092
11808
|
};
|
|
11093
11809
|
|
|
11094
|
-
},{}],
|
|
11810
|
+
},{}],48:[function(require,module,exports){
|
|
11095
11811
|
/* global window: false */
|
|
11096
11812
|
'use strict';
|
|
11097
11813
|
|
|
@@ -11334,7 +12050,7 @@ module.exports = function(Chart) {
|
|
|
11334
12050
|
me.unitScale = helpers.getValueOrDefault(me.options.time.unitStepSize, 1);
|
|
11335
12051
|
} else {
|
|
11336
12052
|
// Determine the smallest needed unit of the time
|
|
11337
|
-
var innerWidth = me.isHorizontal() ? me.width
|
|
12053
|
+
var innerWidth = me.isHorizontal() ? me.width : me.height;
|
|
11338
12054
|
|
|
11339
12055
|
// Crude approximation of what the label length might be
|
|
11340
12056
|
var tempFirstLabel = me.tickFormatFunction(me.firstTick, 0, []);
|
|
@@ -11418,7 +12134,7 @@ module.exports = function(Chart) {
|
|
|
11418
12134
|
me.ticks.push(me.firstTick.clone());
|
|
11419
12135
|
|
|
11420
12136
|
// For every unit in between the first and last moment, create a moment and add it to the ticks tick
|
|
11421
|
-
for (var i =
|
|
12137
|
+
for (var i = me.unitScale; i <= me.scaleSizeInUnits; i += me.unitScale) {
|
|
11422
12138
|
var newTick = roundedStart.clone().add(i, me.tickUnit);
|
|
11423
12139
|
|
|
11424
12140
|
// Are we greater than the max time
|
|
@@ -11426,9 +12142,7 @@ module.exports = function(Chart) {
|
|
|
11426
12142
|
break;
|
|
11427
12143
|
}
|
|
11428
12144
|
|
|
11429
|
-
|
|
11430
|
-
me.ticks.push(newTick);
|
|
11431
|
-
}
|
|
12145
|
+
me.ticks.push(newTick);
|
|
11432
12146
|
}
|
|
11433
12147
|
|
|
11434
12148
|
// Always show the right tick
|
|
@@ -11454,9 +12168,10 @@ module.exports = function(Chart) {
|
|
|
11454
12168
|
getLabelForIndex: function(index, datasetIndex) {
|
|
11455
12169
|
var me = this;
|
|
11456
12170
|
var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
|
|
12171
|
+
var value = me.chart.data.datasets[datasetIndex].data[index];
|
|
11457
12172
|
|
|
11458
|
-
if (typeof
|
|
11459
|
-
label = me.getRightValue(
|
|
12173
|
+
if (value !== null && typeof value === 'object') {
|
|
12174
|
+
label = me.getRightValue(value);
|
|
11460
12175
|
}
|
|
11461
12176
|
|
|
11462
12177
|
// Format nicely
|
|
@@ -11503,14 +12218,11 @@ module.exports = function(Chart) {
|
|
|
11503
12218
|
var decimal = offset !== 0 ? offset / me.scaleSizeInUnits : offset;
|
|
11504
12219
|
|
|
11505
12220
|
if (me.isHorizontal()) {
|
|
11506
|
-
var
|
|
11507
|
-
var valueOffset = (innerWidth * decimal) + me.paddingLeft;
|
|
11508
|
-
|
|
12221
|
+
var valueOffset = (me.width * decimal);
|
|
11509
12222
|
return me.left + Math.round(valueOffset);
|
|
11510
12223
|
}
|
|
11511
|
-
var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
|
|
11512
|
-
var heightOffset = (innerHeight * decimal) + me.paddingTop;
|
|
11513
12224
|
|
|
12225
|
+
var heightOffset = (me.height * decimal);
|
|
11514
12226
|
return me.top + Math.round(heightOffset);
|
|
11515
12227
|
}
|
|
11516
12228
|
},
|
|
@@ -11519,8 +12231,8 @@ module.exports = function(Chart) {
|
|
|
11519
12231
|
},
|
|
11520
12232
|
getValueForPixel: function(pixel) {
|
|
11521
12233
|
var me = this;
|
|
11522
|
-
var innerDimension = me.isHorizontal() ? me.width
|
|
11523
|
-
var offset = (pixel - (me.isHorizontal() ? me.left
|
|
12234
|
+
var innerDimension = me.isHorizontal() ? me.width : me.height;
|
|
12235
|
+
var offset = (pixel - (me.isHorizontal() ? me.left : me.top)) / innerDimension;
|
|
11524
12236
|
offset *= me.scaleSizeInUnits;
|
|
11525
12237
|
return me.firstTick.clone().add(moment.duration(offset, me.tickUnit).asSeconds(), 'seconds');
|
|
11526
12238
|
},
|