/
polygon.js
115 lines (106 loc) · 2.95 KB
/
polygon.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {Element} from 'chart.js';
import {PI, RAD_PER_DEG} from 'chart.js/helpers';
import {setBorderStyle, resolvePointPosition, getElementCenterPoint, setShadowStyle} from '../helpers';
export default class PolygonAnnotation extends Element {
inRange(mouseX, mouseY, useFinalPosition) {
return this.elements.length > 1 && pointIsInPolygon(this.elements, mouseX, mouseY, useFinalPosition);
}
getCenterPoint(useFinalPosition) {
return getElementCenterPoint(this, useFinalPosition);
}
draw(ctx) {
const {elements, options} = this;
ctx.save();
ctx.beginPath();
ctx.fillStyle = options.backgroundColor;
setShadowStyle(ctx, options);
const stroke = setBorderStyle(ctx, options);
let first = true;
for (const el of elements) {
if (first) {
ctx.moveTo(el.x, el.y);
first = false;
} else {
ctx.lineTo(el.x, el.y);
}
}
ctx.closePath();
ctx.fill();
// If no border, don't draw it
if (stroke) {
ctx.shadowColor = options.borderShadowColor;
ctx.stroke();
}
ctx.restore();
}
resolveElementProperties(chart, options) {
const {x, y, width, height} = resolvePointPosition(chart, options);
const {sides, radius, rotation, borderWidth} = options;
const halfBorder = borderWidth / 2;
const elements = [];
const angle = (2 * PI) / sides;
let rad = rotation * RAD_PER_DEG;
for (let i = 0; i < sides; i++, rad += angle) {
const sin = Math.sin(rad);
const cos = Math.cos(rad);
elements.push({
type: 'point',
optionScope: 'point',
properties: {
x: x + sin * radius,
y: y - cos * radius,
bX: x + sin * (radius + halfBorder),
bY: y - cos * (radius + halfBorder)
}
});
}
return {x, y, width, height, elements, initProperties: {x, y}};
}
}
PolygonAnnotation.id = 'polygonAnnotation';
PolygonAnnotation.defaults = {
adjustScaleRange: true,
backgroundShadowColor: 'transparent',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0,
borderJoinStyle: 'miter',
borderShadowColor: 'transparent',
borderWidth: 1,
display: true,
point: {
radius: 0
},
radius: 10,
rotation: 0,
shadowBlur: 0,
shadowOffsetX: 0,
shadowOffsetY: 0,
sides: 3,
xAdjust: 0,
xMax: undefined,
xMin: undefined,
xScaleID: 'x',
xValue: undefined,
yAdjust: 0,
yMax: undefined,
yMin: undefined,
yScaleID: 'y',
yValue: undefined
};
PolygonAnnotation.defaultRoutes = {
borderColor: 'color',
backgroundColor: 'color'
};
function pointIsInPolygon(points, x, y, useFinalPosition) {
let isInside = false;
let A = points[points.length - 1].getProps(['bX', 'bY'], useFinalPosition);
for (const point of points) {
const B = point.getProps(['bX', 'bY'], useFinalPosition);
if ((B.bY > y) !== (A.bY > y) && x < (A.bX - B.bX) * (y - B.bY) / (A.bY - B.bY) + B.bX) {
isInside = !isInside;
}
A = B;
}
return isInside;
}