import * as d3 from 'd3';
/*
d3.select(selector: string)
μΈμλ‘ CSS μ νμ λ¬Έμμ΄μ μ λ¬, DOM μμλ₯Ό μ ννκ³ μ νν μμμ λν D3.js κΈ°λ₯μ μ μ©νλλ° μ¬μ©
*/
const element = d3.select('css selector');
/*
d3.selectAll(selector: string)
λ§€μΉλ λͺ¨λ μμλ₯Ό κ°λ Selection κ°μ²΄ λ°ν
*/
const elements = d3.selectAll('css selector');/*
Selection κ°μ²΄μ ꡬ쑰λ μλμ κ°μ΅λλ€.
Selection κ°μ²΄λ₯Ό μ¬μ©νμ¬ μ νν μμμ μ€νμΌ, μμ±, λ°μ΄ν° λ°μΈλ©, μ΄λ²€νΈ νΈλ€λ§ λ±μ μ‘°μν μ μμ΅λλ€. λν Selection κ°μ²΄λ₯Ό μ΄μ©νμ¬ μ λλ©μ΄μ
κ³Ό μ ν ν¨κ³Όλ₯Ό μ μ©νμ¬ λμ μΈ ν¨κ³Όλ₯Ό ꡬνν μλ μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ λ°μ΄ν° μκ°ν λ° DOM μ‘°μμ ν¨κ³Όμ μΌλ‘ μνν μ μμ΅λλ€.
Selection {
_groups: [Array of DOM elements], // μ νν μμμ κ·Έλ£Ή (μ¬λ¬ μμλ₯Ό ν¬ν¨ν μ μμ)
_parents: [Array of parent nodes], // μ νν μμμ λΆλͺ¨ λ
Έλ κ·Έλ£Ή (λ§μ°¬κ°μ§λ‘ μ¬λ¬ λΆλͺ¨ λ
Έλλ₯Ό ν¬ν¨ν μ μμ)
}
- _groups: μ νν DOM μμμ κ·Έλ£Ήμ
λλ€. μ΄λ λ°°μ΄ ννλ‘ μ¬λ¬ DOM μμλ₯Ό ν¬ν¨ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, d3.selectλ₯Ό μ¬μ©νμ¬ νλμ μμλ₯Ό μ νν κ²½μ°μλ _groups λ°°μ΄μ ν΄λΉ μμκ° ν¬ν¨λ©λλ€.
μ¬λ¬ κ°μ μμλ₯Ό μ νν κ²½μ°, κ° μμλ λ°°μ΄ λ΄μ κ°κ°μ μμλ‘ ννλ©λλ€.
- _parents: μ νν DOM μμμ λΆλͺ¨ λ
Έλ κ·Έλ£Ήμ
λλ€.
μ΄ μμ λ°°μ΄ ννλ‘ μ¬λ¬ λΆλͺ¨ λ
Έλλ₯Ό ν¬ν¨ν μ μμ΅λλ€.
_groupsμ μ μ¬νκ², κ° λΆλͺ¨ λ
Έλλ λ°°μ΄ λ΄μ κ°κ°μ μμλ‘ ννλ©λλ€.
*/import * as d3 from 'd3';
/*
Selection.append(type: string)
μ νν μμ λ΄μ μλ‘μ΄ μμ μμλ₯Ό μΆκ°νλλ° μ¬μ©. μΆκ°λ μμλ μ νν μμ λ΄μμ ν΄λΉ μμλ€μ κ°μ₯ λ§μ§λ§μ μμΉ
λ°νκ°μ μλ‘κ² μΆκ°λ μμλ₯Ό κ°λ Selection κ°μ²΄
*/
d3.select('css selector').append('tag name');
/*
Selection.remove()
μ νλ μμλ₯Ό DOMμμ μ κ±°νλλ° μ¬μ©
*/
d3.select('css selector').remove();
/*
Selection.attr(key: string, value?: string)
νλ μμμ μμ±(HTML Attribute)μ μ€μ νκ±°λ κ°μ Έμ¬ λ μ¬μ©
λ°νκ°μ μμ λ μμλ₯Ό κ°λ Selection κ°μ²΄
*/
d3.select('css selector').attr('key', 'value');
d3.select('css selector').attr('key'); // 'value'
/*
Selection.style(key: string, value?: any, priority?: 'important')
μ νλ μμμ CSS μ€νμΌμ μ€μ νκ±°λ κ°μ Έμ¬ λ μ¬μ©
*/
d3.select('css selector').style('key', 'value');
d3.select('css selector').style('key'); // 'value'import * as d3 from 'd3';
/*
selection.call(function: (element: Selection) => void)
μ νν μμμ μΈμλ‘ μ λ¬ν ν¨μλ₯Ό μ μ©. μ΄ ν¨μλ μ νν μμλ₯Ό λμμΌλ‘ μμ
μ μννκ±°λ μ€μ μ λ³κ²½
첫 λ²μ§Έ μΈμλ‘ μ νλ μμ μ λ¬
*/
d3.select('css selector').call((element: Selection) => {
// element μ‘°μ,,,
});import * as d3 from 'd3';
// μ£Όλ‘ λ§λ μ°¨νΈ, κ·Έλ£Ήνλ λ§λ μ°¨νΈ, μΆκ³Ό κ°μ μκ°ν μμμμ x λλ y μΆμ μμΉλ₯Ό μ€μ νλλ° νμ©
const createXScale = (xAxisDataList: string[], svgWidth: number) => {
/*
d3.scaleBand(domain: string[], range: [number, number])
domainμλ μ
λ ₯κ°μ λ²μ£Όλ€μ μ€μ , rangeμλ ν΄λΉ λ²μ£Όλ€μ΄ νμλ μμΉ(μΆμ μμΉ)λ₯Ό μ€μ
d3.scaleBandμ λ°ν κ°μ ν¨μ. μ΄ ν¨μμ λ²μ£Όν λ°μ΄ν° κ°μ μ
λ ₯νλ©΄ ν΄λΉ κ°μ΄ μΆμ μμΉλ‘ λ³ν
*/
return d3.scaleBand().domain(xAxisData).range([0, svgWidth]);
};
const xScale = createXScale(['a', 'b', 'c'], 300);
console.log(xScale('a')); // 0
console.log(xScale('b')); // 150
console.log(xScale('c')); // 300import * as d3 from 'd3';
// μ£Όλ‘ μ κ·Έλν, μ°μ λ, μΆκ³Ό κ°μ μκ°ν μμμμ λ°μ΄ν°μ κ°μ ν½μ
μ’νλ ν¬κΈ°λ‘ λ³ννλλ° νμ©
const createYScale = (yAxisDataList: number[], svgHeight: number) => {
/*
d3.scaleLinear(domain: [number, number], range: [number, number])
domainμλ μ
λ ₯κ°μ λ²μλ₯Ό μ€μ , rangeμλ ν΄λΉ μ
λ ₯κ°λ€μ΄ νμλ μμΉ(μΆμ μμΉ)λ ν¬κΈ°μ λ²μλ₯Ό μ€μ
λ°ν κ°μ ν¨μ. μ΄ ν¨μμ μ
λ ₯κ°μ μ λ¬νλ©΄ ν΄λΉ κ°μ΄ μΆλ ₯ λ²μ λ΄μ μμΉλ‘ λ³ν
*/
return d3
.scaleLinear()
.domain([0, d3.max(yAxisDataList)])
.range([0, svgHeight]);
};
const yScale = createYScale([10, 130], 960);
console.log(yScale(10)); // 80
console.log(yScale(10)); // 320import * as d3 from 'd3';
const createXAxis = (
svgEl: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>,
xSacle: d3.ScaleBand<string>
) => {
/*
d3.axisBottom(sacle: AxisScale)
xμΆμ μ€μΌμΌκ³Ό μ°κ²°νμ¬ x μΆμ μμ±. μ΄ μ€μΌμΌμ μ
λ ₯ λλ©μΈμ κ°μ μΆλ ₯ λ²μμ λ§€ννλ μν μ μν
μΈμλ‘ scale ν¨μ μ λ¬
*/
svgEl.append('g').call(d3.axisBottom(xScale));
};
const createYAxis = (
svgEl: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>,
yScale: d3.ScaleLinear<number, number, never>
) => {
svgEl.append('g').call(d3.axisTop(yScale));
};import * as d3 from 'd3';
const createBar = (
svgEl: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>,
xSacle: d3.ScaleBand<string>,
yScale: d3.ScaleLinear<number, number, never>,
chartDataList: { xAxisData: string, yAxisData: number }[]
) => {
/*
Selection.data(any[])
λ°μ΄ν°λ₯Ό μ νν μμμ λ°μ΄ν° λ°μΈλ©νλλ° μ¬μ©. μ΄λ₯Ό ν΅ν΄ λ°μ΄ν°μ μμκ° μ°κ²°λμ΄ λ°μ΄ν°μ λ³νμ λ°λΌ μμμ μνλ₯Ό μ
λ°μ΄νΈ
λ°μ΄ν°λ₯Ό λ°μΈλ©νλ©΄ μλ‘μ΄ λ°μ΄ν°μ κ°―μμ λ°λΌ enter, update, exitμ κ°λ
μ μ¬μ©νμ¬ μμλ₯Ό κ΄λ¦¬ κ°λ₯
λ°μΈλ©λ λ°μ΄ν°λ μ νν μμ λ΄μμ μ½λ°± ν¨μ λ±μμ μ¬μ©
λ°μ΄ν° λ°μΈλ© ν μ΄ν λ©μλ 체μ΄λ λ λ²μ§Έ μΈμλ‘ μ½λ°±ν¨μ μ λ¬νμ¬ λ°μΈλ©ν λ°μ΄ν° μ κ·Ό κ°λ₯
ex) Selection.data(dataList).attr('key', (data: any) => { ,,, })
μ μμ μ²λΌ data λ©μλλ‘ λ°μ΄ν° λ°μΈλ© ν attr λ©μλ 체μ΄λ λ λ²μ§Έ μΈμλ‘ μ½λ°±ν¨μ μ λ¬νμ¬ λ°μΈλ©λ λ°μ΄ν°μ μ κ·Ό κ°λ₯
μ½λ°±ν¨μλ μλμ κ°μ μΈμλ₯Ό μ λ¬λ°μ
1. data: λ°μ΄ν° λ°μΈλ©λ μμμ λμνλ λ°μ΄ν° νλͺ©
2. index: λ°μ΄ν° λ°°μ΄ λ΄μμμ λ°μ΄ν° νλͺ©μ μΈλ±μ€
3. groupIndex: selectAll() λ©μλλ₯Ό μ¬μ©νμ¬ μ¬λ¬ κ·Έλ£Ήμ μ νν κ²½μ°μ ν΄λΉ κ·Έλ£Ήμ μΈλ±μ€λ₯Ό μ λ¬
4. nodes: μΌλΆ λ©μλλ μ΄λ²€νΈμμλ μ νλ μμμ λν μ 보
5. event: μ΄λ²€νΈμ κ΄λ ¨λ μ 보
*/
/*
Selection.enter()
μλ‘μ΄ λ°μ΄ν°μ λμνλ Selection(μμ)λ₯Ό μΆκ°νλ μν
λ°μΈλ©ν λ°μ΄ν°μ κ°μκ° Selection κ°μ²΄λ³΄λ€ λ§μ κ²½μ°, μλ‘μ΄ Selection κ°μ κ°μ²΄ μμ±νμ¬ λ°μ΄ν° λ°μΈλ©νκ³ κ°μ κ°μ²΄ λ°ν
μ΄ν append λ©μλλ₯Ό ν΅ν΄ κ°μ Selection κ°μ²΄λ₯Ό μ€μ Selection κ°μ²΄λ‘ μΆκ°
μ¦, selectAll -> data -> enter -> append μμλ‘ μ¬μ©
*/
svgEl
.append('g')
.selectAll('rect')
.data(chartDataList)
.enter()
.append('rect')
.attr('x', (chartData) => xScale(chartData.xAxisData))
.attr('y', (chartData) => yScale(chartData.yAxisData))
.attr('width', 50)
.attr('height', yScale(0) - yScale(d.yAxisData));
};import * as d3 from 'd3';
const handleMouseMove = (event: MouseEvent) => {
/*
d3.bisect(array: ArrayLike<number>, x: number, lo?: number, hi?: number): number
첫 λ²μ§Έ μΈμλ‘ λ°°μ΄, λ λ²μ§Έ μΈμλ‘ μ²« λ²μ§Έ λ°°μ΄μ μ½μ
ν κ°, μΈ λ²μ§Έ μΈμλ κ²μ μμ, λ€ λ²μ§Έ μΈμλ κ²μ λ§μ§λ§ μΈλ±μ€ μ λ¬
μ λ ¬λ λ°°μ΄μμ νΉμ κ°μ΄ μ½μ
λ μμΉλ κ°μ μ°Ύλλ° μ¬μ©λλ ν¨μ
*/
const currentDataIndex =
d3.bisect(
xAxisData.map((data) => xScale(data)),
event.offsetX
) - 1;
};import * as d3 from 'd3';
const createLinePath = (
svgEl: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>,
xSacle: d3.ScaleBand<string>,
yScale: d3.ScaleLinear<number, number, never>,
chartDataList: { xAxisData: string, yAxisData: number }[]
) => {
// [xμ’ν, yμ’ν]λ₯Ό μμλ‘ κ°λ λ°°μ΄
const lineGeneratorParams = chartDataList.map((chartData) => [
xScale(chartData.xAxisData),
yScale(chartData.yAxisData)
]);
/*
d3.line()
.x(function: (data: [xPosition: number, yPosition: number]) => data[0])
.y(function: (data: [xPosition: number, yPosition: number]) => data[1])
(dataList: [xPosition: number, yPostion: number][])
μ κ·Έλν(line chart)λ₯Ό μμ±νκΈ° μν΄ μ¬μ©λλ ν¨μ. μ κ·Έλνλ λ°μ΄ν° ν¬μΈνΈλ₯Ό μ μΌλ‘ μ°κ²°νμ¬ λ°μ΄ν°μ μΆμ΄λ ν¨ν΄μ μκ°ννλλ° μ¬μ©
lineμ μμ±νκΈ° μν path μμμ d μ΄νΈλ¦¬λ·°νΈ κ°μΌλ‘ λ³νν΄μ£Όλ ν¨μλ₯Ό λ°ν
λ°νλ ν¨μ μΈμλ‘ x, y μ’ν κ°μ κ°λ λ°°μ΄ μ λ¬μ x, y λ©μλ μ½λ°±ν¨μ μΈμλ‘ λ°°μ΄ μμ μμ°¨ μ λ¬
*/
const lineGenerator = d3
.line()
// x μ’ν
.x((data) => data[0])
// y μ’ν
.y((data) => data[1]);
return svg
.append('g')
.append('path')
.data([positionValueList])
.attr('d', (positionValueList) => lineGenerator(positionValueList));
};import * as d3 from 'd3';
// νμ΄ μ°¨νΈλ₯Ό 그리기 μν΄ yAxis κ°μ λ°±λΆμ¨λ‘ λ³ν
const convertPercentDataList = (dataList: { xAxisData: string, yAxisData: number }[]) => {
const totalYAxisData = dataList.reduce(
(prevTotalValue: number, data: { xAxisData: string, yAxisData: number }) =>
data.yAxisData + prevTotalValue,
0
);
return dataList.map((data) => ({
xAxisData: data.xAxisData,
yAxisData: (data.yAxisData / totalAmount) * 100
}));
};
const getPieDatalist = (calculatedDataList: { xAxisData: string, yAxisData: number }[]) => {
/*
d3.pie().value(Function)(dataList: any[])
value λ©μλ μΈμλ‘ μ½λ°± μ λ¬νλ©΄μ νΈμΆμ ν¨μ λ°ν, λ°νλ ν¨μ μΈμλ‘ λ°°μ΄ μ λ¬
value λ©μλ μΈμλ‘ μ λ¬ν μ½λ°±μ λ°±λΆμ¨λ‘ λ³νλ κ° λ°ν
μ
λ ₯ λ°μ΄ν° λ°°μ΄μ νμ΄ μ°¨νΈμ λ°μ΄ν° ν¬μΈνΈ λ°°μ΄λ‘ λ³ν. κ° λ°μ΄ν° ν¬μΈνΈμλ λ°μ΄ν° νλͺ©μ κ°, κ°λ λ±μ μ λ³΄κ° ν¬ν¨
*/
/*
d3.pie().value(Function)(dataList: any[]) λ°νκ°μ νμ
μ μλμ κ°μ΅λλ€.
{
data: any;
index: number;
endAngle: nuimber;
startAngle: number;
padAngle: number;
value: number;
}[]
*/
return d3.pie().value((data) => data.yAxisData)(calculatedDataList);
};
const createPieChart = (
svg: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>,
pieDataList: d3.PieArcDatum<
| number
| {
valueOf(): number
}
>[]
) => {
const svgWidth = Number(svg.attr('width'));
const svgHeight = Number(svg.attr('height'));
const outerRadius = d3.min([svgWidth, svgHeight]) / 2;
/*
d3.arc()
.innerRadius(radius: number)
.outerRadius(radius: number)
.startAngle((data) => data.startAngle)
.endAngle((data) => data.endAngle)
(data)
νμ΄ μ°¨νΈ(pie chart)λ₯Ό 그리기 μν path μ΄νΈλ¦¬λ·°νΈμ d μ΄νΈλ¦¬λ·°νΈ κ°μΌλ‘ λ³ννλ ν¨μ λ°ν
innerRadius, outerRadius λ©μλ μΈμλ‘ κ°κ° λ΄λΆ, μΈλΆ μ λ°μ§λ¦ κ° μ λ¬
startAngle, endAngle λ©μλ μΈμλ‘ κ°κ° μμ, λ κ°λ κ° μ λ¬
λ°νλ ν¨μ νΈμΆμ d3.pie().value(Function)κ° λ°νν λ°°μ΄μ μμ μ λ¬
*/
const arcGenerator = d3
.arc()
.innerRadius(outerRadius * 0.65)
.outerRadius(outerRadius)
// d3.pie().value(Function)(data) λ°νκ° λ°μΈλ©μ startAngle, endAngle κ°μΌλ‘ κ°λ κ° μ κ·Ό κ°λ₯
.startAngle((data) => data.startAngle)
.endAngle((data) => data.endAngle);
svg
.append('g')
.attr('transform', `translate(${svgWidth / 2}, ${svgHeight / 2})`)
.selectAll('path')
// d3.pie().value(Function)(data) λ°νκ° μ λ¬
.data(pieDatalist)
.enter()
.append('path')
.attr('d', (data) => arcGenerator(data))
.attr('stroke', '#fff');
};