构建力导向图与集成流行图表库
1. 构建力导向图
力导向图是一种强大的可视化工具,用于展示节点和边之间的关系。下面将介绍如何使用 React、D3 和 TypeScript 构建一个力导向图。
1.1 数据管理
使用 Recoil 进行数据管理,设置一个选择器来获取数据。以下是
powerChartSelectors.ts
文件的代码:
// src/recoil/selectors/powerChartSelectors.ts
import { selector } from 'recoil'
import { Types } from '../../components/SimpleForceGraph/types'
export const getPowerChartData = selector({
key: 'getPowerChartData',
get: () => {
return getDataFromAPI()
},
})
const getDataFromAPI = () =>
new Promise((resolve) =>
fetch('/data/power_network.json').then((response) => {
if (response.status !== 200) {
// eslint-disable-next-line no-console
console.log(`Houston, we have a problem! ${response.status}`)
return
}
response.json().then((data) => {
const d = data.results[0] as Types.dataObject
resolve(d)
})
})
)
1.2 网络小部件
创建一个
NetworksWidget
组件,用于集成力导向图和 Recoil 选择器。以下是
NetworksWidget.tsx
文件的代码:
// src/component/QuestionsWidget/QuestionsWidget
import React, { useState } from 'react'
import './NetworksWidget.scss'
import { useRecoilValue } from 'recoil'
import SimpleForceGraph from '../../components/SimpleForceGraph/SimpleForceGraph'
import { Types } from '../../components/SimpleForceGraph/types'
import { getPowerChartData } from '../../recoil/selectors/powerChartSelectors'
const NetworksWidget = () => {
const forceData: Types.dataObject = useRecoilValue(getPowerChartData) as Types.dataObject
const [selectedIndex, setSelectedIndex] = useState(0)
return (
<>
{forceData ? (
<>
<div className="selectedText">Selected Index: {selectedIndex}</div>
<div className="wrapperDiv">
<SimpleForceGraph
width={800}
height={350}
data={forceData}
onNodeSelected={setSelectedIndex}
linkDistance={80}
linkStrength={1}
chargeStrength={-20}
centerWidth={350}
centerHeight={170}
/>
</div>
</>
) : (
<>Loading</>
)}
</>
)
}
export default NetworksWidget
1.3 样式设置
设置
NetworksWidget
的样式,确保图表不溢出。以下是
NetworksWidget.scss
文件的代码:
.wrapperDiv {
width: 800px;
height: 350px;
clip-path: inset(10px 20px 30px 40px);
}
.selectedText {
font-size: 13px;
color: #373636;
}
1.4 父组件
在
App.tsx
中添加
NetworksWidget
组件。以下是
App.tsx
文件的代码:
// src/App.tsx
import React from 'react'
import './App.scss'
import NetworksWidget from './widgets/NetworksWidget/NetworksWidget'
function App() {
return (
<div className="App">
<header className="App-header">
<NetworksWidget />
</header>
</div>
)
}
export default App
2. 集成流行图表库
D3 是创建图表的标准库,结合 React 可以带来更多好处。以下将介绍一些流行的 React/D3 库,并进行比较和实现。
2.1 流行的 React/D3 库
以下是一些流行的 React/D3 库:
- Recharts: https://github.com/recharts/recharts (示例: http://recharts.org/en-US/examples)
- Visx: https://github.com/airbnb/visx (示例: https://airbnb.io/visx/gallery)
- Victory: https://github.com/FormidableLabs/victory (示例: https://formidable.com/open-source/victory/gallery)
- Nivo: https://github.com/plouc/nivo (示例: https://nivo.rocks/components)
- React-vi: https://github.com/uber/react-vis (示例: https://github.com/uber/react-vis/tree/master/docs/examples/showcases)
2.2 库的比较
| 图表库 | 成本 | 支持 TS | 模块化 | 模拟数据 | 简单性 | 已样式化 | 文档 | 示例 | 贡献者 | 受欢迎程度 | 开放问题 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Recharts | 432KB 👎 | 是 | 否 👎 | 否 | 是 | 否 | 是 | 是 | 177 👍 | 15600 👍 | 131 |
| Visx | 91KB 👍 | 是 | 是 | 是 | 否 👎 | 是👍 | 是 | 是 | 87 | 12500 | 72 👍 |
| Victory | 164KB | 是 | 是 | 是 | 是 👍 | 否 | 是 | 是 | 135 | 8500 | 154 |
| Nivo | 241KB | 是 | 是 | 是, nivo - generators | 是 | 是 | 是 | 是 | 113 | 7800 | 133 |
| React - vis | 316KB 👎 | 部分 | 是 | 否 | 是 | 是 | 是 | 是 | 116 | 7500 | 277 👎 |
2.3 实现 Rechart
Rechart 是一个基于 React 组件的可组合图表库。以下是实现步骤:
2.3.1 安装
yarn add recharts @types/recharts
2.3.2 定义类型
// src/component/SimpleLineChart/types.ts
export namespace Types {
export type Data = {
date: string
value: number
}
}
2.3.3 实现简单折线图组件
// src/component/SimpleLineChart/SimpleLineChart.tsx
import React from 'react'
import { LineChart, Line, XAxis, CartesianGrid, Tooltip, YAxis } from 'recharts'
import { Types } from './types'
const CustomizedAxisTick = (props: { x: number; y: number; payload: { value: string } }) => {
return (
<g transform={`translate(${props.x},${props.y})`}>
<text fontSize={12} x={0} y={0} dy={16} textAnchor="end" fill="black" transform="rotate(-35)">
{props.payload.value}
</text>
</g>
)
}
const CustomizedYAxisTick = (props: { x: number; y: number; payload: { value: string } }) => {
return (
<g transform={`translate(${props.x},${props.y})`}>
<text fontSize="12px" x={0} y={0} dy={0} textAnchor="end" fill="black">
{props.payload.value}
</text>
</g>
)
}
const EmptyDot = () => {
return <></>
}
const SimpleLineChart = (props: ISimpleLineChartProps) => {
return (
<>
<LineChart
width={500}
height={300}
data={props.data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
height={60}
dataKey="date"
// @ts-ignore
tick={<CustomizedAxisTick />}
/>
<YAxis
// @ts-ignore
tick={<CustomizedYAxisTick />}
/>
<Tooltip />
<Line type="monotone" dataKey="value" stroke="#8884d8" dot={<EmptyDot />} />
</LineChart>
</>
)
}
interface ISimpleLineChartProps {
data: Types.Data[]
}
export default SimpleLineChart
2.3.4 获取数据
// src/recoil/selectors/lineDataSelectors.ts
import { selector } from 'recoil'
import * as d3 from 'd3'
export const getLineData = selector({
key: 'getLineData',
get: () => {
return getData()
},
})
const getData = () =>
new Promise((resolve) =>
d3
.dsv(',', '/Data/line.csv', (d) => {
const res = d as { date: string; data: string }
const value = parseFloat(res.data as string)
const { date } = res
return {
date,
value,
}
})
.then((data) => {
resolve(data)
})
)
2.3.5 父组件
// src/App.tsx
import React from 'react'
import './App.scss'
import { useRecoilValue } from 'recoil'
import SimpleLineChart from './components/SimpleLineChart/SimpleLineChart'
import { Types } from './components/SimpleLineChart/types'
import { getLineData } from './recoil/selectors/lineDataSelectors'
function App() {
const data = useRecoilValue(getLineData) as Types.Data[]
return (
<div className="App">
<header className="App-header">
<SimpleLineChart data={data} />
</header>
</div>
)
}
export default App
通过以上步骤,你可以构建一个力导向图,并集成流行的图表库 Rechart。不同的图表库有不同的特点和适用场景,你可以根据自己的需求选择合适的库。
构建力导向图与集成流行图表库
3. 实现其他流行图表库
3.1 实现 Visx
Visx 是 Airbnb 创建的用于 React 的低级别可视化原语集合。以下是实现步骤:
步骤 1:创建新项目
yarn create react-app react-chart-libraries --template must-have-libraries
cd react-chart-libraries
yarn start
open http://localhost:3000
步骤 2:安装 Visx
yarn add @visx/visx
步骤 3:实现简单的柱状图
// src/component/SimpleBarChart/SimpleBarChart.tsx
import React from 'react';
import { Group } from '@visx/group';
import { Bar } from '@visx/shape';
import { scaleBand, scaleLinear } from '@visx/scale';
const data = [
{ key: 'A', value: 10 },
{ key: 'B', value: 20 },
{ key: 'C', value: 30 },
{ key: 'D', value: 40 },
];
const width = 500;
const height = 300;
const margin = { top: 20, right: 20, bottom: 20, left: 20 };
const xScale = scaleBand({
range: [0, width - margin.left - margin.right],
domain: data.map(d => d.key),
padding: 0.2,
});
const yScale = scaleLinear({
range: [height - margin.top - margin.bottom, 0],
domain: [0, Math.max(...data.map(d => d.value))],
});
const SimpleBarChart = () => {
return (
<svg width={width} height={height}>
<Group top={margin.top} left={margin.left}>
{data.map((d, i) => {
const barWidth = xScale.bandwidth();
const barHeight = height - margin.top - margin.bottom - yScale(d.value);
return (
<Bar
key={i}
x={xScale(d.key)}
y={yScale(d.value)}
width={barWidth}
height={barHeight}
fill="#8884d8"
/>
);
})}
</Group>
</svg>
);
};
export default SimpleBarChart;
步骤 4:父组件使用
// src/App.tsx
import React from 'react';
import './App.scss';
import SimpleBarChart from './components/SimpleBarChart/SimpleBarChart';
function App() {
return (
<div className="App">
<header className="App-header">
<SimpleBarChart />
</header>
</div>
);
}
export default App;
3.2 实现 Victory
Victory 是一个用于 React 的声明式图表库。以下是实现步骤:
步骤 1:安装 Victory
yarn add victory
步骤 2:实现简单的折线图
// src/component/SimpleVictoryLineChart/SimpleVictoryLineChart.tsx
import React from 'react';
import { VictoryChart, VictoryLine } from 'victory';
const data = [
{ x: 1, y: 10 },
{ x: 2, y: 20 },
{ x: 3, y: 30 },
{ x: 4, y: 40 },
];
const SimpleVictoryLineChart = () => {
return (
<VictoryChart>
<VictoryLine data={data} />
</VictoryChart>
);
};
export default SimpleVictoryLineChart;
步骤 3:父组件使用
// src/App.tsx
import React from 'react';
import './App.scss';
import SimpleVictoryLineChart from './components/SimpleVictoryLineChart/SimpleVictoryLineChart';
function App() {
return (
<div className="App">
<header className="App-header">
<SimpleVictoryLineChart />
</header>
</div>
);
}
export default App;
3.3 实现 Nivo
Nivo 是一个提供丰富图表组件的库。以下是实现步骤:
步骤 1:安装 Nivo
yarn add @nivo/core @nivo/line
步骤 2:实现简单的折线图
// src/component/SimpleNivoLineChart/SimpleNivoLineChart.tsx
import React from 'react';
import { ResponsiveLine } from '@nivo/line';
const data = [
{
id: 'line',
data: [
{ x: 'A', y: 10 },
{ x: 'B', y: 20 },
{ x: 'C', y: 30 },
{ x: 'D', y: 40 },
],
},
];
const SimpleNivoLineChart = () => {
return (
<div style={{ height: 300 }}>
<ResponsiveLine
data={data}
margin={{ top: 50, right: 110, bottom: 50, left: 60 }}
xScale={{ type: 'point' }}
yScale={{ type: 'linear', min: 'auto', max: 'auto' }}
axisTop={null}
axisRight={null}
axisBottom={{
orient: 'bottom',
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'X Axis',
legendOffset: 36,
legendPosition: 'middle',
}}
axisLeft={{
orient: 'left',
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'Y Axis',
legendOffset: -40,
legendPosition: 'middle',
}}
/>
</div>
);
};
export default SimpleNivoLineChart;
步骤 3:父组件使用
// src/App.tsx
import React from 'react';
import './App.scss';
import SimpleNivoLineChart from './components/SimpleNivoLineChart/SimpleNivoLineChart';
function App() {
return (
<div className="App">
<header className="App-header">
<SimpleNivoLineChart />
</header>
</div>
);
}
export default App;
3.4 实现 React - vis
React - vis 是 Uber 开发的用于 React 的可视化库。以下是实现步骤:
步骤 1:安装 React - vis
yarn add react-vis
步骤 2:实现简单的散点图
// src/component/SimpleScatterPlot/SimpleScatterPlot.tsx
import React from 'react';
import {
XYPlot,
XAxis,
YAxis,
VerticalGridLines,
HorizontalGridLines,
ScatterPlotSeries,
} from 'react-vis';
const data = [
{ x: 1, y: 10 },
{ x: 2, y: 20 },
{ x: 3, y: 30 },
{ x: 4, y: 40 },
];
const SimpleScatterPlot = () => {
return (
<XYPlot width={500} height={300}>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis />
<YAxis />
<ScatterPlotSeries data={data} color="#8884d8" />
</XYPlot>
);
};
export default SimpleScatterPlot;
步骤 3:父组件使用
// src/App.tsx
import React from 'react';
import './App.scss';
import SimpleScatterPlot from './components/SimpleScatterPlot/SimpleScatterPlot';
function App() {
return (
<div className="App">
<header className="App-header">
<SimpleScatterPlot />
</header>
</div>
);
}
export default App;
4. 总结
不同的图表库各有优缺点,以下是一个简单的对比总结:
| 图表库 | 优点 | 缺点 |
|---|---|---|
| Recharts | 易于使用 SVG 自定义图表,图表种类多,受欢迎程度高,社区活跃 | 非模块化,单个图表成本较高 |
| Visx | 成本低,模块化,样式已设置好,开放问题少 | 学习和实现相对复杂 |
| Victory | 支持 TS,有模拟数据,实现简单 | 有一定的成本 |
| Nivo | 支持 TS,模块化,有模拟数据生成器,样式已设置好 | 实现时容器需设置宽高 |
| React - vis | 支持部分 TS,模块化,有样式设置 | 成本较高,受欢迎程度和支持度相对较低 |
在选择图表库时,需要根据项目的具体需求,如成本、复杂度、对 TypeScript 的支持等因素进行综合考虑。希望通过本文的介绍,你能更好地选择适合自己项目的图表库。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(选择图表类型):::process
B --> C{选择图表库}:::decision
C -->|Recharts| D(安装并实现相应图表):::process
C -->|Visx| E(安装并实现相应图表):::process
C -->|Victory| F(安装并实现相应图表):::process
C -->|Nivo| G(安装并实现相应图表):::process
C -->|React - vis| H(安装并实现相应图表):::process
D --> I([结束]):::startend
E --> I
F --> I
G --> I
H --> I
以上流程图展示了选择图表库并实现图表的基本流程。你可以根据自己的需求选择合适的图表库,然后按照相应的步骤进行实现。
超级会员免费看
3524

被折叠的 条评论
为什么被折叠?



