Skip to content

Commit

Permalink
Early data parsing + stacking by value
Browse files Browse the repository at this point in the history
determineDataLimits: simplify/fix for object data

Add test for object data

Make CC happier

Review comments

far far away

some fixes

Rebase, comments, cc warnings

Some more cleanup

get rid of _index
  • Loading branch information
kurkle committed Oct 27, 2019
1 parent 21da5be commit a564802
Show file tree
Hide file tree
Showing 18 changed files with 949 additions and 577 deletions.
145 changes: 105 additions & 40 deletions src/controllers/controller.bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,57 @@ function computeFlexCategoryTraits(index, ruler, options) {
};
}

function parseFloatBar(arr, item, vScale, i) {
var startValue = vScale._parse(arr[0], i);
var endValue = vScale._parse(arr[1], i);
var min = Math.min(startValue, endValue);
var max = Math.max(startValue, endValue);
var barStart = min;
var barEnd = max;

if (Math.abs(min) > Math.abs(max)) {
barStart = max;
barEnd = min;
}

// Store `barEnd` (furthest away from origin) as parsed value,
// to make stacking straight forward
item[vScale.id] = barEnd;

item._custom = {
barStart: barStart,
barEnd: barEnd,
start: startValue,
end: endValue,
min: min,
max: max
};
}

function parseArrayOrPrimitive(meta, data, start, count) {
var iScale = this._getIndexScale();
var vScale = this._getValueScale();
var labels = iScale._getLabels();
var singleScale = iScale === vScale;
var parsed = [];
var i, ilen, item, entry;

for (i = start, ilen = start + count; i < ilen; ++i) {
entry = data[i];
item = {_index: i};
item[iScale.id] = singleScale || iScale._parse(labels[i], i);

if (helpers.isArray(entry)) {
parseFloatBar(entry, item, vScale, i);
} else {
item[vScale.id] = vScale._parse(entry, i);
}

parsed.push(item);
}
return parsed;
}

module.exports = DatasetController.extend({

dataElementType: elements.Rectangle,
Expand All @@ -145,6 +196,36 @@ module.exports = DatasetController.extend({
'minBarLength'
],

/**
* Parse array of primitive values
* @param {object} meta - dataset meta
* @param {array} data - data array. Example [1,3,4]
* @param {number} start - start index
* @param {number} count - number of items to parse
* @returns {object} parsed item - item containing index and a parsed value
* for each scale id.
* Example: {index: 1, xScale0: 0, yScale0: 1}
* @private
*/
_parsePrimitiveData: function() {
return parseArrayOrPrimitive.apply(this, arguments);
},

/**
* Parse array of arrays
* @param {object} meta - dataset meta
* @param {array} data - data array. Example [[1,2],[3,4]]
* @param {number} start - start index
* @param {number} count - number of items to parse
* @returns {object} parsed item - item containing index and a parsed value
* for each scale id.
* Example: {index: 1, xScale0: 0, yScale0: 1}
* @private
*/
_parseArrayData: function() {
return parseArrayOrPrimitive.apply(this, arguments);
},

initialize: function() {
var me = this;
var meta, scaleOpts;
Expand Down Expand Up @@ -294,7 +375,7 @@ module.exports = DatasetController.extend({
var i, ilen;

for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
pixels.push(scale.getPixelForValue(null, i, me.index));
pixels.push(scale.getPixelForValue(me._getParsedValue(scale, i)));
}

return {
Expand All @@ -312,50 +393,36 @@ module.exports = DatasetController.extend({
*/
calculateBarValuePixels: function(datasetIndex, index, options) {
var me = this;
var chart = me.chart;
var scale = me._getValueScale();
var isHorizontal = scale.isHorizontal();
var datasets = chart.data.datasets;
var metasets = scale._getMatchingVisibleMetas(me._type);
var value = scale._parseValue(datasets[datasetIndex].data[index]);
var valueScale = me._getValueScale();
var minBarLength = options.minBarLength;
var stacked = scale.options.stacked;
var stack = me.getMeta().stack;
var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
var ilen = metasets.length;
var i, imeta, ivalue, base, head, size, stackLength;

if (stacked || (stacked === undefined && stack !== undefined)) {
for (i = 0; i < ilen; ++i) {
imeta = metasets[i];

if (imeta.index === datasetIndex) {
break;
}

if (imeta.stack === stack) {
stackLength = scale._parseValue(datasets[imeta.index].data[index]);
ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
var start = 0;
var value = me._getParsedValue(valueScale, index);
var custom = me._getParsedCustom(index);
var length = me._getStackedValue(valueScale, index);
var base, head, size;

if (length !== value) {
start = length - value;
length = value;
}

if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {
start += ivalue;
}
}
if (custom && custom.barStart !== undefined && custom.barEnd !== undefined) {
value = custom.barStart;
length = custom.barEnd - custom.barStart;
// bars crossing origin are not stacked
if (value !== 0 && Math.sign(value) !== Math.sign(custom.barEnd)) {
start = 0;
}
start += value;
}

base = scale.getPixelForValue(start);
head = scale.getPixelForValue(start + length);
base = valueScale.getPixelForValue(start);
head = valueScale.getPixelForValue(start + length);
size = head - base;

if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
size = minBarLength;
if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) {
head = base - minBarLength;
} else {
head = base + minBarLength;
}
size = size < 0 ? -minBarLength : minBarLength;
head = base + size;
}

return {
Expand Down Expand Up @@ -394,15 +461,13 @@ module.exports = DatasetController.extend({
var chart = me.chart;
var scale = me._getValueScale();
var rects = me.getMeta().data;
var dataset = me.getDataset();
var ilen = rects.length;
var i = 0;

helpers.canvas.clipArea(chart.ctx, chart.chartArea);

for (; i < ilen; ++i) {
var val = scale._parseValue(dataset.data[i]);
if (!isNaN(val.min) && !isNaN(val.max)) {
if (!isNaN(me._getParsedValue(scale, i))) {
rects[i].draw();
}
}
Expand Down
12 changes: 9 additions & 3 deletions src/controllers/controller.bubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ module.exports = DatasetController.extend({
'rotation'
],

/**
* @private
*/
_parseCustomObjectData: function(obj) {
return obj && obj.r && +obj.r;
},

/**
* @protected
*/
Expand All @@ -87,11 +94,10 @@ module.exports = DatasetController.extend({
var xScale = me.getScaleForId(meta.xAxisID);
var yScale = me.getScaleForId(meta.yAxisID);
var options = me._resolveDataElementOptions(point, index);
var data = me.getDataset().data[index];
var dsIndex = me.index;

var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(me._getParsedValue(xScale, index));
var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(me._getParsedValue(yScale, index));

point._xScale = xScale;
point._yScale = yScale;
Expand Down
24 changes: 18 additions & 6 deletions src/controllers/controller.doughnut.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@ module.exports = DatasetController.extend({
'hoverBorderWidth',
],

/**
* Override data parsing, since we are not using scales
* @private
*/
_parse: function(start, count) {
var data = this.getDataset().data;
var metaData = this.getMeta().data;
var i, ilen;
for (i = start, ilen = start + count; i < ilen; ++i) {
metaData[i]._val = +data[i];
}
},

// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
getRingIndex: function(datasetIndex) {
var ringIndex = 0;
Expand Down Expand Up @@ -223,7 +236,7 @@ module.exports = DatasetController.extend({
var startAngle = opts.rotation; // non reset case handled later
var endAngle = opts.rotation; // non reset case handled later
var dataset = me.getDataset();
var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI);
var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(arc._val * opts.circumference / DOUBLE_PI);
var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
var options = arc._options || {};
Expand Down Expand Up @@ -267,14 +280,13 @@ module.exports = DatasetController.extend({
},

calculateTotal: function() {
var dataset = this.getDataset();
var meta = this.getMeta();
var metaData = this.getMeta().data;
var total = 0;
var value;

helpers.each(meta.data, function(element, index) {
value = dataset.data[index];
if (!isNaN(value) && !element.hidden) {
helpers.each(metaData, function(arc) {
value = arc ? arc._val : NaN;
if (!isNaN(value) && !arc.hidden) {
total += Math.abs(value);
}
});
Expand Down
56 changes: 16 additions & 40 deletions src/controllers/controller.line.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,18 +117,16 @@ module.exports = DatasetController.extend({
var me = this;
var meta = me.getMeta();
var custom = point.custom || {};
var dataset = me.getDataset();
var datasetIndex = me.index;
var value = dataset.data[index];
var xScale = me._xScale;
var yScale = me._yScale;
var lineModel = meta.dataset._model;
var x, y;

var options = me._resolveDataElementOptions(point, index);

x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
x = xScale.getPixelForValue(me._getParsedValue(xScale, index));
y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(me._getStackedValue(yScale, index));

// Utility
point._xScale = xScale;
Expand Down Expand Up @@ -177,42 +175,6 @@ module.exports = DatasetController.extend({
return values;
},

calculatePointY: function(value, index, datasetIndex) {
var me = this;
var chart = me.chart;
var yScale = me._yScale;
var sumPos = 0;
var sumNeg = 0;
var rightValue = +yScale.getRightValue(value);
var metasets = chart._getSortedVisibleDatasetMetas();
var ilen = metasets.length;
var i, ds, dsMeta, stackedRightValue;

if (yScale.options.stacked) {
for (i = 0; i < ilen; ++i) {
dsMeta = metasets[i];
if (dsMeta.index === datasetIndex) {
break;
}

ds = chart.data.datasets[dsMeta.index];
if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
stackedRightValue = +yScale.getRightValue(ds.data[index]);
if (stackedRightValue < 0) {
sumNeg += stackedRightValue || 0;
} else {
sumPos += stackedRightValue || 0;
}
}
}

if (rightValue < 0) {
return yScale.getPixelForValue(sumNeg + rightValue);
}
}
return yScale.getPixelForValue(sumPos + rightValue);
},

updateBezierControlPoints: function() {
var me = this;
var chart = me.chart;
Expand Down Expand Up @@ -319,4 +281,18 @@ module.exports = DatasetController.extend({
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
model.radius = valueOrDefault(options.hoverRadius, options.radius);
},

// DEPRECATIONS

/**
* Provided for backward compatibility
* @deprecated since version 2.9.0
* @todo remove at version 3
*/
calculatePointY: function(value, index, datasetIndex) {
var me = this;
var chart = me.chart;
var controller = datasetIndex === me.index ? me : chart.getDatasetMeta(datasetIndex).controller;
return controller._getStackedValue(me._yScale, index);
},
});
Loading

0 comments on commit a564802

Please sign in to comment.