Adds different point styles

This commit is contained in:
Mathias Küsel 2016-01-16 18:07:57 +01:00
parent f6b18a5998
commit 655c1152eb
6 changed files with 386 additions and 25 deletions

View File

@ -209,6 +209,7 @@ line | - | - | -
*line*.fill | Boolean | true |
point | - | - | -
*point*.radius | Number | 3 | Default point radius
*point*.pointStyle | String | 'circle' | Default point style
*point*.backgroundColor | Color | `Chart.defaults.global.defaultColor` | Default point fill color
*point*.borderWidth | Number | 1 | Default point stroke width
*point*.borderColor | Color | `Chart.defaults.global.defaultColor` | Default point stroke color

View File

@ -186,6 +186,7 @@
// 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),
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),

View File

@ -19,6 +19,7 @@
Chart.defaults.global.elements.point = {
radius: 3,
pointStyle: 'circle',
backgroundColor: Chart.defaults.global.defaultColor,
borderWidth: 1,
borderColor: Chart.defaults.global.defaultColor,
@ -69,17 +70,88 @@
if (vm.radius > 0 || vm.borderWidth > 0) {
ctx.beginPath();
ctx.arc(vm.x, vm.y, vm.radius || Chart.defaults.global.elements.point.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor;
ctx.lineWidth = vm.borderWidth || Chart.defaults.global.elements.point.borderWidth;
ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor;
ctx.fill();
var radius = vm.radius || Chart.defaults.global.elements.point.radius;
switch (vm.pointStyle) {
case 'circle':
default:
ctx.beginPath();
ctx.arc(vm.x, vm.y, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
break;
case 'triangle':
ctx.beginPath();
var edgeLength = 3 * radius / Math.sqrt(3);
var height = edgeLength * Math.sqrt(3) / 2;
ctx.moveTo(vm.x - edgeLength / 2, vm.y + height / 3);
ctx.lineTo(vm.x + edgeLength / 2, vm.y + height / 3);
ctx.lineTo(vm.x, vm.y - 2 * height / 3);
ctx.closePath();
ctx.fill();
break;
case 'rect':
ctx.fillRect(vm.x - radius, vm.y - radius, 2 * radius, 2 * radius);
ctx.strokeRect(vm.x - radius, vm.y - radius, 2 * radius, 2 * radius);
break;
case 'rectRot':
ctx.translate(vm.x, vm.y);
ctx.rotate(Math.PI / 4);
ctx.fillRect(-radius, -radius, 2 * radius, 2 * radius);
ctx.strokeRect(-radius, -radius, 2 * radius, 2 * radius);
ctx.setTransform(1, 0, 0, 1, 0, 0);
break;
case 'cross':
ctx.beginPath();
ctx.moveTo(vm.x, vm.y + radius);
ctx.lineTo(vm.x, vm.y - radius);
ctx.moveTo(vm.x - radius, vm.y);
ctx.lineTo(vm.x + radius, vm.y);
ctx.closePath();
break;
case 'crossRot':
ctx.beginPath();
var xOffset = Math.cos(Math.PI / 4) * radius;
var yOffset = Math.sin(Math.PI / 4) * radius;
ctx.moveTo(vm.x - xOffset, vm.y - yOffset);
ctx.lineTo(vm.x + xOffset, vm.y + yOffset);
ctx.moveTo(vm.x - xOffset, vm.y + yOffset);
ctx.lineTo(vm.x + xOffset, vm.y - yOffset);
ctx.closePath();
break;
case 'star':
ctx.beginPath();
ctx.moveTo(vm.x, vm.y + radius);
ctx.lineTo(vm.x, vm.y - radius);
ctx.moveTo(vm.x - radius, vm.y);
ctx.lineTo(vm.x + radius, vm.y);
var xOffset = Math.cos(Math.PI / 4) * radius;
var yOffset = Math.sin(Math.PI / 4) * radius;
ctx.moveTo(vm.x - xOffset, vm.y - yOffset);
ctx.lineTo(vm.x + xOffset, vm.y + yOffset);
ctx.moveTo(vm.x - xOffset, vm.y + yOffset);
ctx.lineTo(vm.x + xOffset, vm.y - yOffset);
ctx.closePath();
break;
case 'line':
ctx.beginPath();
ctx.moveTo(vm.x - radius, vm.y);
ctx.lineTo(vm.x + radius, vm.y);
ctx.closePath();
break;
case 'dash':
ctx.beginPath();
ctx.moveTo(vm.x, vm.y);
ctx.lineTo(vm.x + radius, vm.y);
ctx.closePath();
break;
}
ctx.stroke();
}
}

View File

@ -238,6 +238,7 @@ describe('Line controller tests', function() {
hoverRadius: 4,
hoverBorderWidth: 1,
radius: 3,
pointStyle: 'circle'
}
},
scales: {
@ -281,6 +282,7 @@ describe('Line controller tests', function() {
borderColor: Chart.defaults.global.defaultColor,
hitRadius: 1,
radius: 3,
pointStyle: 'circle',
skip: false,
tension: 0.1,
@ -301,6 +303,7 @@ describe('Line controller tests', function() {
borderColor: Chart.defaults.global.defaultColor,
hitRadius: 1,
radius: 3,
pointStyle: 'circle',
skip: false,
tension: 0.1,
@ -321,6 +324,7 @@ describe('Line controller tests', function() {
borderColor: Chart.defaults.global.defaultColor,
hitRadius: 1,
radius: 3,
pointStyle: 'circle',
skip: false,
tension: 0.1,
@ -341,6 +345,7 @@ describe('Line controller tests', function() {
borderColor: Chart.defaults.global.defaultColor,
hitRadius: 1,
radius: 3,
pointStyle: 'circle',
skip: false,
tension: 0.1,
@ -397,6 +402,7 @@ describe('Line controller tests', function() {
borderColor: 'rgb(56, 57, 58)',
hitRadius: 3.3,
radius: 22,
pointStyle: 'circle',
skip: false,
tension: 0,
@ -417,6 +423,7 @@ describe('Line controller tests', function() {
borderColor: 'rgb(56, 57, 58)',
hitRadius: 3.3,
radius: 22,
pointStyle: 'circle',
skip: false,
tension: 0,
@ -437,6 +444,7 @@ describe('Line controller tests', function() {
borderColor: 'rgb(56, 57, 58)',
hitRadius: 3.3,
radius: 22,
pointStyle: 'circle',
skip: false,
tension: 0,
@ -457,6 +465,7 @@ describe('Line controller tests', function() {
borderColor: 'rgb(56, 57, 58)',
hitRadius: 3.3,
radius: 22,
pointStyle: 'circle',
skip: false,
tension: 0,
@ -519,6 +528,7 @@ describe('Line controller tests', function() {
borderColor: 'rgb(4, 6, 8)',
hitRadius: 5,
radius: 2.2,
pointStyle: 'circle',
skip: true,
tension: 0.15,

View File

@ -77,6 +77,7 @@ describe('Point element tests', function() {
// Attach a view object as if we were the controller
point._view = {
radius: 2,
pointStyle: 'circle',
hitRadius: 3,
borderColor: 'rgba(1, 2, 3, 1)',
borderWidth: 6,
@ -89,15 +90,6 @@ describe('Point element tests', function() {
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'beginPath',
args: []
}, {
name: 'arc',
args: [10, 15, 2, 0, 2 * Math.PI]
}, {
name: 'closePath',
args: [],
}, {
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
@ -106,6 +98,15 @@ describe('Point element tests', function() {
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'arc',
args: [10, 15, 2, 0, 2 * Math.PI]
}, {
name: 'closePath',
args: [],
}, {
name: 'fill',
args: [],
@ -113,6 +114,280 @@ describe('Point element tests', function() {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'triangle';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [10 - 3 * 2 / Math.sqrt(3) / 2, 15 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3]
}, {
name: 'lineTo',
args: [10 + 3 * 2 / Math.sqrt(3) / 2, 15 + 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3],
}, {
name: 'lineTo',
args: [10, 15 - 2 * 3 * 2 / Math.sqrt(3) * Math.sqrt(3) / 2 / 3],
}, {
name: 'closePath',
args: [],
}, {
name: 'fill',
args: [],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'rect';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'fillRect',
args: [8, 13, 4, 4]
}, {
name: 'strokeRect',
args: [8, 13, 4, 4]
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'rectRot';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'translate',
args: [10, 15]
}, {
name: 'rotate',
args: [Math.PI / 4]
}, {
name: 'fillRect',
args: [-2, -2, 4, 4],
}, {
name: 'strokeRect',
args: [-2, -2, 4, 4],
}, {
name: 'setTransform',
args: [1, 0, 0, 1, 0, 0],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'cross';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [10, 17]
}, {
name: 'lineTo',
args: [10, 13],
}, {
name: 'moveTo',
args: [8, 15],
}, {
name: 'lineTo',
args: [12, 15],
},{
name: 'closePath',
args: [],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'crossRot';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [10 - Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2]
}, {
name: 'lineTo',
args: [10 + Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2],
}, {
name: 'moveTo',
args: [10 - Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2],
}, {
name: 'lineTo',
args: [10 + Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2],
}, {
name: 'closePath',
args: [],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'star';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [10, 17]
}, {
name: 'lineTo',
args: [10, 13],
}, {
name: 'moveTo',
args: [8, 15],
}, {
name: 'lineTo',
args: [12, 15],
},{
name: 'moveTo',
args: [10 - Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2]
}, {
name: 'lineTo',
args: [10 + Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2],
}, {
name: 'moveTo',
args: [10 - Math.cos(Math.PI / 4) * 2, 15 + Math.sin(Math.PI / 4) * 2],
}, {
name: 'lineTo',
args: [10 + Math.cos(Math.PI / 4) * 2, 15 - Math.sin(Math.PI / 4) * 2],
}, {
name: 'closePath',
args: [],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'line';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [8, 15]
}, {
name: 'lineTo',
args: [12, 15],
}, {
name: 'closePath',
args: [],
}, {
name: 'stroke',
args: []
}]);
mockContext.resetCalls();
point._view.pointStyle = 'dash';
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'setStrokeStyle',
args: ['rgba(1, 2, 3, 1)']
}, {
name: 'setLineWidth',
args: [6]
}, {
name: 'setFillStyle',
args: ['rgba(0, 255, 0)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [10, 15]
}, {
name: 'lineTo',
args: [12, 15],
}, {
name: 'closePath',
args: [],
}, {
name: 'stroke',
args: []
}]);
});
it ('should draw correctly with default settings if necessary', function() {
@ -137,15 +412,6 @@ describe('Point element tests', function() {
point.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'beginPath',
args: []
}, {
name: 'arc',
args: [10, 15, 2, 0, 2 * Math.PI]
}, {
name: 'closePath',
args: [],
}, {
name: 'setStrokeStyle',
args: ['rgba(0,0,0,0.1)']
}, {
@ -154,6 +420,15 @@ describe('Point element tests', function() {
}, {
name: 'setFillStyle',
args: ['rgba(0,0,0,0.1)']
}, {
name: 'beginPath',
args: []
}, {
name: 'arc',
args: [10, 15, 2, 0, 2 * Math.PI]
}, {
name: 'closePath',
args: [],
}, {
name: 'fill',
args: [],

View File

@ -82,7 +82,9 @@
save: function() {},
setLineDash: function() {},
stroke: function() {},
translate: function() {},
strokeRect: function(x, y, w, h) {},
setTransform: function(a, b, c, d, e, f) {},
translate: function(x, y) {},
};
// attach methods to the class itself