mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Merge pull request #1653 from nnnick/fix/1381
Fixes flickering during animations
This commit is contained in:
commit
ac098b8b2f
175
samples/line-skip-points.html
Normal file
175
samples/line-skip-points.html
Normal file
@ -0,0 +1,175 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
//return 0;
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
|
||||
// Skip a point in the middle
|
||||
data: [randomScalingFactor(), randomScalingFactor(), NaN, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: true,
|
||||
borderDash: [5, 5],
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
|
||||
// Skip first and last points
|
||||
data: [NaN, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), NaN],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
},
|
||||
hover: {
|
||||
mode: 'label'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
show: true,
|
||||
labelString: 'Month'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
show: true,
|
||||
labelString: 'Value'
|
||||
},
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
152
samples/radar-skip-points.html
Normal file
152
samples/radar-skip-points.html
Normal file
@ -0,0 +1,152 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Radar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<canvas id="canvas" height="450" width="450"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'radar',
|
||||
data: {
|
||||
labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
|
||||
datasets: [{
|
||||
label: "Skip first dataset",
|
||||
borderColor: 'rgb(255, 0, 0)',
|
||||
backgroundColor: "rgba(255,255,0,0.5)",
|
||||
pointBackgroundColor: "rgba(220,220,220,1)",
|
||||
data: [NaN, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: "Skip mid dataset",
|
||||
borderColor: 'rgb(255, 0, 255)',
|
||||
backgroundColor: "rgba(0, 255, 0, 0.5)",
|
||||
pointBackgroundColor: "rgba(151,187,205,1)",
|
||||
hoverPointBackgroundColor: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), NaN, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
},{
|
||||
label: "Skip last dataset",
|
||||
borderColor: 'rgb(0, 255, 255)',
|
||||
backgroundColor: "rgba(0, 0, 255, 0.5)",
|
||||
pointBackgroundColor: "rgba(151,187,205,1)",
|
||||
hoverPointBackgroundColor: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), NaN]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.0,
|
||||
}
|
||||
},
|
||||
scale: {
|
||||
beginAtZero: true,
|
||||
reverse: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myRadar.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
window.myRadar = new Chart(document.getElementById("canvas"), config);
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
|
||||
$.each(config.data.datasets, function (i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.pop(); // remove the label first
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -41,7 +41,7 @@
|
||||
label: "My First dataset",
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
pointBackgroundColor: "rgba(220,220,220,1)",
|
||||
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Hidden dataset',
|
||||
hidden: true,
|
||||
@ -52,7 +52,7 @@
|
||||
pointBackgroundColor: "rgba(151,187,205,1)",
|
||||
hoverPointBackgroundColor: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
},]
|
||||
},
|
||||
options: {
|
||||
|
||||
@ -251,28 +251,12 @@
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = controlPoints.previous.x;
|
||||
point._model.controlPointNextX = controlPoints.next.x;
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
||||
point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
||||
|
||||
// Cap outer bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.next.y > this.chart.chartArea.bottom) {
|
||||
point._model.controlPointNextY = this.chart.chartArea.bottom;
|
||||
} else if (controlPoints.next.y < this.chart.chartArea.top) {
|
||||
point._model.controlPointNextY = this.chart.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.previous.y > this.chart.chartArea.bottom) {
|
||||
point._model.controlPointPreviousY = this.chart.chartArea.bottom;
|
||||
} else if (controlPoints.previous.y < this.chart.chartArea.top) {
|
||||
point._model.controlPointPreviousY = this.chart.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointPreviousY = controlPoints.previous.y;
|
||||
}
|
||||
point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
||||
point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
|
||||
@ -197,28 +197,12 @@
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = controlPoints.previous.x;
|
||||
point._model.controlPointNextX = controlPoints.next.x;
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
||||
point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
||||
|
||||
// Cap outer bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.next.y > this.chart.chartArea.bottom) {
|
||||
point._model.controlPointNextY = this.chart.chartArea.bottom;
|
||||
} else if (controlPoints.next.y < this.chart.chartArea.top) {
|
||||
point._model.controlPointNextY = this.chart.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.previous.y > this.chart.chartArea.bottom) {
|
||||
point._model.controlPointPreviousY = this.chart.chartArea.bottom;
|
||||
} else if (controlPoints.previous.y < this.chart.chartArea.top) {
|
||||
point._model.controlPointPreviousY = this.chart.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointPreviousY = controlPoints.previous.y;
|
||||
}
|
||||
point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
||||
point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
// Init if doesn't exist
|
||||
else if (!this._view[key]) {
|
||||
if (typeof value === 'number') {
|
||||
if (typeof value === 'number' && isNaN(this._view[key]) === false) {
|
||||
this._view[key] = value * ease;
|
||||
} else {
|
||||
this._view[key] = value || null;
|
||||
@ -61,14 +61,13 @@
|
||||
}
|
||||
// Number transitions
|
||||
else if (typeof value === 'number') {
|
||||
var startVal = this._start[key] !== undefined ? this._start[key] : 0;
|
||||
var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0;
|
||||
this._view[key] = ((this._model[key] - startVal) * ease) + startVal;
|
||||
}
|
||||
// Everything else
|
||||
else {
|
||||
this._view[key] = value;
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
if (ease === 1) {
|
||||
|
||||
@ -321,27 +321,29 @@
|
||||
aliasPixel = helpers.aliasPixel = function(pixelWidth) {
|
||||
return (pixelWidth % 2 === 0) ? 0 : 0.5;
|
||||
},
|
||||
splineCurve = helpers.splineCurve = function(FirstPoint, MiddlePoint, AfterPoint, t) {
|
||||
splineCurve = helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
|
||||
//Props to Rob Spencer at scaled innovation for his post on splining between points
|
||||
//http://scaledinnovation.com/analytics/splines/aboutSplines.html
|
||||
|
||||
// This function must also respect "skipped" points
|
||||
|
||||
var previous = FirstPoint,
|
||||
current = MiddlePoint,
|
||||
next = AfterPoint;
|
||||
var previous = firstPoint.skip ? middlePoint : firstPoint,
|
||||
current = middlePoint,
|
||||
next = afterPoint.skip ? middlePoint : afterPoint;
|
||||
|
||||
if (previous.skip) {
|
||||
previous = current;
|
||||
}
|
||||
if (next.skip) {
|
||||
next = current;
|
||||
}
|
||||
var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
|
||||
var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
|
||||
|
||||
var s01 = d01 / (d01 + d12);
|
||||
var s12 = d12 / (d01 + d12);
|
||||
|
||||
// If all points are the same, s01 & s02 will be inf
|
||||
s01 = isNaN(s01) ? 0 : s01;
|
||||
s12 = isNaN(s12) ? 0 : s12;
|
||||
|
||||
var fa = t * s01; // scaling factor for triangle Ta
|
||||
var fb = t * s12;
|
||||
|
||||
var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)),
|
||||
d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)),
|
||||
fa = t * d01 / (d01 + d12), // scaling factor for triangle Ta
|
||||
fb = t * d12 / (d01 + d12);
|
||||
return {
|
||||
previous: {
|
||||
x: current.x - fa * (next.x - previous.x),
|
||||
|
||||
@ -29,64 +29,38 @@
|
||||
fill: true, // do we fill in the area between the line and its base axis
|
||||
};
|
||||
|
||||
|
||||
Chart.elements.Line = Chart.Element.extend({
|
||||
lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
|
||||
var ctx = this._chart.ctx;
|
||||
|
||||
if (point._view.skip) {
|
||||
skipHandler.call(this, previousPoint, point, nextPoint);
|
||||
} else if (previousPoint._view.skip) {
|
||||
previousSkipHandler.call(this, previousPoint, point, nextPoint);
|
||||
} else {
|
||||
// Line between points
|
||||
ctx.bezierCurveTo(
|
||||
previousPoint._view.controlPointNextX,
|
||||
previousPoint._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
point._view.x,
|
||||
point._view.y
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
var _this = this;
|
||||
|
||||
var vm = this._view;
|
||||
var ctx = this._chart.ctx;
|
||||
var first = this._children[0];
|
||||
var last = this._children[this._children.length - 1];
|
||||
|
||||
ctx.save();
|
||||
|
||||
// Draw the background first (so the border is always on top)
|
||||
helpers.each(this._children, function(point, index) {
|
||||
|
||||
var previous = helpers.previousItem(this._children, index);
|
||||
var next = helpers.nextItem(this._children, index);
|
||||
|
||||
// First point moves to it's starting position no matter what
|
||||
if (!index) {
|
||||
ctx.moveTo(point._view.x, vm.scaleZero);
|
||||
}
|
||||
|
||||
// Skip this point, draw to scaleZero, move to next point, and draw to next point
|
||||
if (point._view.skip && !this.loop) {
|
||||
ctx.lineTo(previous._view.x, vm.scaleZero);
|
||||
ctx.moveTo(next._view.x, vm.scaleZero);
|
||||
return;
|
||||
}
|
||||
|
||||
// The previous line was skipped, so just draw a normal straight line to the point
|
||||
if (previous._view.skip) {
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw a bezier to point
|
||||
if (vm.tension > 0 && index) {
|
||||
//ctx.lineTo(point._view.x, point._view.y);
|
||||
ctx.bezierCurveTo(
|
||||
previous._view.controlPointNextX,
|
||||
previous._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
point._view.x,
|
||||
point._view.y
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw a straight line to the point
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
|
||||
}, this);
|
||||
|
||||
// For radial scales, loop back around to the first point
|
||||
if (this._loop) {
|
||||
// Draw a bezier line
|
||||
if (vm.tension > 0 && !first._view.skip) {
|
||||
function loopBackToStart(drawLineToCenter) {
|
||||
if (!first._view.skip && !last._view.skip) {
|
||||
// Draw a bezier line from last to first
|
||||
ctx.bezierCurveTo(
|
||||
last._view.controlPointNextX,
|
||||
last._view.controlPointNextY,
|
||||
@ -95,23 +69,68 @@
|
||||
first._view.x,
|
||||
first._view.y
|
||||
);
|
||||
return;
|
||||
} else if (drawLineToCenter) {
|
||||
// Go to center
|
||||
ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y);
|
||||
}
|
||||
// Draw a straight line
|
||||
ctx.lineTo(first._view.x, first._view.y);
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
// If we had points and want to fill this line, do so.
|
||||
if (this._children.length > 0 && vm.fill) {
|
||||
//Round off the line by going to the base of the chart, back to the start, then fill.
|
||||
ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero);
|
||||
ctx.lineTo(this._children[0]._view.x, vm.scaleZero);
|
||||
// Draw the background first (so the border is always on top)
|
||||
ctx.beginPath();
|
||||
|
||||
helpers.each(this._children, function(point, index) {
|
||||
var previous = helpers.previousItem(this._children, index);
|
||||
var next = helpers.nextItem(this._children, index);
|
||||
|
||||
// First point moves to it's starting position no matter what
|
||||
if (index === 0) {
|
||||
if (this._loop) {
|
||||
ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
|
||||
} else {
|
||||
ctx.moveTo(point._view.x, vm.scaleZero);
|
||||
}
|
||||
|
||||
if (point._view.skip) {
|
||||
if (!this._loop) {
|
||||
ctx.moveTo(next._view.x, this._view.scaleZero);
|
||||
}
|
||||
} else {
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
}
|
||||
} else {
|
||||
this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
|
||||
if (this._loop) {
|
||||
// Go to center
|
||||
ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y);
|
||||
} else {
|
||||
ctx.lineTo(previousPoint._view.x, this._view.scaleZero);
|
||||
ctx.moveTo(nextPoint._view.x, this._view.scaleZero);
|
||||
}
|
||||
}, function(previousPoint, point, nextPoint) {
|
||||
// If we skipped the last point, draw a line to ourselves so that the fill is nice
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
// For radial scales, loop back around to the first point
|
||||
if (this._loop) {
|
||||
loopBackToStart(true);
|
||||
} else {
|
||||
//Round off the line by going to the base of the chart, back to the start, then fill.
|
||||
ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero);
|
||||
ctx.lineTo(this._children[0]._view.x, vm.scaleZero);
|
||||
}
|
||||
|
||||
ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor;
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
|
||||
// Now draw the line between all the points with any borders
|
||||
ctx.lineCap = vm.borderCapStyle || Chart.defaults.global.elements.line.borderCapStyle;
|
||||
|
||||
@ -130,62 +149,20 @@
|
||||
var previous = helpers.previousItem(this._children, index);
|
||||
var next = helpers.nextItem(this._children, index);
|
||||
|
||||
if (!index) {
|
||||
ctx.moveTo(point._view.x, vm.scaleZero);
|
||||
}
|
||||
|
||||
// Skip this point and move to the next points zeroPoint
|
||||
if (point._view.skip && !this.loop) {
|
||||
ctx.moveTo(next._view.x, vm.scaleZero);
|
||||
return;
|
||||
}
|
||||
|
||||
// Previous point was skipped, just move to the point
|
||||
if (previous._view.skip) {
|
||||
if (index === 0) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
return;
|
||||
} else {
|
||||
this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
|
||||
ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
|
||||
}, function(previousPoint, point, nextPoint) {
|
||||
// If we skipped the last point, move up to our point preventing a line from being drawn
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
});
|
||||
}
|
||||
|
||||
// If First point, move to the point ahead of time (so a line doesn't get drawn up the left axis)
|
||||
if (!index) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
}
|
||||
|
||||
// Draw a bezier line to the point
|
||||
if (vm.tension > 0 && index) {
|
||||
ctx.bezierCurveTo(
|
||||
previous._view.controlPointNextX,
|
||||
previous._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
point._view.x,
|
||||
point._view.y
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw a straight line to the point
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
|
||||
}, this);
|
||||
|
||||
if (this._loop && !first._view.skip) {
|
||||
|
||||
// Draw a bezier line to the first point
|
||||
if (vm.tension > 0) {
|
||||
ctx.bezierCurveTo(
|
||||
last._view.controlPointNextX,
|
||||
last._view.controlPointNextY,
|
||||
first._view.controlPointPreviousX,
|
||||
first._view.controlPointPreviousY,
|
||||
first._view.x,
|
||||
first._view.y
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw a straight line to the first point
|
||||
ctx.lineTo(first._view.x, first._view.y);
|
||||
if (this._loop) {
|
||||
loopBackToStart();
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
@ -272,7 +272,10 @@
|
||||
return index * angleMultiplier - (Math.PI / 2);
|
||||
},
|
||||
getDistanceFromCenterForValue: function(value) {
|
||||
if (value === null) return 0; // null always in center
|
||||
if (value === null) {
|
||||
return 0; // null always in center
|
||||
}
|
||||
|
||||
// Take into account half font size + the yPadding of the top value
|
||||
var scalingFactor = this.drawingArea / (this.max - this.min);
|
||||
if (this.options.reverse) {
|
||||
|
||||
@ -192,7 +192,7 @@ describe('Line controller tests', function() {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: 200,
|
||||
right: xScale.left + 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
|
||||
@ -22,6 +22,8 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -30,6 +32,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -38,6 +44,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -46,6 +56,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
@ -68,21 +82,6 @@ describe('Line element tests', function() {
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['butt']
|
||||
@ -106,24 +105,18 @@ describe('Line element tests', function() {
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 0]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
@ -143,7 +136,9 @@ describe('Line element tests', function() {
|
||||
_index: 0,
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10
|
||||
y: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -151,7 +146,11 @@ describe('Line element tests', function() {
|
||||
_index: 1,
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -159,7 +158,11 @@ describe('Line element tests', function() {
|
||||
_index: 2,
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -167,7 +170,11 @@ describe('Line element tests', function() {
|
||||
_index: 3,
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
@ -198,6 +205,9 @@ describe('Line element tests', function() {
|
||||
var expected = [{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 2]
|
||||
@ -205,14 +215,14 @@ describe('Line element tests', function() {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, 2]
|
||||
@ -251,24 +261,171 @@ describe('Line element tests', function() {
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}];
|
||||
expect(mockContext.getCalls()).toEqual(expected);
|
||||
});
|
||||
|
||||
it ('should skip points correctly', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
// Create our points
|
||||
var points = [];
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 0,
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 1,
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 2,
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10,
|
||||
skip: true
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 3,
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
var line = new Chart.elements.Line({
|
||||
_datasetindex: 2,
|
||||
_chart: {
|
||||
ctx: mockContext,
|
||||
},
|
||||
_children: points,
|
||||
// Need to provide some settings
|
||||
_view: {
|
||||
fill: true,
|
||||
scaleZero: 2, // for filling lines
|
||||
tension: 0.0, // no bezier curve for now
|
||||
}
|
||||
});
|
||||
|
||||
line.draw();
|
||||
|
||||
var expected = [{
|
||||
name: 'save',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 2]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [19, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 2]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['butt']
|
||||
}, {
|
||||
name: 'setLineDash',
|
||||
args: [
|
||||
[]
|
||||
]
|
||||
}, {
|
||||
name: 'setLineDashOffset',
|
||||
args: [0.0]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['miter']
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [3]
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
name: 'moveTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
name: 'moveTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
@ -289,7 +446,11 @@ describe('Line element tests', function() {
|
||||
_index: 0,
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10
|
||||
y: 10,
|
||||
controlPointPreviousX: 0,
|
||||
controlPointPreviousY: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -297,7 +458,11 @@ describe('Line element tests', function() {
|
||||
_index: 1,
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -305,7 +470,11 @@ describe('Line element tests', function() {
|
||||
_index: 2,
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -313,7 +482,11 @@ describe('Line element tests', function() {
|
||||
_index: 3,
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
@ -326,9 +499,12 @@ describe('Line element tests', function() {
|
||||
_loop: true, // want the line to loop back to the first point
|
||||
// Need to provide some settings
|
||||
_view: {
|
||||
fill: false, // don't want to fill
|
||||
fill: true, // don't want to fill
|
||||
tension: 0.0, // no bezier curve for now
|
||||
scaleZero: 0,
|
||||
scaleZero: {
|
||||
x: 3,
|
||||
y: 2
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@ -337,24 +513,36 @@ describe('Line element tests', function() {
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 0]
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [19, -5, 0, 10, 0, 10]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['butt']
|
||||
@ -378,27 +566,21 @@ describe('Line element tests', function() {
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 0]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [15, -10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'bezierCurveTo',
|
||||
args: [19, -5, 0, 10, 0, 10]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
@ -408,7 +590,7 @@ describe('Line element tests', function() {
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should draw with bezier curves if tension > 0', function() {
|
||||
it('should be able to draw with a loop back to the beginning point when there is a skip in the middle of the dataset', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
// Create our points
|
||||
@ -419,10 +601,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
controlPointNextX: 1,
|
||||
controlPointNextY: 1,
|
||||
controlPointPreviousX: 0,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointPreviousY: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -431,10 +613,11 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0,
|
||||
controlPointNextX: 6,
|
||||
controlPointNextY: 7,
|
||||
controlPointPreviousX: 4,
|
||||
controlPointPreviousY: 3,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0,
|
||||
skip: true
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -443,10 +626,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10,
|
||||
controlPointNextX: 16,
|
||||
controlPointNextY: 17,
|
||||
controlPointPreviousX: 14,
|
||||
controlPointPreviousY: 13,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
@ -455,10 +638,10 @@ describe('Line element tests', function() {
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5,
|
||||
controlPointNextX: 20,
|
||||
controlPointNextY: 21,
|
||||
controlPointPreviousX: 18,
|
||||
controlPointPreviousY: 17,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
@ -468,51 +651,47 @@ describe('Line element tests', function() {
|
||||
ctx: mockContext,
|
||||
},
|
||||
_children: points,
|
||||
_loop: true, // want the line to loop back to the first point
|
||||
// Need to provide some settings
|
||||
_view: {
|
||||
fill: true,
|
||||
scaleZero: 2, // for filling lines
|
||||
tension: 0.5, // have bezier curves
|
||||
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(255, 255, 0)',
|
||||
borderDash: [2, 2],
|
||||
borderDashOffset: 1.5,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 4,
|
||||
backgroundColor: 'rgb(0, 0, 0)'
|
||||
fill: true, // don't want to fill
|
||||
tension: 0.0, // no bezier curve for now
|
||||
scaleZero: {
|
||||
x: 3,
|
||||
y: 2
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
line.draw();
|
||||
|
||||
var expected = [{
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 2]
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [1, 1, 4, 3, 5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [6, 7, 14, 13, 15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [16, 17, 18, 17, 19, -5]
|
||||
name: 'lineTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [19, 2]
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 2]
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [19, -5, 0, 10, 0, 10]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgb(0, 0, 0)']
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
@ -521,52 +700,349 @@ describe('Line element tests', function() {
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['round']
|
||||
args: ['butt']
|
||||
}, {
|
||||
name: 'setLineDash',
|
||||
args: [
|
||||
[2, 2]
|
||||
[]
|
||||
]
|
||||
}, {
|
||||
name: 'setLineDashOffset',
|
||||
args: [1.5]
|
||||
args: [0.0]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['bevel']
|
||||
args: ['miter']
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [4]
|
||||
args: [3]
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgb(255, 255, 0)']
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 2]
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
name: 'moveTo',
|
||||
args: [15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [1, 1, 4, 3, 5, 0]
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [6, 7, 14, 13, 15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [16, 17, 18, 17, 19, -5]
|
||||
args: [19, -5, 0, 10, 0, 10]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}];
|
||||
expect(mockContext.getCalls()).toEqual(expected);
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should be able to draw with a loop back to the beginning point when the first point is skipped', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
// Create our points
|
||||
var points = [];
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 0,
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
controlPointPreviousX: 0,
|
||||
controlPointPreviousY: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10,
|
||||
skip: true
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 1,
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0,
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 2,
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 3,
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5
|
||||
}
|
||||
}));
|
||||
|
||||
var line = new Chart.elements.Line({
|
||||
_datasetindex: 2,
|
||||
_chart: {
|
||||
ctx: mockContext,
|
||||
},
|
||||
_children: points,
|
||||
_loop: true, // want the line to loop back to the first point
|
||||
// Need to provide some settings
|
||||
_view: {
|
||||
fill: true, // don't want to fill
|
||||
tension: 0.0, // no bezier curve for now
|
||||
scaleZero: {
|
||||
x: 3,
|
||||
y: 2
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
line.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['butt']
|
||||
}, {
|
||||
name: 'setLineDash',
|
||||
args: [
|
||||
[]
|
||||
]
|
||||
}, {
|
||||
name: 'setLineDashOffset',
|
||||
args: [0.0]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['miter']
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [3]
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [15, -10, 19, -5, 19, -5]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should be able to draw with a loop back to the beginning point when the last point is skipped', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
// Create our points
|
||||
var points = [];
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 0,
|
||||
_view: {
|
||||
x: 0,
|
||||
y: 10,
|
||||
controlPointPreviousX: 0,
|
||||
controlPointPreviousY: 10,
|
||||
controlPointNextX: 0,
|
||||
controlPointNextY: 10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 1,
|
||||
_view: {
|
||||
x: 5,
|
||||
y: 0,
|
||||
controlPointPreviousX: 5,
|
||||
controlPointPreviousY: 0,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 0,
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 2,
|
||||
_view: {
|
||||
x: 15,
|
||||
y: -10,
|
||||
controlPointPreviousX: 15,
|
||||
controlPointPreviousY: -10,
|
||||
controlPointNextX: 15,
|
||||
controlPointNextY: -10
|
||||
}
|
||||
}));
|
||||
points.push(new Chart.elements.Point({
|
||||
_datasetindex: 2,
|
||||
_index: 3,
|
||||
_view: {
|
||||
x: 19,
|
||||
y: -5,
|
||||
controlPointPreviousX: 19,
|
||||
controlPointPreviousY: -5,
|
||||
controlPointNextX: 19,
|
||||
controlPointNextY: -5,
|
||||
skip: true
|
||||
}
|
||||
}));
|
||||
|
||||
var line = new Chart.elements.Line({
|
||||
_datasetindex: 2,
|
||||
_chart: {
|
||||
ctx: mockContext,
|
||||
},
|
||||
_children: points,
|
||||
_loop: true, // want the line to loop back to the first point
|
||||
// Need to provide some settings
|
||||
_view: {
|
||||
fill: true, // don't want to fill
|
||||
tension: 0.0, // no bezier curve for now
|
||||
scaleZero: {
|
||||
x: 3,
|
||||
y: 2
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
line.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'lineTo',
|
||||
args: [3, 2]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineCap',
|
||||
args: ['butt']
|
||||
}, {
|
||||
name: 'setLineDash',
|
||||
args: [
|
||||
[]
|
||||
]
|
||||
}, {
|
||||
name: 'setLineDashOffset',
|
||||
args: [0.0]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['miter']
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [3]
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgba(0,0,0,0.1)']
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [0, 10]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [0, 10, 5, 0, 5, 0]
|
||||
}, {
|
||||
name: 'bezierCurveTo',
|
||||
args: [5, 0, 15, -10, 15, -10]
|
||||
}, {
|
||||
name: 'moveTo',
|
||||
args: [19, -5]
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: [],
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user