chart-js-rails 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
},
|