Skip to content

Commit 2a7ece1

Browse files
committed
Add box annotations and some refactoring
1 parent 81fb154 commit 2a7ece1

File tree

5 files changed

+343
-46
lines changed

5 files changed

+343
-46
lines changed

README.md

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
An annotation plugin for Chart.js >= 2.1.3
44

5+
Currently draws lines and boxes on the chart area.
6+
57

68
## Configuration
79

@@ -13,7 +15,7 @@ To configure the annotations plugin, you can simply add new config options to yo
1315
annotations: [{
1416
type: 'line',
1517
mode: 'horizontal',
16-
scaleID: 'y-axis-0',
18+
scaleID: 'y-axis-1',
1719
value: '25',
1820
borderColor: 'red',
1921
borderWidth: 2
@@ -22,9 +24,71 @@ To configure the annotations plugin, you can simply add new config options to yo
2224
}
2325
```
2426

27+
### Line Annotations
28+
Vertical or horizontal lines are supported.
29+
30+
```javascript
31+
{
32+
type: 'line',
33+
// set to 'vertical' to draw a vertical line
34+
mode: 'horizontal',
35+
36+
// ID of the scale to bind onto
37+
scaleID: 'y-axis-1',
38+
39+
// Data value to draw the line at
40+
value: 25,
41+
42+
// Line color
43+
borderColor: 'red',
44+
45+
// Line width
46+
borderWidth: 2
47+
}
48+
```
49+
50+
### Box Annotations
51+
Box annotations are supported. If one of the axes is not specified, the box will take the entire chart dimension.
52+
53+
The 4 coordinates, xMin, xMax, yMin, yMax are optional. If not specified, the box is expanded out to the edges
54+
55+
```javascript
56+
{
57+
type: 'box',
58+
59+
// ID of the X scale to bind onto
60+
xScaleID: 'x-axis-1',
61+
62+
// ID of the Y scale to bind onto
63+
scaleID: 'y-axis-1',
64+
65+
// Left edge of the box. in units along the x axis
66+
xMin: 25,
67+
68+
// Right edge of the box
69+
xMax: 40,
70+
71+
// Top edge of the box in units along the y axis
72+
yMax: 20,
73+
74+
// Bottom edge of the box
75+
yMin: 15,
76+
77+
// Stroke color
78+
borderColor: 'red',
79+
80+
// Stroke width
81+
borderWidth: 2,
82+
83+
// Fill color
84+
backgroundColor: 'green'
85+
}
86+
```
87+
2588
## To-do Items
2689
The following features still need to be done:
27-
90+
* Point Annotations
91+
* Text annotations
2892

2993
## Installation
3094

samples/box.html

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<title>Scatter Chart</title>
6+
<script src="../node_modules/chart.js/dist/Chart.bundle.js"></script>
7+
<script src="../Chart.Annotation.js"></script>
8+
<style>
9+
canvas {
10+
-moz-user-select: none;
11+
-webkit-user-select: none;
12+
-ms-user-select: none;
13+
}
14+
</style>
15+
</head>
16+
17+
<body>
18+
<div style="width:75%">
19+
<div>
20+
<canvas id="canvas"></canvas>
21+
</div>
22+
</div>
23+
<script>
24+
var randomScalingFactor = function() {
25+
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
26+
};
27+
var randomColor = function(opacity) {
28+
return 'rgba(' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + (opacity || '.3') + ')';
29+
};
30+
31+
var scatterChartData = {
32+
datasets: [{
33+
label: "My First dataset",
34+
data: [{
35+
x: randomScalingFactor(),
36+
y: randomScalingFactor(),
37+
}, {
38+
x: randomScalingFactor(),
39+
y: randomScalingFactor(),
40+
}, {
41+
x: randomScalingFactor(),
42+
y: randomScalingFactor(),
43+
}, {
44+
x: randomScalingFactor(),
45+
y: randomScalingFactor(),
46+
}, {
47+
x: randomScalingFactor(),
48+
y: randomScalingFactor(),
49+
}, {
50+
x: randomScalingFactor(),
51+
y: randomScalingFactor(),
52+
}, {
53+
x: randomScalingFactor(),
54+
y: randomScalingFactor(),
55+
}]
56+
}, {
57+
label: "My Second dataset",
58+
data: [{
59+
x: randomScalingFactor(),
60+
y: randomScalingFactor(),
61+
}, {
62+
x: randomScalingFactor(),
63+
y: randomScalingFactor(),
64+
}, {
65+
x: randomScalingFactor(),
66+
y: randomScalingFactor(),
67+
}, {
68+
x: randomScalingFactor(),
69+
y: randomScalingFactor(),
70+
}, {
71+
x: randomScalingFactor(),
72+
y: randomScalingFactor(),
73+
}, {
74+
x: randomScalingFactor(),
75+
y: randomScalingFactor(),
76+
}, {
77+
x: randomScalingFactor(),
78+
y: randomScalingFactor(),
79+
}]
80+
}]
81+
};
82+
83+
scatterChartData.datasets.forEach(function(dataset) {
84+
dataset.borderColor = randomColor(0.4);
85+
dataset.backgroundColor = randomColor(0.1);
86+
dataset.pointBorderColor = randomColor(0.7);
87+
dataset.pointBackgroundColor = randomColor(0.5);
88+
dataset.pointBorderWidth = 1;
89+
});
90+
91+
window.onload = function() {
92+
var ctx = document.getElementById("canvas").getContext("2d");
93+
window.myScatter = Chart.Scatter(ctx, {
94+
data: scatterChartData,
95+
options: {
96+
title: {
97+
display: true,
98+
text: 'Chart.js Scatter Chart'
99+
},
100+
scales: {
101+
xAxes: [{
102+
position: 'top',
103+
gridLines: {
104+
zeroLineColor: "rgba(0,255,0,1)"
105+
},
106+
scaleLabel: {
107+
display: true,
108+
labelString: 'x axis'
109+
},
110+
ticks: {
111+
maxRotation: 0,
112+
reverse: true
113+
}
114+
}],
115+
yAxes: [{
116+
position: 'right',
117+
gridLines: {
118+
zeroLineColor: "rgba(0,255,0,1)"
119+
},
120+
scaleLabel: {
121+
display: true,
122+
labelString: 'y axis'
123+
},
124+
ticks: {
125+
reverse: true
126+
}
127+
}]
128+
},
129+
annotation: {
130+
annotations: [{
131+
type: 'box',
132+
xScaleID: 'x-axis-1',
133+
yScaleID: 'y-axis-1',
134+
xMin: -20,
135+
xMax: 20,
136+
yMin: -20,
137+
yMax: 20,
138+
backgroundColor: 'rgba(101, 33, 171, 0.5)',
139+
borderColor: 'rgb(101, 33, 171)',
140+
borderWidth: 1
141+
}]
142+
}
143+
}
144+
});
145+
};
146+
</script>
147+
</body>
148+
149+
</html>

src/box.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Box Annotation implementation
2+
module.exports = function(Chart) {
3+
var BoxAnnotation = Chart.Element.extend({
4+
draw: function(ctx) {
5+
var view = this._view;
6+
7+
// Canvas setup
8+
ctx.lineWidth = view.borderWidth;
9+
ctx.strokeStyle = view.borderColor;
10+
ctx.fillStyle = view.backgroundColor;
11+
12+
// Draw
13+
var width = view.right - view.left,
14+
height = view.bottom - view.top;
15+
ctx.fillRect(view.left, view.top, width, height);
16+
ctx.strokeRect(view.left, view.top, width, height)
17+
}
18+
});
19+
20+
function isValid(num) {
21+
return !isNaN(num) && isFinite(num);
22+
}
23+
24+
// Function that updates a box annotation
25+
function boxUpdate(obj, options, chartInstance) {
26+
var model = obj._model = obj._model || {};
27+
28+
var xScale = chartInstance.scales[options.xScaleID];
29+
var yScale = chartInstance.scales[options.yScaleID];
30+
var chartArea = chartInstance.chartArea;
31+
32+
var left = chartArea.left,
33+
top = chartArea.top,
34+
right = chartArea.right,
35+
bottom = chartArea.bottom;
36+
37+
var min,max;
38+
39+
if (xScale) {
40+
min = isValid(options.xMin) ? xScale.getPixelForValue(options.xMin) : chartArea.left;
41+
max = isValid(options.xMax) ? xScale.getPixelForValue(options.xMax) : chartArea.right;
42+
left = Math.min(min, max);
43+
right = Math.max(min, max);
44+
}
45+
46+
if (yScale) {
47+
min = isValid(options.yMin) ? yScale.getPixelForValue(options.yMin) : chartArea.bottom;
48+
max = isValid(options.yMax) ? yScale.getPixelForValue(options.yMax) : chartArea.top;
49+
top = Math.min(min, max);
50+
bottom = Math.max(min, max);
51+
}
52+
53+
// Ensure model has rect coordinates
54+
model.left = left;
55+
model.top = top;
56+
model.right = right;
57+
model.bottom = bottom;
58+
59+
// Stylistic options
60+
model.borderColor = options.borderColor;
61+
model.borderWidth = options.borderWidth;
62+
model.backgroundColor = options.backgroundColor;
63+
}
64+
65+
66+
return {
67+
Constructor: BoxAnnotation,
68+
update: boxUpdate
69+
};
70+
}

src/chart.annotation.js

Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ Chart = typeof(Chart) === 'function' ? Chart : window.Chart;
44
var helpers = Chart.helpers;
55
var isArray = helpers.isArray;
66

7-
var horizontalKeyword = 'horizontal';
8-
var verticalKeyword= 'vertica';
9-
107
// Take the zoom namespace of Chart
118
Chart.Annotation = Chart.Annotation || {};
129

@@ -15,54 +12,19 @@ var defaultOptions = Chart.Annotation.defaults = {
1512
annotations: [] // default to no annotations
1613
};
1714

18-
var LineAnnotation = Chart.Element.extend({
19-
20-
draw: function(ctx) {
21-
var view = this._view;
22-
23-
// Canvas setup
24-
ctx.lineWidth = view.borderWidth;
25-
ctx.strokeStyle = view.borderColor;
26-
27-
// Draw
28-
ctx.beginPath();
29-
ctx.moveTo(view.x1, view.y1);
30-
ctx.lineTo(view.x2, view.y2);
31-
ctx.stroke();
32-
}
33-
});
34-
35-
function lineUpdate(obj, options, chartInstance) {
36-
var model = obj._model = obj._model || {};
37-
38-
var scale = chartInstance.scales[options.scaleID];
39-
var pixel = scale ? scale.getPixelForValue(options.value) : NaN;
40-
var chartArea = chartInstance.chartArea;
41-
42-
if (!isNaN(pixel)) {
43-
if (options.mode == horizontalKeyword) {
44-
model.x1 = chartArea.left;
45-
model.x2 = chartArea.right;
46-
model.y1 = model.y2 = pixel;
47-
} else {
48-
model.y1 = chartArea.top;
49-
model.y2 = chartArea.bottom;
50-
model.x1 = model.x2 = pixel;
51-
}
52-
}
53-
54-
model.borderColor = options.borderColor;
55-
model.borderWidth = options.borderWidth;
56-
}
15+
var lineAnnotation = require('./line.js')(Chart);
16+
var boxAnnotation = require('./box.js')(Chart);
5717

5818
// Map of all types
5919
var annotationTypes = Chart.Annotation.annotationTypes = {
60-
line: LineAnnotation
20+
line: lineAnnotation.Constructor,
21+
box: boxAnnotation.Constructor
6122
};
6223

6324
// Map of all update functions
6425
var updateFunctions = Chart.Annotation.updateFunctions = {
65-
line: lineUpdate,
26+
line: lineAnnotation.update,
27+
box: boxAnnotation.update
6628
};
6729

6830
// Chartjs Zoom Plugin
@@ -115,4 +77,5 @@ var AnnotationPlugin = Chart.PluginBase.extend({
11577
}
11678
});
11779

80+
module.exports = AnnotationPlugin;
11881
Chart.pluginService.register(new AnnotationPlugin());

0 commit comments

Comments
 (0)