Repository navigation
Expand file tree
/
Copy pathpie-chart.html
More file actions
88 lines (77 loc) · 2.82 KB
/
Copy pathpie-chart.html
File metadata and controls
88 lines (77 loc) · 2.82 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
<!doctype html>
<meta charset="utf-8" />
<title>Pie chart</title>
<style>
.pie {
width: 250px;
height: 250px;
}
.pie .label {
text-align: center;
max-width: 40%;
font-family: sans-serif;
}
.pie .label .val {
display: block;
font-size: xx-large;
font-weight: bold;
}
</style>
<!-- Note: content=drawable is the new API and layoutsubtree has been left -->
<!-- only for temporary backwards compatibility. -->
<canvas content="drawable" layoutsubtree class="pie" role="list" aria-label="Pie Chart">
<div drawable class="label" role="listitem" tabindex="0" data-val="0.45" data-color="tomato">
<span class="val">45%</span>Apple
</div>
<div drawable class="label" role="listitem" tabindex="0" data-val="0.35" data-color="cornflowerblue">
<span class="val">35%</span>Blackberry / Bramble
</div>
<div drawable class="label" role="listitem" tabindex="0" data-val="0.20" data-color="gold">
<span class="val">20%</span>Durian
</div>
</canvas>
<script>
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.onpaint = () => {
ctx.reset();
// 1. Center the coordinate system.
const radius = 0.95 * Math.min(canvas.width, canvas.height) / 2;
ctx.translate(canvas.width / 2, canvas.height / 2);
let angle = 0;
let focusedPath = null;
for (const label of canvas.children) {
const slice = Number(label.dataset.val) * Math.PI * 2;
// 2. Draw the wedge.
const grad = ctx.createRadialGradient(0, 0, 0, 0, 0, radius);
grad.addColorStop(0, `color-mix(${label.dataset.color}, white 40%)`);
grad.addColorStop(1, label.dataset.color);
ctx.fillStyle = grad;
const path = new Path2D();
path.moveTo(0, 0);
path.arc(0, 0, radius, angle, angle + slice);
path.closePath();
ctx.fill(path);
if (document.activeElement === label)
focusedPath = path;
// 3. Draw the label element, and update its transform.
const mid = angle + slice / 2;
const label_width = label.offsetWidth * devicePixelRatio;
const label_height = label.offsetHeight * devicePixelRatio;
const x = Math.cos(mid) * radius * 0.60 - label_width / 2;
const y = Math.sin(mid) * radius * 0.60 - label_height / 2;
ctx.drawElementImage(label, x, y);
angle += slice;
}
// 4. Draw the focus ring on top of everything else.
if (focusedPath)
ctx.drawFocusIfNeeded(focusedPath, document.activeElement);
};
canvas.requestPaint(); // Request an initial paint event.
// Setup a resize observer to resize the canvas in response to dpr changes.
new ResizeObserver(([entry]) => {
const box = entry.devicePixelContentBoxSize[0];
canvas.width = box.inlineSize;
canvas.height = box.blockSize;
}).observe(canvas, {box: ['device-pixel-content-box']});
</script>