✨pie chart
Last updated
Last updated
browser ⟩ SVG ⟩ examples ⟩ pie chart
replit: pie chart, SVGElemnt()
⬆️ 需要: SVGElement()
// ⭐ SVGElement
function SVGElement(tagName, attributes, config) {
// create SVG element (<svg>, <path>, <rect>, <text> ...)
let elem = document.createElementNS("http://www.w3.org/2000/svg", tagName);
// set attributes (non-string value is converted automatically into string)
Object.entries(attributes).forEach(([key, value]) => elem.setAttribute(key, value));
// furthur configuration if necessary
if (config) config(elem);
// return the element
return elem;
}
/**
* Create an <svg> element and draw a pie chart into it.
*
* first (only) parameter: an object with the following properties:
* - width, height: size of SVG (in pixels)
* - cx, cy, r : center and radius of the pie
* - lx, ly : upper-left corner of the chart legend
* - data : dictionary object with `label: value` pairs
*
* The function returns an <svg> element. The caller must insert it into
* the document in order to make it visible.
*/
function pieChart(options) {
let { width, height, cx, cy, r, lx, ly, data } = options;
// -----------
// SVG
// -----------
// ⭐ create chart with <svg> element
let chart = SVGElement('svg', {
width: width, height: height,
viewBox: `0 0 ${width} ${height}`,
// text styles for the chart (can be set with CSS instead)
'font-family': "sans-serif",
'font-size': 18,
});
// Get labels and values as arrays
let labels = Object.keys(data);
let values = Object.values(data);
// sum of the values
let total = values.reduce((x, y) => x + y);
// angles for all slices
// slice i: angles[i] ~ angles[i+1] (in radians)
let angles = [0];
values.forEach((x, i) => angles.push(angles[i] + x / total * 2 * Math.PI));
// loop through the slices of the pie
values.forEach((value, i) => {
// two points for slice arc
// angle of 0 is at 12 o'clock (increase clockwise)
let x1 = cx + r * Math.sin(angles[i]);
let y1 = cy - r * Math.cos(angles[i]);
let x2 = cx + r * Math.sin(angles[i + 1]);
let y2 = cy - r * Math.cos(angles[i + 1]);
// flag for angles larger than a half circle
// required by the SVG arc drawing component
let big = (angles[i + 1] - angles[i] > Math.PI) ? 1 : 0;
// commands to draw a slice:
let path = `M${cx},${cy}` + // Move to circle center.
`L${x1},${y1}` + // Line to (x1,y1).
`A${r},${r} 0 ${big} 1 ${x2},${y2}` + // Arc of radius r to (x2,y2).
"Z"; // cloZe path back to (cx,cy).
// CSS color for this slice. This formula works for only
// about 15 colors. So don't include more than 15 slices in a chart.
let color = `hsl(${(i * 40) % 360},${90 - 3 * i}%,${50 + 2 * i}%)`;
// --------------
// <path>
// --------------
// ⭐ create a slice with <path> element
let slice = SVGElement('path', {
d: path, fill: color, stroke: 'black', 'stroke-width': 1,
});
chart.append(slice); // ⭐ add slice to chart
// --------------
// <rect>
// --------------
// ⭐ legend icon square for each slice
let icon = SVGElement('rect', {
x: lx, y: ly + 30 * i, // position
width: 20, height: 20, // size
fill: color, stroke: 'black', 'stroke-width': 1,
});
chart.append(icon); // ⭐ add to chart
// --------------
// <text>
// --------------
// ⭐ legend label
let label = SVGElement('text', {
x: lx + 30, y: ly + 30 * i + 16, // position
});
label.append(`${labels[i]} (${value})`); // ⭐ add text to label
chart.append(label); // ⭐ add label to chart
});
return chart;
}
// main
document.querySelector("#chart").append(pieChart({
// chart size
width: 640, height: 400,
// center/radius of pie
cx: 200, cy: 200, r: 180,
// legend position
lx: 400, ly: 10,
// chart data
data: {
"JavaScript": 71.5,
"Java" : 45.4,
"Bash/Shell": 40.4,
"Python" : 37.9,
"C#" : 35.3,
"PHP": 31.4,
"C++": 24.6,
"C" : 22.1,
"TypeScript" : 18.3,
"Ruby" : 10.3,
"Swift" : 8.3,
"Objective-C": 7.3,
"Go": 7.2,
}
}));
Document ⟩ .createElementNS() - to create SVG elements.