-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpie.js
More file actions
117 lines (100 loc) · 3.88 KB
/
Copy pathpie.js
File metadata and controls
117 lines (100 loc) · 3.88 KB
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
116
117
const COUNTERCLOCKWISE = "counterclockwise";
const CLOCKWISE = "clockwise";
function zip(rows) {
return rows[0].map((_,c)=>rows.map(row=>row[c]))
}
export class PieTrace {
constructor(plot, trace) {
this.plot = plot;
this.trace = trace
}
getSize() {
let paperBBox = this.plot.paper.getBBox();
let min = Math.min(paperBBox.width, paperBBox.height);
return min / 2 - 20; // TODO margin
}
getCenter() {
let paperBBox = this.plot.paper.getBBox();
return {x:paperBBox.width/2, y: paperBBox.height / 2}
}
draw(traceIndex) {
let direction = this.trace.direction === undefined ? COUNTERCLOCKWISE : this.trace.direction
let clockwise = direction === CLOCKWISE
// TODO hole https://plotly.com/javascript/reference/#pie-hole
let rotation = this.trace.rotation === undefined ? 0 : this.trace.rotation
let sort = this.trace.sort === undefined || this.trace.sort;
let traceData = zip([this.trace.values, this.trace.labels])
if (sort) {
traceData.sort((a, b) => b[0] - a[0])
}
let pieMaskCircle = this.plot.paper.getElementById("piemask-circle")
if (pieMaskCircle) {
pieMaskCircle.r = this.getSize()
}
let sum = this.trace.values.reduce((a, b) => a + b);
let startingAngle = rotation;
if (!clockwise) {
let value = traceData[0][0];
let percent = value / sum;
startingAngle = 360 * percent;
}
for (let i = 0; i < traceData.length; i++) {
let value = traceData[i][0];
let percent = value / sum;
let angle = 360 * percent;
console.log(`drawPie ${percent} ${angle} ${startingAngle}`)
this._drawPie(percent, angle, startingAngle, clockwise, i)
startingAngle += clockwise ? angle : -angle
}
for (let pie of this.plot.pies) {
pie.style.display = "none";
}
}
getScaleFromDegree(deg) {
let rad = deg / 2 * Math.PI / 180;
return Math.tan(rad);
}
_drawPie(percent, angle, startingAngle, clockwise, pieIndex) {
let pie = this.plot.getPie(angle > 180)
let pieRect = pie.getElementById("pie-rect")
let t1 = pie.getElementById("g1").groupTransform;
let t2 = pie.getElementById("g2").groupTransform;
let rotateAngle = startingAngle + 180
rotateAngle += clockwise ? angle / 2 : - angle / 2
let size = this.getSize();
if (angle === 180) {
// t1.rotate.angle = startingAngle + angle / 2
t1.scale.x = 2
t2.translate.x = - size
t1.rotate.angle = rotateAngle
} else if (angle > 180) {
t1.translate.x = - size
t1.translate.y = - size
t1.scale.x = 2
t1.scale.y = 2
} else {
t2.rotate.angle = 45;
t1.scale.x = this.getScaleFromDegree(angle)
t1.rotate.angle = rotateAngle
// t1.translate.x = pie.getBBox().width / 2
// t1.translate.y = pie.getBBox().height / 2
}
pieRect.style.fill = this.plot.layout.colorway[pieIndex % this.plot.layout.colorway.length]
const eventEmitter = this.plot.eventEmitter;
pieRect.onclick = function (e) {
eventEmitter.emit('plotly_click', angle);
}
let center = this.getCenter()
let textAngle = rotateAngle + 90;
let x = size * 0.7 * Math.cos(textAngle * Math.PI / 180)
let y = size * 0.7 * Math.sin(textAngle * Math.PI / 180)
let text = this.plot.getText()
text.text = Math.round(percent * 100) + "%"
text.x = center.x + x + 5 // font size adjustment
text.y = center.y + y
text.style.fontSize = 10
text.layer = 4
text.textAnchor = "middle"
text.style.fill = "black"
}
}