fengchia_guest_source = [
{ 客源:'外來客(不含陸客)', 比例: 80*(1-0.3) },
{ 客源:'台中人', 比例: 20 },
{ 客源:'陸客', 比例: 80*0.3 },
]
chart = DonutChart(fengchia_guest_source, {
name: d => d.客源,
value: d => d.比例,
width,
height: 500
})
結果如下
我看到幾個問題
20 + 80*(1-0.3) + 80*0.3 = 20 + 56 + 24 = 100
DonutChart
function打開開發者工具,用小箭頭功能,找出 DOM 的位置
從 DonutChart
中,理解出這些文字怎麼被謄寫上來的
原本長這樣
svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${arcLabel.centroid(d)})`)
.selectAll("tspan")
.data(d => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d);
.attr("font-size", 20)
.text(d => d);
就是直接把傳進來的值,原封不動謄寫上去。
<tspan>
中的文字,都被加了 % 呢i
的值是吧(d, i) => i==0 ? d : d + " %"
i == 0
這樣的敘述,會回傳「真」或「假」d
: d + " %"
表示,如果上述條件為真,回傳冒號左邊的東西,如果上述條件為假,回傳冒號右邊的東西。DonutChart
的部分內容如下DonutChart
的完整內容如下// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/donut-chart
function DonutChart(data, {
name = ([x]) => x, // given d in data, returns the (ordinal) label
value = ([, y]) => y, // given d in data, returns the (quantitative) value
title, // given d in data, returns the title text
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
innerRadius = Math.min(width, height) / 3, // inner radius of pie, in pixels (non-zero for donut)
outerRadius = Math.min(width, height) / 2, // outer radius of pie, in pixels
labelRadius = (innerRadius + outerRadius) / 2, // center radius of labels
format = ",", // a format specifier for values (in the label)
names, // array of names (the domain of the color scale)
colors, // array of colors for names
stroke = innerRadius > 0 ? "none" : "white", // stroke separating widths
strokeWidth = 1, // width of stroke separating wedges
strokeLinejoin = "round", // line join of stroke separating wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0, // angular separation between wedges
} = {}) {
// Compute values.
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));
// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);
// Chose a default color scheme based on cardinality.
if (colors === undefined) colors = d3.schemeSpectral[names.size];
if (colors === undefined) colors = d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), names.size);
// Construct scales.
const color = d3.scaleOrdinal(names, colors);
// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
title = i => `${N[i]}\n${formatValue(V[i])}`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}
// Construct arcs.
const arcs = d3.pie().padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");
svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(N[d.data]))
.attr("d", arc)
.append("title")
.text(d => title(d.data));
svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${arcLabel.centroid(d)})`)
.selectAll("tspan")
.data(d => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text((d, i) => i == 0 ? d : d + " %");
return Object.assign(svg.node(), {scales: {color}});
}