diff --git a/docs/02-Line-Chart.md b/docs/02-Line-Chart.md index 2202fcb67..aa10c4d8f 100644 --- a/docs/02-Line-Chart.md +++ b/docs/02-Line-Chart.md @@ -37,14 +37,16 @@ var data = { label: "My First dataset", // Boolean - if true fill the area under the line - fill: false, + fill: false, + + // Tension - bezier curve tension of the line. Set to 0 to draw straight lines connecting points + // Used to be called "tension" but was renamed for consistency. The old option name continues to work for compatibility. + lineTension: 0.1, // String - the color to fill the area under the line with if fill is true - backgroundColor: "rgba(220,220,220,0.2)", + backgroundColor: "rgba(220,220,220,0.2)", - // The properties below allow an array to be specified to change the value of the item at the given index - - // String or array - Line color + // String - Line color borderColor: "rgba(220,220,220,1)", // String - cap style of the line. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap @@ -57,34 +59,39 @@ var data = { borderDashOffset: 0.0, // String - line join style. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin - borderJoinStyle: 'miter', + borderJoinStyle: 'miter', + + // The properties below allow an array to be specified to change the value of the item at the given index - // String or array - Point stroke color + // String or Array - Point stroke color pointBorderColor: "rgba(220,220,220,1)", - // String or array - Point fill color + // String or Array - Point fill color pointBackgroundColor: "#fff", - // Number or array - Stroke width of point border + // Number or Array - Stroke width of point border pointBorderWidth: 1, - // Number or array - Radius of point when hovered + // Number or Array - Radius of point when hovered pointHoverRadius: 5, - // String or array - point background color when hovered + // String or Array - point background color when hovered pointHoverBackgroundColor: "rgba(220,220,220,1)", - // Point border color when hovered + // String or Array - Point border color when hovered pointHoverBorderColor: "rgba(220,220,220,1)", - // Number or array - border width of point when hovered - pointHoverBorderWidth: 2, + // Number or Array - border width of point when hovered + pointHoverBorderWidth: 2, - // Tension - bezier curve tension of the line. Set to 0 to draw straight Wlines connecting points - tension: 0.1, - - // Number - the pixel size of the point shape. Can be set to 0 to not render a circle over the point - radius: 1, + // Number or Array - the pixel size of the point shape. Can be set to 0 to not render a circle over the point + // Used to be called "radius" but was renamed for consistency. The old option name continues to work for compatibility. + pointRadius: 1, + + // Number or Array - the pixel size of the non-displayed point that reacts to mouse hover events + // + // Used to be called "hitRadius" but was renamed for consistency. The old option name continues to work for compatibility. + pointHitRadius: 10, // The actual data data: [65, 59, 80, 81, 56, 55, 40], diff --git a/samples/different-point-sizes.html b/samples/different-point-sizes.html new file mode 100644 index 000000000..926eecfba --- /dev/null +++ b/samples/different-point-sizes.html @@ -0,0 +1,154 @@ + + + + + Line Chart + + + + + + +
+ +
+
+
+ + + + + + + diff --git a/samples/line-legend.html b/samples/line-legend.html index e454eb08f..92e5e5b5a 100644 --- a/samples/line-legend.html +++ b/samples/line-legend.html @@ -52,8 +52,9 @@ fill: false, borderDash: [5, 5], }, { - label: "My Third dataset", + label: "My Third dataset - No bezier", data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()], + lineTension: 0, fill: false, }, { label: "My Fourth dataset", diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index dcce78f99..a62b285ac 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -86,9 +86,16 @@ module.exports = function(Chart) { // Data line._children = points; // Model + + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().tension !== undefined) && (this.getDataset().lineTension === undefined)) + { + this.getDataset().lineTension = this.getDataset().tension; + } + line._model = { // Appearance - tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().lineTension, this.chart.options.elements.line.tension), backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor), borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth), borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor), @@ -178,18 +185,28 @@ module.exports = function(Chart) { point._index = index; // Desired view properties + + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined)) + { + this.getDataset().pointRadius = this.getDataset().radius; + } + if ((this.getDataset().hitRadius !== undefined) && (this.getDataset().pointHitRadius === undefined)) + { + this.getDataset().pointHitRadius = this.getDataset().hitRadius; + } + point._model = { x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo), y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo), // Appearance - tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), - radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius), + radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius), pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle), backgroundColor: this.getPointBackgroundColor(point, index), borderColor: this.getPointBorderColor(point, index), borderWidth: this.getPointBorderWidth(point, index), // Tooltip - hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius) + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointHitRadius, index, this.chart.options.elements.point.hitRadius) }; point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); @@ -233,7 +250,7 @@ module.exports = function(Chart) { helpers.previousItem(this.getDataset().metaData, index)._model, point._model, helpers.nextItem(this.getDataset().metaData, index)._model, - point._model.tension + this.getDataset().metaDataset._model.tension ); // Prevent the bezier going outside of the bounds of the graph @@ -281,7 +298,13 @@ module.exports = function(Chart) { var dataset = this.chart.data.datasets[point._datasetIndex]; var index = point._index; - point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius); + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined)) + { + this.getDataset().pointRadius = this.getDataset().radius; + } + + point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius); point._model.backgroundColor = this.getPointBackgroundColor(point, index); point._model.borderColor = this.getPointBorderColor(point, index); point._model.borderWidth = this.getPointBorderWidth(point, index); diff --git a/test/controller.line.tests.js b/test/controller.line.tests.js index a4d12bdb3..0d93cd2fb 100644 --- a/test/controller.line.tests.js +++ b/test/controller.line.tests.js @@ -284,7 +284,6 @@ describe('Line controller tests', function() { radius: 3, pointStyle: 'circle', skip: false, - tension: 0.1, // Point x: 82, @@ -300,7 +299,6 @@ describe('Line controller tests', function() { expect(chart.data.datasets[0].metaData[1]._model).toEqual({ x: 132, y: 15, - tension: 0.1, radius: 3, pointStyle: 'circle', backgroundColor: 'rgba(0,0,0,0.1)', @@ -317,7 +315,6 @@ describe('Line controller tests', function() { expect(chart.data.datasets[0].metaData[2]._model).toEqual({ x: 182, y: 156, - tension: 0.1, radius: 3, pointStyle: 'circle', backgroundColor: 'rgba(0,0,0,0.1)', @@ -339,7 +336,6 @@ describe('Line controller tests', function() { radius: 3, pointStyle: 'circle', skip: false, - tension: 0.1, // Point x: 232, @@ -391,7 +387,6 @@ describe('Line controller tests', function() { expect(chart.data.datasets[0].metaData[0]._model).toEqual({ x: 82, y: 62, - tension: 0, radius: 22, pointStyle: 'circle', backgroundColor: 'rgb(128, 129, 130)', @@ -408,7 +403,6 @@ describe('Line controller tests', function() { expect(chart.data.datasets[0].metaData[1]._model).toEqual({ x: 132, y: 15, - tension: 0, radius: 22, pointStyle: 'circle', backgroundColor: 'rgb(128, 129, 130)', @@ -430,7 +424,6 @@ describe('Line controller tests', function() { radius: 22, pointStyle: 'circle', skip: false, - tension: 0, // Point x: 182, @@ -451,7 +444,6 @@ describe('Line controller tests', function() { radius: 22, pointStyle: 'circle', skip: false, - tension: 0, // Point x: 232, @@ -464,9 +456,174 @@ describe('Line controller tests', function() { controlPointNextY: 194, }); + // Use the consistent name "lineTension", setting but overwriting + // another value in "tension" + chart.data.datasets[0].lineTension = 0.5; + chart.data.datasets[0].tension = 0.7; + + controller.update(); + + expect(chart.data.datasets[0].metaDataset._model).toEqual({ + backgroundColor: 'rgb(98, 98, 98)', + borderCapStyle: 'butt', + borderColor: 'rgb(8, 8, 8)', + borderDash: [2, 3], + borderDashOffset: 7, + borderJoinStyle: 'miter', + borderWidth: 0.55, + fill: false, + tension: 0.5, + + scaleTop: 0, + scaleBottom: 200, + scaleZero: 156, + }); + + expect(chart.data.datasets[0].metaData[0]._model).toEqual({ + x: 82, + y: 62, + radius: 22, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 3.3, + skip: false, + controlPointPreviousX: 82, + controlPointPreviousY: 62, + controlPointNextX: 107, + controlPointNextY: 38.5 + }); + + expect(chart.data.datasets[0].metaData[1]._model).toEqual({ + x: 132, + y: 15, + radius: 22, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 3.3, + skip: false, + controlPointPreviousX: 116.2771987579006, + controlPointPreviousY: 0.22056683242656483, + controlPointNextX: 166.2771987579006, + controlPointNextY: 47.22056683242656 + }); + + // Use the consistent name "pointRadius", setting but overwriting + // another value in "radius" + chart.data.datasets[0].pointRadius = 250; + chart.data.datasets[0].radius = 20; + + controller.update(); + + expect(chart.data.datasets[0].metaDataset._model).toEqual({ + backgroundColor: 'rgb(98, 98, 98)', + borderCapStyle: 'butt', + borderColor: 'rgb(8, 8, 8)', + borderDash: [2, 3], + borderDashOffset: 7, + borderJoinStyle: 'miter', + borderWidth: 0.55, + fill: false, + tension: 0.5, + + scaleTop: 0, + scaleBottom: 200, + scaleZero: 156, + }); + + expect(chart.data.datasets[0].metaData[0]._model).toEqual({ + x: 82, + y: 62, + radius: 250, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 3.3, + skip: false, + controlPointPreviousX: 82, + controlPointPreviousY: 62, + controlPointNextX: 107, + controlPointNextY: 38.5 + }); + + expect(chart.data.datasets[0].metaData[1]._model).toEqual({ + x: 132, + y: 15, + radius: 250, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 3.3, + skip: false, + controlPointPreviousX: 116.2771987579006, + controlPointPreviousY: 0.22056683242656483, + controlPointNextX: 166.2771987579006, + controlPointNextY: 47.22056683242656 + }); + + // Use the consistent name "pointHitRadius", setting but overwriting + // another value in "hitRadius" + chart.data.datasets[0].pointHitRadius = 123; + chart.data.datasets[0].hitRadius = 23; + + controller.update(); + + expect(chart.data.datasets[0].metaDataset._model).toEqual({ + backgroundColor: 'rgb(98, 98, 98)', + borderCapStyle: 'butt', + borderColor: 'rgb(8, 8, 8)', + borderDash: [2, 3], + borderDashOffset: 7, + borderJoinStyle: 'miter', + borderWidth: 0.55, + fill: false, + tension: 0.5, + + scaleTop: 0, + scaleBottom: 200, + scaleZero: 156, + }); + + expect(chart.data.datasets[0].metaData[0]._model).toEqual({ + x: 82, + y: 62, + radius: 250, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 123, + skip: false, + controlPointPreviousX: 82, + controlPointPreviousY: 62, + controlPointNextX: 107, + controlPointNextY: 38.5 + }); + + expect(chart.data.datasets[0].metaData[1]._model).toEqual({ + x: 132, + y: 15, + radius: 250, + pointStyle: 'circle', + backgroundColor: 'rgb(128, 129, 130)', + borderColor: 'rgb(56, 57, 58)', + borderWidth: 1.123, + hitRadius: 123, + skip: false, + controlPointPreviousX: 116.2771987579006, + controlPointPreviousY: 0.22056683242656483, + controlPointNextX: 166.2771987579006, + controlPointNextY: 47.22056683242656 + }); + // Use custom styles for lines & first point chart.data.datasets[0].metaDataset.custom = { - tension: 0.25, + tension: 0.15, backgroundColor: 'rgb(55, 55, 54)', borderColor: 'rgb(8, 7, 6)', borderWidth: 0.3, @@ -483,7 +640,6 @@ describe('Line controller tests', function() { backgroundColor: 'rgb(0, 1, 3)', borderColor: 'rgb(4, 6, 8)', borderWidth: 0.787, - tension: 0.15, skip: true, hitRadius: 5, }; @@ -499,7 +655,7 @@ describe('Line controller tests', function() { borderJoinStyle: 'round', borderWidth: 0.3, fill: true, - tension: 0.25, + tension: 0.15, scaleTop: 0, scaleBottom: 200, @@ -509,7 +665,6 @@ describe('Line controller tests', function() { expect(chart.data.datasets[0].metaData[0]._model).toEqual({ x: 82, y: 62, - tension: 0.15, radius: 2.2, pointStyle: 'circle', backgroundColor: 'rgb(0, 1, 3)', @@ -1281,6 +1436,17 @@ describe('Line controller tests', function() { expect(point._model.borderWidth).toBe(2.1); expect(point._model.radius).toBe(3.3); + // Use the consistent name "pointRadius", setting but overwriting + // another value in "radius" + chart.data.datasets[0].pointRadius = 250; + chart.data.datasets[0].radius = 20; + + controller.setHoverStyle(point); + expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)'); + expect(point._model.borderColor).toBe('rgb(123, 125, 127)'); + expect(point._model.borderWidth).toBe(2.1); + expect(point._model.radius).toBe(3.3); + // Custom style point.custom = { hoverRadius: 4.4, @@ -1423,6 +1589,17 @@ describe('Line controller tests', function() { expect(point._model.borderWidth).toBe(2.1); expect(point._model.radius).toBe(3.3); + // Use the consistent name "pointRadius", setting but overwriting + // another value in "radius" + chart.data.datasets[0].pointRadius = 250; + chart.data.datasets[0].radius = 20; + + controller.removeHoverStyle(point); + expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)'); + expect(point._model.borderColor).toBe('rgb(123, 125, 127)'); + expect(point._model.borderWidth).toBe(2.1); + expect(point._model.radius).toBe(250); + // Custom style point.custom = { radius: 4.4,