mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Merge pull request #435 from nnnick/fix/sparse-datasets
Resolve issues with sparse datasets & solve bezier capping to scale bounds
This commit is contained in:
commit
7eec283d70
213
Chart.js
vendored
213
Chart.js
vendored
@ -889,7 +889,7 @@
|
||||
yMin;
|
||||
helpers.each(this.datasets, function(dataset){
|
||||
dataCollection = dataset.points || dataset.bars || dataset.segments;
|
||||
if (dataCollection[dataIndex]){
|
||||
if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){
|
||||
Elements.push(dataCollection[dataIndex]);
|
||||
}
|
||||
});
|
||||
@ -1053,6 +1053,9 @@
|
||||
x : this.x,
|
||||
y : this.y
|
||||
};
|
||||
},
|
||||
hasValue: function(){
|
||||
return isNumber(this.value);
|
||||
}
|
||||
});
|
||||
|
||||
@ -2010,18 +2013,16 @@
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.bars.push(new this.BarClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.bars.push(new this.BarClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
@ -2136,19 +2137,17 @@
|
||||
addData : function(valuesArray,label){
|
||||
//Map the values array for each of the datasets
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
base : this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||||
fillColor : this.datasets[datasetIndex].fillColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
base : this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||||
fillColor : this.datasets[datasetIndex].fillColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
@ -2185,13 +2184,15 @@
|
||||
//Draw all the bars for each dataset
|
||||
helpers.each(this.datasets,function(dataset,datasetIndex){
|
||||
helpers.each(dataset.bars,function(bar,index){
|
||||
bar.base = this.scale.endPoint;
|
||||
//Transition then draw
|
||||
bar.transition({
|
||||
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y : this.scale.calculateY(bar.value),
|
||||
width : this.scale.calculateBarWidth(this.datasets.length)
|
||||
}, easingDecimal).draw();
|
||||
if (bar.hasValue()){
|
||||
bar.base = this.scale.endPoint;
|
||||
//Transition then draw
|
||||
bar.transition({
|
||||
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y : this.scale.calculateY(bar.value),
|
||||
width : this.scale.calculateBarWidth(this.datasets.length)
|
||||
}, easingDecimal).draw();
|
||||
}
|
||||
},this);
|
||||
|
||||
},this);
|
||||
@ -2484,19 +2485,16 @@
|
||||
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Best way to do this? or in draw sequence...?
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.buildScale(data.labels);
|
||||
@ -2603,17 +2601,15 @@
|
||||
//Map the values array for each of the datasets
|
||||
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateX(this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateX(this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
@ -2650,10 +2646,12 @@
|
||||
//We can use this extra loop to calculate the control points of this dataset also in this loop
|
||||
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
point.transition({
|
||||
y : this.scale.calculateY(point.value),
|
||||
x : this.scale.calculateX(index)
|
||||
}, easingDecimal);
|
||||
if (point.hasValue()){
|
||||
point.transition({
|
||||
y : this.scale.calculateY(point.value),
|
||||
x : this.scale.calculateX(index)
|
||||
}, easingDecimal);
|
||||
}
|
||||
|
||||
},this);
|
||||
|
||||
@ -2682,24 +2680,26 @@
|
||||
ctx.strokeStyle = dataset.strokeColor;
|
||||
ctx.beginPath();
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
if (index>0){
|
||||
if(this.options.bezierCurve){
|
||||
ctx.bezierCurveTo(
|
||||
dataset.points[index-1].controlPoints.outer.x,
|
||||
dataset.points[index-1].controlPoints.outer.y,
|
||||
point.controlPoints.inner.x,
|
||||
point.controlPoints.inner.y,
|
||||
point.x,
|
||||
point.y
|
||||
);
|
||||
if (point.hasValue()){
|
||||
if (index>0){
|
||||
if(this.options.bezierCurve){
|
||||
ctx.bezierCurveTo(
|
||||
dataset.points[index-1].controlPoints.outer.x,
|
||||
dataset.points[index-1].controlPoints.outer.y,
|
||||
point.controlPoints.inner.x,
|
||||
point.controlPoints.inner.y,
|
||||
point.x,
|
||||
point.y
|
||||
);
|
||||
}
|
||||
else{
|
||||
ctx.lineTo(point.x,point.y);
|
||||
}
|
||||
|
||||
}
|
||||
else{
|
||||
ctx.lineTo(point.x,point.y);
|
||||
ctx.moveTo(point.x,point.y);
|
||||
}
|
||||
|
||||
}
|
||||
else{
|
||||
ctx.moveTo(point.x,point.y);
|
||||
}
|
||||
},this);
|
||||
ctx.stroke();
|
||||
@ -2718,7 +2718,9 @@
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(dataset.points,function(point){
|
||||
point.draw();
|
||||
if (point.hasValue()){
|
||||
point.draw();
|
||||
}
|
||||
});
|
||||
|
||||
},this);
|
||||
@ -3088,25 +3090,22 @@
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Best way to do this? or in draw sequence...?
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
var pointPosition;
|
||||
if (!this.scale.animation){
|
||||
pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
|
||||
y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
var pointPosition;
|
||||
if (!this.scale.animation){
|
||||
pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
|
||||
y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
@ -3221,17 +3220,15 @@
|
||||
//Map the values array for each of the datasets
|
||||
this.scale.valuesCount++;
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: pointPosition.x,
|
||||
y: pointPosition.y,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
}
|
||||
var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: pointPosition.x,
|
||||
y: pointPosition.y,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.labels.push(label);
|
||||
@ -3278,7 +3275,9 @@
|
||||
|
||||
//Transition each point first so that the line and point drawing isn't out of sync
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
|
||||
if (point.hasValue()){
|
||||
point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
|
||||
}
|
||||
},this);
|
||||
|
||||
|
||||
@ -3305,7 +3304,9 @@
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(dataset.points,function(point){
|
||||
point.draw();
|
||||
if (point.hasValue()){
|
||||
point.draw();
|
||||
}
|
||||
});
|
||||
|
||||
},this);
|
||||
|
||||
@ -104,18 +104,16 @@
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.bars.push(new this.BarClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.bars.push(new this.BarClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
@ -230,19 +228,17 @@
|
||||
addData : function(valuesArray,label){
|
||||
//Map the values array for each of the datasets
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
base : this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||||
fillColor : this.datasets[datasetIndex].fillColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
base : this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||||
fillColor : this.datasets[datasetIndex].fillColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
@ -279,13 +275,15 @@
|
||||
//Draw all the bars for each dataset
|
||||
helpers.each(this.datasets,function(dataset,datasetIndex){
|
||||
helpers.each(dataset.bars,function(bar,index){
|
||||
bar.base = this.scale.endPoint;
|
||||
//Transition then draw
|
||||
bar.transition({
|
||||
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y : this.scale.calculateY(bar.value),
|
||||
width : this.scale.calculateBarWidth(this.datasets.length)
|
||||
}, easingDecimal).draw();
|
||||
if (bar.hasValue()){
|
||||
bar.base = this.scale.endPoint;
|
||||
//Transition then draw
|
||||
bar.transition({
|
||||
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y : this.scale.calculateY(bar.value),
|
||||
width : this.scale.calculateBarWidth(this.datasets.length)
|
||||
}, easingDecimal).draw();
|
||||
}
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
@ -217,6 +217,41 @@
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
where = helpers.where = function(collection, filterCallback){
|
||||
var filtered = [];
|
||||
|
||||
helpers.each(collection, function(item){
|
||||
if (filterCallback(item)){
|
||||
filtered.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
return filtered;
|
||||
},
|
||||
findNextWhere = helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex){
|
||||
// Default to start of the array
|
||||
if (!startIndex){
|
||||
startIndex = -1;
|
||||
}
|
||||
for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
|
||||
var currentItem = arrayToSearch[i];
|
||||
if (filterCallback(currentItem)){
|
||||
return currentItem;
|
||||
}
|
||||
};
|
||||
},
|
||||
findPreviousWhere = helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex){
|
||||
// Default to end of the array
|
||||
if (!startIndex){
|
||||
startIndex = arrayToSearch.length;
|
||||
}
|
||||
for (var i = startIndex - 1; i >= 0; i--) {
|
||||
var currentItem = arrayToSearch[i];
|
||||
if (filterCallback(currentItem)){
|
||||
return currentItem;
|
||||
}
|
||||
};
|
||||
},
|
||||
inherits = helpers.inherits = function(extensions){
|
||||
//Basic javascript inheritance based on the model created in Backbone.js
|
||||
var parent = this;
|
||||
@ -407,11 +442,10 @@
|
||||
//Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
|
||||
template = helpers.template = function(templateString, valuesObject){
|
||||
// If templateString is function rather than string-template - call the function for valuesObject
|
||||
if(templateString instanceof Function)
|
||||
{
|
||||
if(templateString instanceof Function){
|
||||
return templateString(valuesObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var cache = {};
|
||||
function tmpl(str, data){
|
||||
// Figure out if we're getting a template, or if we need to
|
||||
@ -718,7 +752,7 @@
|
||||
var ctx = chart.ctx,
|
||||
width = chart.canvas.width,
|
||||
height = chart.canvas.height;
|
||||
//console.log(width + " x " + height);
|
||||
|
||||
if (window.devicePixelRatio) {
|
||||
ctx.canvas.style.width = width + "px";
|
||||
ctx.canvas.style.height = height + "px";
|
||||
@ -889,7 +923,7 @@
|
||||
yMin;
|
||||
helpers.each(this.datasets, function(dataset){
|
||||
dataCollection = dataset.points || dataset.bars || dataset.segments;
|
||||
if (dataCollection[dataIndex]){
|
||||
if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){
|
||||
Elements.push(dataCollection[dataIndex]);
|
||||
}
|
||||
});
|
||||
@ -1053,6 +1087,9 @@
|
||||
x : this.x,
|
||||
y : this.y
|
||||
};
|
||||
},
|
||||
hasValue: function(){
|
||||
return isNumber(this.value);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1099,6 +1136,7 @@
|
||||
// ctx.fill();
|
||||
|
||||
// ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y);
|
||||
// ctx.lineTo(this.x, this.y);
|
||||
// ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y);
|
||||
// ctx.stroke();
|
||||
|
||||
|
||||
@ -98,19 +98,16 @@
|
||||
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Best way to do this? or in draw sequence...?
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.buildScale(data.labels);
|
||||
@ -217,17 +214,15 @@
|
||||
//Map the values array for each of the datasets
|
||||
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateX(this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
}
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: this.scale.calculateX(this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
@ -255,37 +250,64 @@
|
||||
|
||||
var ctx = this.chart.ctx;
|
||||
|
||||
// Some helper methods for getting the next/prev points
|
||||
var hasValue = function(item){
|
||||
return item.value !== null;
|
||||
},
|
||||
nextPoint = function(point, collection, index){
|
||||
return helpers.findNextWhere(collection, hasValue, index) || point;
|
||||
},
|
||||
previousPoint = function(point, collection, index){
|
||||
return helpers.findPreviousWhere(collection, hasValue, index) || point;
|
||||
};
|
||||
|
||||
this.scale.draw(easingDecimal);
|
||||
|
||||
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
var pointsWithValues = helpers.where(dataset.points, hasValue);
|
||||
|
||||
//Transition each point first so that the line and point drawing isn't out of sync
|
||||
//We can use this extra loop to calculate the control points of this dataset also in this loop
|
||||
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
point.transition({
|
||||
y : this.scale.calculateY(point.value),
|
||||
x : this.scale.calculateX(index)
|
||||
}, easingDecimal);
|
||||
|
||||
helpers.each(dataset.points, function(point, index){
|
||||
if (point.hasValue()){
|
||||
point.transition({
|
||||
y : this.scale.calculateY(point.value),
|
||||
x : this.scale.calculateX(index)
|
||||
}, easingDecimal);
|
||||
}
|
||||
},this);
|
||||
|
||||
|
||||
// Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point
|
||||
// This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
|
||||
if (this.options.bezierCurve){
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
//If we're at the start or end, we don't have a previous/next point
|
||||
//By setting the tension to 0 here, the curve will transition to straight at the end
|
||||
if (index === 0){
|
||||
point.controlPoints = helpers.splineCurve(point,point,dataset.points[index+1],0);
|
||||
helpers.each(pointsWithValues, function(point, index){
|
||||
var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
|
||||
point.controlPoints = helpers.splineCurve(
|
||||
previousPoint(point, pointsWithValues, index),
|
||||
point,
|
||||
nextPoint(point, pointsWithValues, index),
|
||||
tension
|
||||
);
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
|
||||
// Cap puter bezier handles to the upper/lower scale bounds
|
||||
if (point.controlPoints.outer.y > this.scale.endPoint){
|
||||
point.controlPoints.outer.y = this.scale.endPoint;
|
||||
}
|
||||
else if (index >= dataset.points.length-1){
|
||||
point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,point,0);
|
||||
else if (point.controlPoints.outer.y < this.scale.startPoint){
|
||||
point.controlPoints.outer.y = this.scale.startPoint;
|
||||
}
|
||||
else{
|
||||
point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,dataset.points[index+1],this.options.bezierCurveTension);
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (point.controlPoints.inner.y > this.scale.endPoint){
|
||||
point.controlPoints.inner.y = this.scale.endPoint;
|
||||
}
|
||||
else if (point.controlPoints.inner.y < this.scale.startPoint){
|
||||
point.controlPoints.inner.y = this.scale.startPoint;
|
||||
}
|
||||
},this);
|
||||
}
|
||||
@ -295,12 +317,18 @@
|
||||
ctx.lineWidth = this.options.datasetStrokeWidth;
|
||||
ctx.strokeStyle = dataset.strokeColor;
|
||||
ctx.beginPath();
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
if (index>0){
|
||||
|
||||
helpers.each(pointsWithValues, function(point, index){
|
||||
if (index === 0){
|
||||
ctx.moveTo(point.x, point.y);
|
||||
}
|
||||
else{
|
||||
if(this.options.bezierCurve){
|
||||
var previous = previousPoint(point, pointsWithValues, index);
|
||||
|
||||
ctx.bezierCurveTo(
|
||||
dataset.points[index-1].controlPoints.outer.x,
|
||||
dataset.points[index-1].controlPoints.outer.y,
|
||||
previous.controlPoints.outer.x,
|
||||
previous.controlPoints.outer.y,
|
||||
point.controlPoints.inner.x,
|
||||
point.controlPoints.inner.y,
|
||||
point.x,
|
||||
@ -310,19 +338,15 @@
|
||||
else{
|
||||
ctx.lineTo(point.x,point.y);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
}
|
||||
else{
|
||||
ctx.moveTo(point.x,point.y);
|
||||
}
|
||||
},this);
|
||||
ctx.stroke();
|
||||
|
||||
|
||||
if (this.options.datasetFill){
|
||||
if (this.options.datasetFill && pointsWithValues.length > 0){
|
||||
//Round off the line by going to the base of the chart, back to the start, then fill.
|
||||
ctx.lineTo(dataset.points[dataset.points.length-1].x, this.scale.endPoint);
|
||||
ctx.lineTo(this.scale.calculateX(0), this.scale.endPoint);
|
||||
ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint);
|
||||
ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
|
||||
ctx.fillStyle = dataset.fillColor;
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
@ -331,10 +355,9 @@
|
||||
//Now draw the points over the line
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(dataset.points,function(point){
|
||||
helpers.each(pointsWithValues,function(point){
|
||||
point.draw();
|
||||
});
|
||||
|
||||
},this);
|
||||
}
|
||||
});
|
||||
|
||||
@ -111,25 +111,22 @@
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Best way to do this? or in draw sequence...?
|
||||
if (helpers.isNumber(dataPoint)){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
var pointPosition;
|
||||
if (!this.scale.animation){
|
||||
pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
|
||||
y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
var pointPosition;
|
||||
if (!this.scale.animation){
|
||||
pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
|
||||
y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
@ -244,17 +241,15 @@
|
||||
//Map the values array for each of the datasets
|
||||
this.scale.valuesCount++;
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
if (helpers.isNumber(value)){
|
||||
var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: pointPosition.x,
|
||||
y: pointPosition.y,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
}
|
||||
var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
x: pointPosition.x,
|
||||
y: pointPosition.y,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.labels.push(label);
|
||||
@ -301,7 +296,9 @@
|
||||
|
||||
//Transition each point first so that the line and point drawing isn't out of sync
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
|
||||
if (point.hasValue()){
|
||||
point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
|
||||
}
|
||||
},this);
|
||||
|
||||
|
||||
@ -328,7 +325,9 @@
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(dataset.points,function(point){
|
||||
point.draw();
|
||||
if (point.hasValue()){
|
||||
point.draw();
|
||||
}
|
||||
});
|
||||
|
||||
},this);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user