determineDataLimits optimizations (#6695)
@ -384,7 +384,7 @@ module.exports = DatasetController.extend({
|
||||
value = custom.barStart;
|
||||
length = custom.barEnd - custom.barStart;
|
||||
// bars crossing origin are not stacked
|
||||
if (value !== 0 && Math.sign(value) !== Math.sign(custom.barEnd)) {
|
||||
if (value !== 0 && helpers.sign(value) !== helpers.sign(custom.barEnd)) {
|
||||
start = 0;
|
||||
}
|
||||
start += value;
|
||||
|
||||
@ -391,6 +391,10 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
scales[scale.id] = scale;
|
||||
}
|
||||
|
||||
// parse min/max value, so we can properly determine min/max for other scales
|
||||
scale._userMin = scale._parse(scale.options.ticks.min);
|
||||
scale._userMax = scale._parse(scale.options.ticks.max);
|
||||
|
||||
// TODO(SB): I think we should be able to remove this custom case (options.scale)
|
||||
// and consider it as a regular scale part of the "scales"" map only! This would
|
||||
// make the logic easier and remove some useless? custom code.
|
||||
|
||||
@ -146,7 +146,7 @@ function applyStack(stack, value, dsIndex, allOther) {
|
||||
break;
|
||||
}
|
||||
otherValue = stack.values[datasetIndex];
|
||||
if (!isNaN(otherValue) && (value === 0 || Math.sign(value) === Math.sign(otherValue))) {
|
||||
if (!isNaN(otherValue) && (value === 0 || helpers.sign(value) === helpers.sign(otherValue))) {
|
||||
value += otherValue;
|
||||
}
|
||||
}
|
||||
@ -185,6 +185,13 @@ function getFirstScaleId(chart, axis) {
|
||||
return (scalesOpts && scalesOpts[prop] && scalesOpts[prop].length && scalesOpts[prop][0].id) || scaleId;
|
||||
}
|
||||
|
||||
function getUserBounds(scale) {
|
||||
var {min, max, minDefined, maxDefined} = scale._getUserBounds();
|
||||
return {
|
||||
min: minDefined ? min : Number.NEGATIVE_INFINITY,
|
||||
max: maxDefined ? max : Number.POSITIVE_INFINITY
|
||||
};
|
||||
}
|
||||
// Base class for all dataset controllers (line, bar, etc)
|
||||
var DatasetController = function(chart, datasetIndex) {
|
||||
this.initialize(chart, datasetIndex);
|
||||
@ -298,6 +305,15 @@ helpers.extend(DatasetController.prototype, {
|
||||
return this.getScaleForId(this._getIndexScaleId());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getOtherScale: function(scale) {
|
||||
return scale.id === this._getIndexScaleId()
|
||||
? this._getValueScale()
|
||||
: this._getIndexScale();
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._update(true);
|
||||
},
|
||||
@ -612,7 +628,9 @@ helpers.extend(DatasetController.prototype, {
|
||||
var max = Number.NEGATIVE_INFINITY;
|
||||
var stacked = canStack && meta._stacked;
|
||||
var indices = getSortedDatasetIndices(chart, true);
|
||||
var i, item, value, parsed, stack, min, minPositive;
|
||||
var otherScale = this._getOtherScale(scale);
|
||||
var {min: otherMin, max: otherMax} = getUserBounds(otherScale);
|
||||
var i, item, value, parsed, stack, min, minPositive, otherValue;
|
||||
|
||||
min = minPositive = Number.POSITIVE_INFINITY;
|
||||
|
||||
@ -620,7 +638,9 @@ helpers.extend(DatasetController.prototype, {
|
||||
item = metaData[i];
|
||||
parsed = item._parsed;
|
||||
value = parsed[scale.id];
|
||||
if (item.hidden || isNaN(value)) {
|
||||
otherValue = parsed[otherScale.id];
|
||||
if (item.hidden || isNaN(value) ||
|
||||
otherMin > otherValue || otherMax < otherValue) {
|
||||
continue;
|
||||
}
|
||||
if (stacked) {
|
||||
|
||||
@ -6,6 +6,7 @@ const helpers = require('../helpers/index');
|
||||
const Ticks = require('./core.ticks');
|
||||
|
||||
const isArray = helpers.isArray;
|
||||
const isFinite = helpers.isFinite;
|
||||
const isNullOrUndef = helpers.isNullOrUndef;
|
||||
const valueOrDefault = helpers.valueOrDefault;
|
||||
const resolve = helpers.options.resolve;
|
||||
@ -347,26 +348,49 @@ class Scale extends Element {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @since 3.0
|
||||
*/
|
||||
_getUserBounds() {
|
||||
var min = this._userMin;
|
||||
var max = this._userMax;
|
||||
if (isNullOrUndef(min) || isNaN(min)) {
|
||||
min = Number.POSITIVE_INFINITY;
|
||||
}
|
||||
if (isNullOrUndef(max) || isNaN(max)) {
|
||||
max = Number.NEGATIVE_INFINITY;
|
||||
}
|
||||
return {min, max, minDefined: isFinite(min), maxDefined: isFinite(max)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @since 3.0
|
||||
*/
|
||||
_getMinMax(canStack) {
|
||||
var me = this;
|
||||
var metas = me._getMatchingVisibleMetas();
|
||||
var min = Number.POSITIVE_INFINITY;
|
||||
var max = Number.NEGATIVE_INFINITY;
|
||||
var {min, max, minDefined, maxDefined} = me._getUserBounds();
|
||||
var minPositive = Number.POSITIVE_INFINITY;
|
||||
var i, ilen, minmax;
|
||||
var i, ilen, metas, minmax;
|
||||
|
||||
if (minDefined && maxDefined) {
|
||||
return {min, max};
|
||||
}
|
||||
|
||||
metas = me._getMatchingVisibleMetas();
|
||||
for (i = 0, ilen = metas.length; i < ilen; ++i) {
|
||||
minmax = metas[i].controller._getMinMax(me, canStack);
|
||||
min = Math.min(min, minmax.min);
|
||||
max = Math.max(max, minmax.max);
|
||||
if (!minDefined) {
|
||||
min = Math.min(min, minmax.min);
|
||||
}
|
||||
if (!maxDefined) {
|
||||
max = Math.max(max, minmax.max);
|
||||
}
|
||||
minPositive = Math.min(minPositive, minmax.minPositive);
|
||||
}
|
||||
|
||||
return {
|
||||
min: min,
|
||||
max: max,
|
||||
minPositive: minPositive
|
||||
};
|
||||
return {min, max, minPositive};
|
||||
}
|
||||
|
||||
_invalidateCaches() {}
|
||||
|
||||
@ -24,44 +24,20 @@ module.exports = Scale.extend({
|
||||
|
||||
determineDataLimits: function() {
|
||||
var me = this;
|
||||
var labels = me._getLabels();
|
||||
var ticksOpts = me.options.ticks;
|
||||
var min = ticksOpts.min;
|
||||
var max = ticksOpts.max;
|
||||
var minIndex = 0;
|
||||
var maxIndex = labels.length - 1;
|
||||
var findIndex;
|
||||
var max = me._getLabels().length - 1;
|
||||
|
||||
if (min !== undefined) {
|
||||
// user specified min value
|
||||
findIndex = labels.indexOf(min);
|
||||
if (findIndex >= 0) {
|
||||
minIndex = findIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (max !== undefined) {
|
||||
// user specified max value
|
||||
findIndex = labels.indexOf(max);
|
||||
if (findIndex >= 0) {
|
||||
maxIndex = findIndex;
|
||||
}
|
||||
}
|
||||
|
||||
me.minIndex = minIndex;
|
||||
me.maxIndex = maxIndex;
|
||||
me.min = labels[minIndex];
|
||||
me.max = labels[maxIndex];
|
||||
me.min = Math.max(me._userMin || 0, 0);
|
||||
me.max = Math.min(me._userMax || max, max);
|
||||
},
|
||||
|
||||
buildTicks: function() {
|
||||
var me = this;
|
||||
var labels = me._getLabels();
|
||||
var minIndex = me.minIndex;
|
||||
var maxIndex = me.maxIndex;
|
||||
var min = me.min;
|
||||
var max = me.max;
|
||||
|
||||
// If we are viewing some subset of labels, slice the original array
|
||||
labels = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, maxIndex + 1);
|
||||
labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1);
|
||||
return labels.map(function(l) {
|
||||
return {value: l};
|
||||
});
|
||||
@ -93,7 +69,7 @@ module.exports = Scale.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
me._startValue = me.minIndex - (offset ? 0.5 : 0);
|
||||
me._startValue = me.min - (offset ? 0.5 : 0);
|
||||
me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);
|
||||
},
|
||||
|
||||
@ -112,7 +88,7 @@ module.exports = Scale.extend({
|
||||
var ticks = this.ticks;
|
||||
return index < 0 || index > ticks.length - 1
|
||||
? null
|
||||
: this.getPixelForValue(index + this.minIndex);
|
||||
: this.getPixelForValue(index + this.min);
|
||||
},
|
||||
|
||||
getValueForPixel: function(pixel) {
|
||||
|
||||
@ -84,7 +84,7 @@ function generateTicks(generationOptions, dataRange) {
|
||||
}
|
||||
|
||||
module.exports = Scale.extend({
|
||||
_parse: function(raw) {
|
||||
_parse: function(raw, index) { // eslint-disable-line no-unused-vars
|
||||
if (helpers.isNullOrUndef(raw)) {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
@ -64,13 +64,11 @@ var defaultConfig = {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(v3): change this to positiveOrDefault
|
||||
function nonNegativeOrDefault(value, defaultValue) {
|
||||
return helpers.isFinite(value) && value >= 0 ? value : defaultValue;
|
||||
}
|
||||
|
||||
module.exports = Scale.extend({
|
||||
_parse: LinearScaleBase.prototype._parse,
|
||||
_parse: function(raw, index) { // eslint-disable-line no-unused-vars
|
||||
const value = LinearScaleBase.prototype._parse.apply(this, arguments);
|
||||
return helpers.isFinite(value) && value >= 0 ? value : undefined;
|
||||
},
|
||||
|
||||
determineDataLimits: function() {
|
||||
var me = this;
|
||||
@ -88,39 +86,39 @@ module.exports = Scale.extend({
|
||||
|
||||
handleTickRangeOptions: function() {
|
||||
var me = this;
|
||||
var tickOpts = me.options.ticks;
|
||||
var DEFAULT_MIN = 1;
|
||||
var DEFAULT_MAX = 10;
|
||||
var min = me.min;
|
||||
var max = me.max;
|
||||
|
||||
me.min = nonNegativeOrDefault(tickOpts.min, me.min);
|
||||
me.max = nonNegativeOrDefault(tickOpts.max, me.max);
|
||||
|
||||
if (me.min === me.max) {
|
||||
if (me.min !== 0 && me.min !== null) {
|
||||
me.min = Math.pow(10, Math.floor(log10(me.min)) - 1);
|
||||
me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);
|
||||
if (min === max) {
|
||||
if (min !== 0 && min !== null) {
|
||||
min = Math.pow(10, Math.floor(log10(min)) - 1);
|
||||
max = Math.pow(10, Math.floor(log10(max)) + 1);
|
||||
} else {
|
||||
me.min = DEFAULT_MIN;
|
||||
me.max = DEFAULT_MAX;
|
||||
min = DEFAULT_MIN;
|
||||
max = DEFAULT_MAX;
|
||||
}
|
||||
}
|
||||
if (me.min === null) {
|
||||
me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);
|
||||
if (min === null) {
|
||||
min = Math.pow(10, Math.floor(log10(max)) - 1);
|
||||
}
|
||||
if (me.max === null) {
|
||||
me.max = me.min !== 0
|
||||
? Math.pow(10, Math.floor(log10(me.min)) + 1)
|
||||
if (max === null) {
|
||||
max = min !== 0
|
||||
? Math.pow(10, Math.floor(log10(min)) + 1)
|
||||
: DEFAULT_MAX;
|
||||
}
|
||||
if (me.minNotZero === null) {
|
||||
if (me.min > 0) {
|
||||
me.minNotZero = me.min;
|
||||
} else if (me.max < 1) {
|
||||
me.minNotZero = Math.pow(10, Math.floor(log10(me.max)));
|
||||
if (min > 0) {
|
||||
me.minNotZero = min;
|
||||
} else if (max < 1) {
|
||||
me.minNotZero = Math.pow(10, Math.floor(log10(max)));
|
||||
} else {
|
||||
me.minNotZero = DEFAULT_MIN;
|
||||
}
|
||||
}
|
||||
me.min = min;
|
||||
me.max = max;
|
||||
},
|
||||
|
||||
buildTicks: function() {
|
||||
@ -129,8 +127,8 @@ module.exports = Scale.extend({
|
||||
var reverse = !me.isHorizontal();
|
||||
|
||||
var generationOptions = {
|
||||
min: nonNegativeOrDefault(tickOpts.min),
|
||||
max: nonNegativeOrDefault(tickOpts.max)
|
||||
min: me._userMin,
|
||||
max: me._userMax
|
||||
};
|
||||
var ticks = generateTicks(generationOptions, me);
|
||||
|
||||
|
||||
@ -177,7 +177,11 @@ function interpolate(table, skey, sval, tkey) {
|
||||
return prev[tkey] + offset;
|
||||
}
|
||||
|
||||
function toTimestamp(scale, input) {
|
||||
function parse(scale, input) {
|
||||
if (helpers.isNullOrUndef(input)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var adapter = scale._adapter;
|
||||
var options = scale.options.time;
|
||||
var parser = options.parser;
|
||||
@ -194,25 +198,15 @@ function toTimestamp(scale, input) {
|
||||
: adapter.parse(value);
|
||||
}
|
||||
|
||||
return value !== null ? +value : value;
|
||||
}
|
||||
|
||||
function parse(scale, input) {
|
||||
if (helpers.isNullOrUndef(input)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var options = scale.options.time;
|
||||
var value = toTimestamp(scale, input);
|
||||
if (value === null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (options.round) {
|
||||
value = +scale._adapter.startOf(value, options.round);
|
||||
value = scale._adapter.startOf(value, options.round);
|
||||
}
|
||||
|
||||
return value;
|
||||
return +value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,42 +358,60 @@ function ticksFromTimestamps(scale, values, majorUnit) {
|
||||
return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
|
||||
}
|
||||
|
||||
|
||||
function getDataTimestamps(scale) {
|
||||
var timestamps = scale._cache.data || [];
|
||||
var i, ilen, metas;
|
||||
|
||||
if (!timestamps.length) {
|
||||
metas = scale._getMatchingVisibleMetas();
|
||||
for (i = 0, ilen = metas.length; i < ilen; ++i) {
|
||||
timestamps = timestamps.concat(metas[i].controller._getAllParsedValues(scale));
|
||||
}
|
||||
timestamps = scale._cache.data = arrayUnique(timestamps).sort(sorter);
|
||||
if (timestamps.length) {
|
||||
return timestamps;
|
||||
}
|
||||
return timestamps;
|
||||
|
||||
metas = scale._getMatchingVisibleMetas();
|
||||
for (i = 0, ilen = metas.length; i < ilen; ++i) {
|
||||
timestamps = timestamps.concat(metas[i].controller._getAllParsedValues(scale));
|
||||
}
|
||||
|
||||
// We can not assume data is in order or unique - not even for single dataset
|
||||
// It seems to be somewhat faster to do sorting first
|
||||
return (scale._cache.data = arrayUnique(timestamps.sort(sorter)));
|
||||
}
|
||||
|
||||
function getLabelTimestamps(scale) {
|
||||
var timestamps = scale._cache.labels || [];
|
||||
var i, ilen, labels;
|
||||
|
||||
if (!timestamps.length) {
|
||||
labels = scale._getLabels();
|
||||
for (i = 0, ilen = labels.length; i < ilen; ++i) {
|
||||
timestamps.push(parse(scale, labels[i]));
|
||||
}
|
||||
timestamps = scale._cache.labels = arrayUnique(timestamps).sort(sorter);
|
||||
if (timestamps.length) {
|
||||
return timestamps;
|
||||
}
|
||||
return timestamps;
|
||||
|
||||
labels = scale._getLabels();
|
||||
for (i = 0, ilen = labels.length; i < ilen; ++i) {
|
||||
timestamps.push(parse(scale, labels[i]));
|
||||
}
|
||||
|
||||
// We could assume labels are in order and unique - but let's not
|
||||
return (scale._cache.labels = arrayUnique(timestamps.sort(sorter)));
|
||||
}
|
||||
|
||||
function getAllTimestamps(scale) {
|
||||
var timestamps = scale._cache.all || [];
|
||||
var label, data;
|
||||
|
||||
if (!timestamps.length) {
|
||||
timestamps = getDataTimestamps(scale).concat(getLabelTimestamps(scale));
|
||||
timestamps = scale._cache.all = arrayUnique(timestamps).sort(sorter);
|
||||
if (timestamps.length) {
|
||||
return timestamps;
|
||||
}
|
||||
|
||||
data = getDataTimestamps(scale);
|
||||
label = getLabelTimestamps(scale);
|
||||
if (data.length && label.length) {
|
||||
// If combining labels and data (data might not contain all labels),
|
||||
// we need to recheck uniqueness and sort
|
||||
timestamps = arrayUnique(data.concat(label).sort(sorter));
|
||||
} else {
|
||||
timestamps = data.length ? data : label;
|
||||
}
|
||||
timestamps = scale._cache.all = timestamps;
|
||||
|
||||
return timestamps;
|
||||
}
|
||||
|
||||
@ -423,6 +435,24 @@ function getTimestampsForTicks(scale) {
|
||||
return timestamps;
|
||||
}
|
||||
|
||||
function getTimestampsForTable(scale) {
|
||||
return scale.options.distribution === 'series'
|
||||
? getAllTimestamps(scale)
|
||||
: [scale.min, scale.max];
|
||||
}
|
||||
|
||||
function getLabelBounds(scale) {
|
||||
var min = Number.POSITIVE_INFINITY;
|
||||
var max = Number.NEGATIVE_INFINITY;
|
||||
var arr = getLabelTimestamps(scale);
|
||||
|
||||
if (arr.length) {
|
||||
min = arr[0];
|
||||
max = arr[arr.length - 1];
|
||||
}
|
||||
return {min, max};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return subset of `timestamps` between `min` and `max`.
|
||||
* Timestamps are assumend to be in sorted order.
|
||||
@ -501,7 +531,7 @@ module.exports = Scale.extend({
|
||||
if (raw === undefined) {
|
||||
return NaN;
|
||||
}
|
||||
return toTimestamp(this, raw);
|
||||
return parse(this, raw);
|
||||
},
|
||||
|
||||
_parseObject: function(obj, axis, index) {
|
||||
@ -539,30 +569,35 @@ module.exports = Scale.extend({
|
||||
|
||||
determineDataLimits: function() {
|
||||
var me = this;
|
||||
var adapter = me._adapter;
|
||||
var options = me.options;
|
||||
var tickOpts = options.ticks;
|
||||
var adapter = me._adapter;
|
||||
var unit = options.time.unit || 'day';
|
||||
var min = Number.POSITIVE_INFINITY;
|
||||
var max = Number.NEGATIVE_INFINITY;
|
||||
var minmax = me._getMinMax(false);
|
||||
var i, ilen, labels;
|
||||
var {min, max, minDefined, maxDefined} = me._getUserBounds();
|
||||
|
||||
min = Math.min(min, minmax.min);
|
||||
max = Math.max(max, minmax.max);
|
||||
function _applyBounds(bounds) {
|
||||
if (!minDefined && !isNaN(bounds.min)) {
|
||||
min = Math.min(min, bounds.min);
|
||||
}
|
||||
if (!maxDefined && !isNaN(bounds.max)) {
|
||||
max = Math.max(max, bounds.max);
|
||||
}
|
||||
}
|
||||
|
||||
labels = getLabelTimestamps(me);
|
||||
for (i = 0, ilen = labels.length; i < ilen; ++i) {
|
||||
min = Math.min(min, labels[i]);
|
||||
max = Math.max(max, labels[i]);
|
||||
// If we have user provided `min` and `max` labels / data bounds can be ignored
|
||||
if (!minDefined || !maxDefined) {
|
||||
// Labels are always considered, when user did not force bounds
|
||||
_applyBounds(getLabelBounds(me));
|
||||
|
||||
// If `bounds` is `'ticks'` and `ticks.source` is `'labels'`,
|
||||
// data bounds are ignored (and don't need to be determined)
|
||||
if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
|
||||
_applyBounds(me._getMinMax(false));
|
||||
}
|
||||
}
|
||||
|
||||
min = helpers.isFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
|
||||
max = helpers.isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
|
||||
|
||||
min = parse(me, tickOpts.min) || min;
|
||||
max = parse(me, tickOpts.max) || max;
|
||||
|
||||
// Make sure that max is strictly higher than min (required by the lookup table)
|
||||
me.min = Math.min(min, max);
|
||||
me.max = Math.max(min + 1, max);
|
||||
@ -580,8 +615,8 @@ module.exports = Scale.extend({
|
||||
timestamps = getTimestampsForTicks(me);
|
||||
|
||||
if (options.bounds === 'ticks' && timestamps.length) {
|
||||
me.min = parse(me, tickOpts.min) || timestamps[0];
|
||||
me.max = parse(me, tickOpts.max) || timestamps[timestamps.length - 1];
|
||||
me.min = me._userMin || timestamps[0];
|
||||
me.max = me._userMax || timestamps[timestamps.length - 1];
|
||||
}
|
||||
|
||||
min = me.min;
|
||||
@ -597,7 +632,7 @@ module.exports = Scale.extend({
|
||||
: determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
|
||||
me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
|
||||
: determineMajorUnit(me._unit);
|
||||
me._table = buildLookupTable(getAllTimestamps(me), min, max, distribution);
|
||||
me._table = buildLookupTable(getTimestampsForTable(me), min, max, distribution);
|
||||
me._offsets = computeOffsets(me._table, ticks, min, max, options);
|
||||
|
||||
if (tickOpts.reverse) {
|
||||
|
||||
BIN
test/fixtures/controller.line/clip/default-x-max.png
vendored
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
BIN
test/fixtures/controller.line/clip/default-x.png
vendored
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
BIN
test/fixtures/controller.line/clip/default-y-max.png
vendored
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
test/fixtures/controller.line/clip/default-y.png
vendored
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -1493,7 +1493,7 @@ describe('Chart.controllers.bar', function() {
|
||||
var totalBarWidth = 0;
|
||||
for (var i = 0; i < chart.data.datasets.length; i++) {
|
||||
var bars = chart.getDatasetMeta(i).data;
|
||||
for (var j = xScale.minIndex; j <= xScale.maxIndex; j++) {
|
||||
for (var j = xScale.min; j <= xScale.max; j++) {
|
||||
totalBarWidth += bars[j]._model.width;
|
||||
}
|
||||
if (stacked) {
|
||||
@ -1571,7 +1571,7 @@ describe('Chart.controllers.bar', function() {
|
||||
var totalBarHeight = 0;
|
||||
for (var i = 0; i < chart.data.datasets.length; i++) {
|
||||
var bars = chart.getDatasetMeta(i).data;
|
||||
for (var j = yScale.minIndex; j <= yScale.maxIndex; j++) {
|
||||
for (var j = yScale.min; j <= yScale.max; j++) {
|
||||
totalBarHeight += bars[j]._model.height;
|
||||
}
|
||||
if (stacked) {
|
||||
|
||||
@ -581,4 +581,40 @@ describe('Core.scale', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('min and max', function() {
|
||||
it('should be limited to visible data', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'scatter',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [{x: 100, y: 100}, {x: -100, y: -100}]
|
||||
}, {
|
||||
data: [{x: 10, y: 10}, {x: -10, y: -10}]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'x',
|
||||
type: 'linear',
|
||||
ticks: {
|
||||
min: -20,
|
||||
max: 20
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'y',
|
||||
type: 'linear'
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart.scales.x.min).toEqual(-20);
|
||||
expect(chart.scales.x.max).toEqual(20);
|
||||
expect(chart.scales.y.min).toEqual(-10);
|
||||
expect(chart.scales.y.max).toEqual(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -515,7 +515,7 @@ describe('Logarithmic Scale tests', function() {
|
||||
datasets: [{
|
||||
data: [1, 1, 1, 2, 1, 0]
|
||||
}],
|
||||
labels: []
|
||||
labels: ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
@ -523,8 +523,8 @@ describe('Logarithmic Scale tests', function() {
|
||||
id: 'yScale',
|
||||
type: 'logarithmic',
|
||||
ticks: {
|
||||
min: '',
|
||||
max: false,
|
||||
min: 'zero',
|
||||
max: null,
|
||||
callback: function(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||