臺南市勞動人口-依年齡別區分
// html
<div class="stackedBarChart"></div>
// js
const drawBarChart = async () => {
// 建立SVG
const width = parseInt(d3.select('.stackedBarChart').style('width')),
height = 500,
margin = 20,
marginBottom = 100
const svg = d3.select('.stackedBarChart')
.append('svg')
.attr('width', width)
.attr('height', height);
const data = await d3.csv('./data/tainan_labor_force_population.csv')
// 設定要給 X 軸用的 scale 跟 axis
const xData = data.map((i) => i['年度']);
const xScale = d3.scaleBand()
.domain(xData)
.range([margin*2, width - margin])
.padding(0.6)
const xAxis = d3.axisBottom(xScale)
// 呼叫繪製x軸、調整x軸位置
const xAxisGroup = svg
.append("g")
.call(xAxis)
.attr("transform", `translate(0,${height - marginBottom})`)
// 設定要給 Y 軸用的 scale 跟 axis
const yScale = d3.scaleLinear()
.domain([0, 1200])
.range([height - marginBottom, margin])
.nice()
const yAxis = d3.axisLeft(yScale)
.ticks(5)
.tickSize(3)
// 呼叫繪製y軸、調整y軸位置
const yAxisGroup = svg.append("g")
.call(yAxis)
.attr("transform", `translate(${margin*2},0)`)
// 設定分組,用 d3.stack() 把資料堆疊起來
const subgroups = Object.keys(data[0]).slice(1)
const stackedData = d3.stack()
.keys(subgroups)(data);
// 設定不同 subgorup bar的顏色
const color = d3.scaleOrdinal()
.domain(subgroups)
.range(['#97a9bf','#d6dbbb','#d4e6e8', '#dcd2d0'])
// 開始建立長條圖
const bar = svg.append('g')
.selectAll('g')
.data(stackedData)
.join('g')
.attr('fill', d => color(d.key))
.selectAll('rect')
.data(d=>d)
.join('rect')
.attr("x", d => xScale(d.data['年度']))
.attr("y", d => yScale(d[1]))
.attr("height", d => yScale(d[0]) - yScale(d[1]))
.attr("width",xScale.bandwidth())
.style('cursor', 'pointer')
.on("mouseover", handleMouseOver)
.on("mouseleave", handleMouseLeave)
// 設定文字標籤
const textTag = svg.append('text')
.attr('class', 'infoText')
.style('fill', '#000')
.style('font-size', '18px')
.style('font-weight', 'bold')
.style("text-anchor", 'middle')
.style('opacity', '0')
function handleMouseOver(d, i){
const pt = d3.pointer(event, svg.node());
d3.select(this).style('opacity', '0.5');
// 加上文字標籤
textTag
.style('opacity', '1')
.attr("x", pt[0])
.attr('y', pt[1]-20)
.text((d.target.__data__[1] - d.target.__data__[0]) + '千人');
}
function handleMouseLeave(){
d3.select(this).style('opacity', '1');
textTag.style('opacity', '0');
}
// 加上tag標籤
const tagsWrap = svg.append('g')
.selectAll('g')
.attr('class', 'tags')
.data(subgroups)
.join('g')
tagsWrap.append('rect')
.attr('x', (d,i)=> {
const unit = (width-margin*2)/5;
return (i+1)*unit;
})
.attr('y', height-marginBottom/2)
.attr('width', 20)
.attr('height', 20)
.attr('fill', d => color(d))
tagsWrap.append('text')
.attr('x', (d,i)=> {
const unit = (width-margin)/5;
return (i+1)*unit;
})
.attr('y', height-10)
.style('fill', '#000')
.style('font-size', '12px')
.style('font-weight', 'bold')
.style("text-anchor", 'middle')
.text(d=>d)
};
drawBarChart();