D3로 실시간 차트를 만들다.그리고 리액션!
본문에서 저는 D3를 사용하여 이 간단한 차트를 만드는 방법을 보여 드리겠습니다.그리고 반응해.
D3.js는 전방 데이터의 시각화 렌더링을 위한 표준 라이브러리 중 하나입니다.기본적으로 복잡한 SVG를 구축하는 데 사용되는 선언식 시스템입니다.
당신의 차트에 활력을 불어넣기 위해서 간단한 애니메이션을 만드는 방법을 보여 드리겠습니다.그것들은 사용자의 실시간 정보를 더욱 가독성과 흥미를 가지게 할 것이다.
마지막으로, 우리는 응답이 민감한 차트를 확보할 것이다. 모든 크기의 입력 데이터에 적응하고, 작은 화면에서 읽을 수 있도록 해야 한다.
💡 You already want to check out the end result ? Look at it here !
준비 다 됐어요?그럼 시작합시다!!🤩
항목 및 라이브러리 설정
이 강좌를 계속 배우려면 몇 개의 명령으로 문장의 항목을 설정할 수도 있고, 항목에서 직접 수정할 수도 있습니다.
우리는 세 개의 라이브러리를 사용할 것이다: D3.물론 js와 Reactreact-use-measure도 있는데 이것은 React 구성 요소를 쉽게 측정할 수 있는 소형 라이브러리입니다.이는 유연하고 신속한 응답을 제공하는 SVG 구성 요소에 유용합니다.
자습서 항목 사용
본문을 계속 읽으려면 아래의 간단한 명령을 사용하여 본문의 React 항목을 다운로드하십시오.
# Cloning the starter project
git clone -b setup [email protected]:rhidra/d3js-leaderboard.git
cd d3js-leaderboard
# Install dependancies
npm i
너를 위한 프로젝트.
D3를 설치합니다.js.
npm i d3
작은 React 라이브러리를 설치하여 어셈블리를 측정합니다.우리가 차트에 응답을 시도할 때, 이것은 매우 유용할 것이다.
npm i react-use-measure
초기 설정 개요
하면, 만약, 만약...
<div className="app">
<div className="leaderboard-container">
<Leaderboard
data={data}
/>
</div>
<div className="button">
<button onClick={() => refreshData()}>Refresh Data</button>
</div>
</div>
우리는 두 개의 블록이 있는데, 하나는 미래의 차트이고, 다른 하나는 버튼이다.파일의 나머지 부분을 보면 업데이트App.jsx
변수에서 차트로 전달되는 데이터를 볼 수 있습니다.
기본적으로 우리는 차트에 약간의 데이터를 제공할 것이다.이 데이터들은 지금처럼 전단에서 올 수도 있지만, 후단에서 올 수도 있고, 비동기 함수를 사용할 수도 있다.
차트의 목표는 페이지를 새로 고칠 필요 없이 실시간으로 데이터를 업데이트하는 것이다.따라서 data
구성 요소에서 우리는 Leaderboard
입력의 변경 가능성을 고려해야 한다.
이제 data
파일을 봅시다.
import { useRef, useState, useEffect } from 'react';
import * as d3 from 'd3';
function Leaderboard({data}) {
const d3Ref = useRef(null);
useEffect(() => {
/***
Write D3.js code here !
***/
}, [d3Ref, data]);
return (
<svg
ref={d3Ref}
/>
);
}
export default Leaderboard;
Leaderboard.jsx
에서는 모든 D3을 작성합니다.js 코드.useEffect()
부품은 기본적으로 Leaderboard
부품으로 구성되어 있다.다음 부분에서 우리는 그것을 D3에 연결할 것이다.js.그런 다음 프레임을 사용하여 SVG 캔버스에 모양과 텍스트를 그립니다.
마지막으로 우리는 데이터를 신속하게 볼 수 있다.고유한 ID, 레이블 및 값으로 구성된 <svg>
파일에서 생성됩니다.
const data = [
...
{ "id":15, "value":33, "label":"Indonesia" },
{ "id":16, "value":14, "label":"China" },
{ "id":21, "value":7, "label":"Germany" },
{ "id":22, "value":12, "label":"China" },
{ "id":23, "value":38, "label":"Argentina" },
{ "id":24, "value":58, "label":"China" },
...
];
고정된 너비와 높이 설정
우선, 우리는 디자인이 유연하고 응답이 빠르기를 원하기 때문에 SVGdata.js
파라미터를 사용해서는 안 된다.따라서 SVG 어셈블리의 고정 너비와 높이를 지정해야 합니다.
우리는 차트 상단의 높이를 알고 있기 때문에, 우리는 전체 높이를 쉽게 계산해 낼 수 있다.만약 우리가 생각한다면, 우리도 약간의 간격과 충전을 넣을 수 있다.
수직 차트를 원하기 때문에, 모든 수평 공간을 차지해야 하고, CSS 너비는 viewBox
이어야 한다.불행하게도, 우리는 쓸 수 없습니다. 100%
픽셀 값을 사용해야 합니다.해결책은 모 어셈블리에서 서브어셈블리를 측정하는 것입니다.<svg width="100%"/>
에서 자식 객체의 폭을 측정합니다.그런 다음 너비를 매개변수로 전달할 수 있습니다.
이것은 새것App.jsx
이다.
function Leaderboard({data, width}) {
// ...
// Constant (in px)
const rowHeight = 60;
// Total height of the leaderboard
const [height, setHeight] = useState(rowHeight * data.length ?? 0);
useEffect(() => {
// Update total height, to use the most up-to-date value
setHeight(rowHeight * data.length);
const height = rowHeight * data.length;
// ...
}, [d3Ref, data, width]);
return (
<svg
width={width}
height={height}
ref={d3Ref}
/>
);
}
Leaderboard
의 경우 어셈블리의 크기를 쉽게 측정할 수 있는 단순한 단일 선 솔루션이 없습니다.따라서 우리는 React 라이브러리react-use-measure를 사용할 것이다.그것은 인기가 많고 사용하기 쉽다.
이것은 우리Leaderboard
를 이렇게 보게 한다.
import useMeasure from 'react-use-measure';
// ...
// Use React-use-measure to measure the Leaderboard component
const [ref, {width: leaderboardWidth}] = useMeasure({debounce: 100});
return (
// ...
<div className="leaderboard-container" ref={ref}>
<Leaderboard
data={data}
width={leaderboardWidth}
/>
</div>
// ...
);
마지막 중요한 일: CSS에 상수App
와 App
를 설정하는 것을 잊지 마세요. 그러면 차트 구성 요소가 기한 없이 넓어지지 않고 작은 장치에서 보기 좋아요!
SVG 그려달래요!
심심한 일을 다 끝냈으니 놀 때가 되었다🥳 !
useEffect(() => {
// ...
// Select the root SVG tag
const svg = d3.select(d3Ref.current);
// Scales
// Get the biggest value in the set,
// to draw all other relative to the maximum value.
const maxValue = d3.max(data.map(d => +d.value)) ?? 1;
const x = d3.scaleLinear().domain([0, maxValue]).range([5, width]);
const y = d3.scaleLinear().domain([0, data.length]).range([0, height]);
// Join the data
// We use the ID of a row to distinguish identical elements.
const g = svg.selectAll('g').data(data, d => d.id);
먼저 루트 SVG 구성 요소를 선택하고 데이터 행당 하나의 요소max-width
요소를 그립니다.SVG에서 width: 100%
요소는 다른 요소 그룹일 뿐입니다.
우리는 또한 데이터 집합의 최대 값을 사용하여 일부 축소 실용 함수<g>
와 <g>
를 정의했다.
마지막 줄에서 D3에게 알려주자.js는 한 줄의 ID를 사용하여 같은 줄을 찾습니다.데이터가 변경되거나 화면이 커질 때마다 코드가 실행되기 때문에 줄을 그렸을 수도 있습니다.값이 같을 수도 있지만, 순서가 다를 수도 있으니, 우리는 그것을 이동해야 한다.따라서 D3를 사용합니다.js, 우리는 우리가 한 줄을 만들고, 업데이트하고, 삭제할지 쉽게 결정할 수 있습니다.
간단하게 살펴보자면, 먼저 우리가 만들 때 줄을 정의한 다음에, 어떻게 모든 줄을 업데이트하는지 (새로 만든 줄은 이전에 수정한 줄도 포함하지만), 마지막으로 우리는 줄을 삭제하기 전에 작은 애니메이션을 정의할 것이다.
행 작성
초기화할 때, 우리는 SVG의 프레임워크를 간단하게 정의할 것입니다. 즉, 가능한 한 많은 정적 정보를 사용하여 탭을 만들 것입니다.x
함수는 만들어야 하는 줄을 격리하는 데 사용됩니다.
// Initialization
const gEnter = g.enter()
.append('g')
.attr('transform', `translate(0, ${y(data.length) + 500})`);
우선, 우리는 줄의 y
요소를 정의하고 그것을 전환한다.이 변환 명령은 그룹을 수직으로 g.enter()
으로 이동합니다.다시 말하면, 이 줄을 차트 밑부분 밖으로 옮겨 보이지 않게 할 것이다.새 줄을 추가할 때 작은 enter 애니메이션을 만들 수 있습니다.
// More constants !
const fontSize = '1.1rem';
const textColor = 'black';
const bgColor = '#d4d8df'; // Background bar color (grey)
const barColor = '#3d76c1'; // Main bar color (blue)
const barHeight = 10;
const marginText = 2; // Margin between the text and the bars
// Append background rect as child
gEnter
.append('rect')
.attr('class', 'bg')
.attr('fill', bgColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5)
.attr('height', barHeight);
// Append main rect as child
gEnter
.append('rect')
.attr('class', 'main')
.attr('fill', barColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5) // Rectangle border radius
.attr('height', barHeight);
// Append label text as child
gEnter
.append('text')
.attr('class', 'label')
.attr('font-size', fontSize)
.attr('fill', textColor)
.attr('x', 0)
.attr('y', -5)
.text(d => d.label);
// Append value text as child
gEnter
.append('text')
.attr('class', 'value')
.attr('text-anchor', 'end')
.attr('fill', textColor)
.attr('font-size', fontSize)
.attr('y', -5);
우리의 줄은 네 가지 요소로 구성되어 있다.
# Cloning the starter project
git clone -b setup [email protected]:rhidra/d3js-leaderboard.git
cd d3js-leaderboard
# Install dependancies
npm i
npm i d3
npm i react-use-measure
<div className="app">
<div className="leaderboard-container">
<Leaderboard
data={data}
/>
</div>
<div className="button">
<button onClick={() => refreshData()}>Refresh Data</button>
</div>
</div>
import { useRef, useState, useEffect } from 'react';
import * as d3 from 'd3';
function Leaderboard({data}) {
const d3Ref = useRef(null);
useEffect(() => {
/***
Write D3.js code here !
***/
}, [d3Ref, data]);
return (
<svg
ref={d3Ref}
/>
);
}
export default Leaderboard;
const data = [
...
{ "id":15, "value":33, "label":"Indonesia" },
{ "id":16, "value":14, "label":"China" },
{ "id":21, "value":7, "label":"Germany" },
{ "id":22, "value":12, "label":"China" },
{ "id":23, "value":38, "label":"Argentina" },
{ "id":24, "value":58, "label":"China" },
...
];
우선, 우리는 디자인이 유연하고 응답이 빠르기를 원하기 때문에 SVG
data.js
파라미터를 사용해서는 안 된다.따라서 SVG 어셈블리의 고정 너비와 높이를 지정해야 합니다.우리는 차트 상단의 높이를 알고 있기 때문에, 우리는 전체 높이를 쉽게 계산해 낼 수 있다.만약 우리가 생각한다면, 우리도 약간의 간격과 충전을 넣을 수 있다.
수직 차트를 원하기 때문에, 모든 수평 공간을 차지해야 하고, CSS 너비는
viewBox
이어야 한다.불행하게도, 우리는 쓸 수 없습니다. 100%
픽셀 값을 사용해야 합니다.해결책은 모 어셈블리에서 서브어셈블리를 측정하는 것입니다.<svg width="100%"/>
에서 자식 객체의 폭을 측정합니다.그런 다음 너비를 매개변수로 전달할 수 있습니다.이것은 새것
App.jsx
이다.function Leaderboard({data, width}) {
// ...
// Constant (in px)
const rowHeight = 60;
// Total height of the leaderboard
const [height, setHeight] = useState(rowHeight * data.length ?? 0);
useEffect(() => {
// Update total height, to use the most up-to-date value
setHeight(rowHeight * data.length);
const height = rowHeight * data.length;
// ...
}, [d3Ref, data, width]);
return (
<svg
width={width}
height={height}
ref={d3Ref}
/>
);
}
Leaderboard
의 경우 어셈블리의 크기를 쉽게 측정할 수 있는 단순한 단일 선 솔루션이 없습니다.따라서 우리는 React 라이브러리react-use-measure를 사용할 것이다.그것은 인기가 많고 사용하기 쉽다.이것은 우리
Leaderboard
를 이렇게 보게 한다.import useMeasure from 'react-use-measure';
// ...
// Use React-use-measure to measure the Leaderboard component
const [ref, {width: leaderboardWidth}] = useMeasure({debounce: 100});
return (
// ...
<div className="leaderboard-container" ref={ref}>
<Leaderboard
data={data}
width={leaderboardWidth}
/>
</div>
// ...
);
마지막 중요한 일: CSS에 상수App
와 App
를 설정하는 것을 잊지 마세요. 그러면 차트 구성 요소가 기한 없이 넓어지지 않고 작은 장치에서 보기 좋아요!SVG 그려달래요!
심심한 일을 다 끝냈으니 놀 때가 되었다🥳 !
useEffect(() => {
// ...
// Select the root SVG tag
const svg = d3.select(d3Ref.current);
// Scales
// Get the biggest value in the set,
// to draw all other relative to the maximum value.
const maxValue = d3.max(data.map(d => +d.value)) ?? 1;
const x = d3.scaleLinear().domain([0, maxValue]).range([5, width]);
const y = d3.scaleLinear().domain([0, data.length]).range([0, height]);
// Join the data
// We use the ID of a row to distinguish identical elements.
const g = svg.selectAll('g').data(data, d => d.id);
먼저 루트 SVG 구성 요소를 선택하고 데이터 행당 하나의 요소max-width
요소를 그립니다.SVG에서 width: 100%
요소는 다른 요소 그룹일 뿐입니다.
우리는 또한 데이터 집합의 최대 값을 사용하여 일부 축소 실용 함수<g>
와 <g>
를 정의했다.
마지막 줄에서 D3에게 알려주자.js는 한 줄의 ID를 사용하여 같은 줄을 찾습니다.데이터가 변경되거나 화면이 커질 때마다 코드가 실행되기 때문에 줄을 그렸을 수도 있습니다.값이 같을 수도 있지만, 순서가 다를 수도 있으니, 우리는 그것을 이동해야 한다.따라서 D3를 사용합니다.js, 우리는 우리가 한 줄을 만들고, 업데이트하고, 삭제할지 쉽게 결정할 수 있습니다.
간단하게 살펴보자면, 먼저 우리가 만들 때 줄을 정의한 다음에, 어떻게 모든 줄을 업데이트하는지 (새로 만든 줄은 이전에 수정한 줄도 포함하지만), 마지막으로 우리는 줄을 삭제하기 전에 작은 애니메이션을 정의할 것이다.
행 작성
초기화할 때, 우리는 SVG의 프레임워크를 간단하게 정의할 것입니다. 즉, 가능한 한 많은 정적 정보를 사용하여 탭을 만들 것입니다.x
함수는 만들어야 하는 줄을 격리하는 데 사용됩니다.
// Initialization
const gEnter = g.enter()
.append('g')
.attr('transform', `translate(0, ${y(data.length) + 500})`);
우선, 우리는 줄의 y
요소를 정의하고 그것을 전환한다.이 변환 명령은 그룹을 수직으로 g.enter()
으로 이동합니다.다시 말하면, 이 줄을 차트 밑부분 밖으로 옮겨 보이지 않게 할 것이다.새 줄을 추가할 때 작은 enter 애니메이션을 만들 수 있습니다.
// More constants !
const fontSize = '1.1rem';
const textColor = 'black';
const bgColor = '#d4d8df'; // Background bar color (grey)
const barColor = '#3d76c1'; // Main bar color (blue)
const barHeight = 10;
const marginText = 2; // Margin between the text and the bars
// Append background rect as child
gEnter
.append('rect')
.attr('class', 'bg')
.attr('fill', bgColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5)
.attr('height', barHeight);
// Append main rect as child
gEnter
.append('rect')
.attr('class', 'main')
.attr('fill', barColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5) // Rectangle border radius
.attr('height', barHeight);
// Append label text as child
gEnter
.append('text')
.attr('class', 'label')
.attr('font-size', fontSize)
.attr('fill', textColor)
.attr('x', 0)
.attr('y', -5)
.text(d => d.label);
// Append value text as child
gEnter
.append('text')
.attr('class', 'value')
.attr('text-anchor', 'end')
.attr('fill', textColor)
.attr('font-size', fontSize)
.attr('y', -5);
우리의 줄은 네 가지 요소로 구성되어 있다.
useEffect(() => {
// ...
// Select the root SVG tag
const svg = d3.select(d3Ref.current);
// Scales
// Get the biggest value in the set,
// to draw all other relative to the maximum value.
const maxValue = d3.max(data.map(d => +d.value)) ?? 1;
const x = d3.scaleLinear().domain([0, maxValue]).range([5, width]);
const y = d3.scaleLinear().domain([0, data.length]).range([0, height]);
// Join the data
// We use the ID of a row to distinguish identical elements.
const g = svg.selectAll('g').data(data, d => d.id);
// Initialization
const gEnter = g.enter()
.append('g')
.attr('transform', `translate(0, ${y(data.length) + 500})`);
// More constants !
const fontSize = '1.1rem';
const textColor = 'black';
const bgColor = '#d4d8df'; // Background bar color (grey)
const barColor = '#3d76c1'; // Main bar color (blue)
const barHeight = 10;
const marginText = 2; // Margin between the text and the bars
// Append background rect as child
gEnter
.append('rect')
.attr('class', 'bg')
.attr('fill', bgColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5)
.attr('height', barHeight);
// Append main rect as child
gEnter
.append('rect')
.attr('class', 'main')
.attr('fill', barColor)
.attr('x', 0).attr('y', marginText)
.attr('rx', 5).attr('ry', 5) // Rectangle border radius
.attr('height', barHeight);
// Append label text as child
gEnter
.append('text')
.attr('class', 'label')
.attr('font-size', fontSize)
.attr('fill', textColor)
.attr('x', 0)
.attr('y', -5)
.text(d => d.label);
// Append value text as child
gEnter
.append('text')
.attr('class', 'value')
.attr('text-anchor', 'end')
.attr('fill', textColor)
.attr('font-size', fontSize)
.attr('y', -5);
이 선들은 매우 자명하기 때문에 우리는 색깔, 크기, 위치 속성을 네 개의 요소로 설정한다.
행 업데이트
현재, 우리는 모든 필요한 줄을 만들었습니다. 만약 필요하다면, 우리는 그것들을 업데이트하는 것을 책임질 수 있습니다.
// Update each g row, when data changes
const gUpdate = g.merge(gEnter);
gUpdate
.transition()
.ease(d3.easePoly)
.duration(500)
.attr('transform', (d, i) => `translate(0, ${y(i) + 30})`);
부모<g>
를 사용하기 때문에,transform 속성만 업데이트하면 줄을 정확한 위치로 이동할 수 있습니다.우리가 값 y(data.length) + 500
이 아닌 색인 매개 변수를 순서대로 표시하는 것을 보실 수 있습니다.또한 전환 애니메이션을 사용했습니다.만약 당신이 그것을 제거한다면, 모든 줄이 그것들의 위치에 추악한 스냅샷을 가지고 있는 것을 볼 수 있을 것이다.
// Update rect bg
gUpdate
.select('rect.bg')
.attr('width', x(maxValue));
// Update rect main
gUpdate
.select('rect.main')
.transition()
.ease(d3.easePolyOut)
.duration(1000)
.attr('width', d => x(d.value));
// Update value text
gUpdate
.select('text.value')
.text(d => d.value)
.attr('x', x(maxValue));
여기에서 나머지 요소를 업데이트합니다.또한 변환 애니메이션을 사용하여 사각형의 올바른 너비를 설정합니다.텍스트 값도 업데이트했습니다.보시다시피, 라벨은 고정되어 있기 때문에, 우리는 그것을 업데이트할 필요가 없습니다.만약 같은 ID에 고정된 라벨이 없다면, 여기처럼 업데이트해야 할 수도 있습니다.행 제거
일부 줄은 업데이트 후에 데이터 집합에 나타나지 않기 때문에 삭제해야 합니다.이를 위해, 삭제해야 할 줄을 격리하기 위해
<g>
함수를 사용합니다.// Exit animation
g.exit()
.attr('opacity', 1)
.transition()
.ease(d3.easeLinear)
.duration(200)
.attr('transform', (d, i) => `translate(-50, ${y(i)})`)
.attr('opacity', 0)
.remove();
그것들을 제거하기 위해서, 우리는 그것들을 매끄럽게 왼쪽으로 50개의 픽셀을 이동한 다음, 그것들의 불투명도를 천천히 0으로 낮추기만 하면 된다.종료 애니메이션의 지속 시간이 만족스럽지 않으면 조정i
할 수 있습니다.그리고이렇게?
네!이렇게!😁
작은 화면 크기로 시도하고 데이터 입력을 변경할 수 있습니다.항목과 다르게 보일 수 있으므로 더 많은 속성을 추가하고 D3의 매개변수를 조정할 수 있습니다.js 코드.
full project source code 및 a live demo of the leaderboard 📊.
💡 Feel free to follow me on Twitter ( ), to get more articles and tutorial about Web development. I just started writing blog posts and I am trying to build a small audience from it, so there will be plenty of content coming soon ! 😄
Additionaly, tell me in the comments, what other kind of data visualization would you like to build ?
Reference
이 문제에 관하여(D3로 실시간 차트를 만들다.그리고 리액션!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/rhidra/build-a-real-time-leaderboard-with-d3js-and-react--2lmj
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
💡 Feel free to follow me on Twitter ( ), to get more articles and tutorial about Web development. I just started writing blog posts and I am trying to build a small audience from it, so there will be plenty of content coming soon ! 😄
Additionaly, tell me in the comments, what other kind of data visualization would you like to build ?
Reference
이 문제에 관하여(D3로 실시간 차트를 만들다.그리고 리액션!), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rhidra/build-a-real-time-leaderboard-with-d3js-and-react--2lmj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)