d3-vx-helper
v1.0.29
Published
d3 and vx helper for our team
Downloads
16
Readme
d3-helper
d3 图形库,在vx上的二次封装
更多的是对于图形库复用的思考 核心:基础图形的复用及拼接
Why
- 使用 d3 以命令式的方式来进行图形的书写,不太便于图形的复用,往往需要通过函数抽象以及一大堆参数来重用
- 使用 d3 来进行图形的渲染已经非常方便,再抽象成 echart 那种根据配置进行渲染的方式没有太大必要,费时费力且效果差不多。
- vx 以单元拼接的方式来进行书写,非常满足我们的要求
- vx 默认样式并不符合我们的要求,重复的设置各种 props 时,跟我们使用 d3 的过程其实类似,依旧复杂
- 我们需要一种可变的复用单元。
API
其他请直接从@vx 中引用
- Container
- AxisLeft, AxisBottom, AxisTop, AxisRight
- Grid, GridRows, GridColumns
- Line, Bar, LinePath, AreaClosed
- withTooltip, Tooltip
- tickValues, withConfig
- Group
- scaleBand, scalePoint, scaleLinear, scaleTime, scaleLog, scalePower
使用方式
vx 非常巧妙的定义了各种图形单元,支持以声明式使用图形单元进行拼接, 我们对 vx 的默认样式进行了重置,并且添加了 Container 元素,用于定义图形容器
npm i d3-vx-helper
import { appleStock } from "@vx/mock-data";
import {
Container,
scaleLinear,
scaleTime,
Group,
AxisLeft,
AxisBottom,
Grid,
Bar,
LinePath,
AreaClosed
} from "d3-vx-helper";
// 定义getter
const x = d => new Date(d.date);
const y = d => +d.close;
// 定义容器配置
const padding = {
top: 20,
left: 40,
bottom: 20,
right: 20
};
export default class LineGraph {
render() {
return (
<Container width={1000} height={200} padding={padding} x={x} y={y}>
{({ width, height }) => {
// 根据数据定义x,y轴的scale
const xScale = scaleTime({
rangeRound: [0, width],
domain: d3.extent(data, x)
});
const yScale = scaleLinear({
rangeRound: [height, 0],
domain: d3.extent(data, y)
});
return (
<Group>
<Grid
width={width}
height={height}
xScale={xScale}
yScale={yScale}
/>
<AxisBottom top={height} scale={xScale} />
<AxisLeft scale={yScale} />
<AreaClosed
data={data}
xScale={xScale}
yScale={yScale}
x={x}
y={y}
/>
</Group>
);
}}
</Container>
);
}
}
withConfig
很多时候,我们更希望重用自定义单元,比如我的系统里有两种通用的折线样式,提供该方法进行封装, 我们可以在基础单元上不断的进行上层封装,以便灵活快速的使用。
import { LinePath, withConfig } from "d3-vx-helper";
export const DashedRedLine = withConfig({
stroke: "red",
strokeWidth: 1,
strokeDasharray
})(LinePath);
export const BoldBlueLine = withConfig({
stroke: "green",
strokeWidth: 4
})(LinePath);
tooltip
在进行 tooltip 提示时,往往会比较吃力,我们也在配合 vx/shape 进行统新的封装, 提供两种 tooltip 类型,baseTooltip, lineTooltip
return (
<Container
padding={padding}
x={x}
y={y}
// 定义tooltip格式
tooltip={data => (
<div>
{String(x(data))}: {y(data)}
</div>
)}
>
{({ width, height, showBasicTooltip, showLineTooltip, hideTooltip }) => {
const xScale = scaleTime({
rangeRound: [0, width],
domain: d3.extent(data, x)
});
const yScale = scaleLinear({
rangeRound: [height, 0],
domain: d3.extent(data, y)
});
return (
<Group>
<Grid width={width} height={height} xScale={xScale} yScale={yScale} />
<AxisBottom top={height} scale={xScale} />
<AxisLeft scale={yScale} />
<Group className="line-graph">
<AreaClosed
data={data}
xScale={xScale}
yScale={yScale}
x={x}
y={y}
/>
// 定义整个图形触发区间
<Bar
x={0}
y={0}
width={width}
height={height}
fill="transparent"
data={data}
onMouseMove={d => e =>
showLineTooltip({
event: e,
data: d,
xScale,
yScale
})}
onMouseLeave={d => e => hideTooltip()}
/>
</Group>
</Group>
);
}}
</Container>
);
withTooltip
对于复杂的 tooltip,或者多个 tooltip,可以用 withTooltip 装饰器来实现:
@withTooltip
class Area {
render () {
const {
showTooltip,
hideTooltip,
tooltipData,
tooltipTop,
tooltipLeft
} = this.props
return <div>
<Graph>
<Tooltip ...>
</div>
}
}
tickValues
我们使用 axis.ticks 设置坐标的刻度是,往往产生的刻度数量是不准确的。 我们可以使用 axis.tickValues 使用指定的数组作为刻度。在这里我们提供一个方法,来自动获取精准数量的指定数组。
import { tickValues } from 'd3-vx-helper'
<AxisBottom tickValues={tickValues(4, [0, d3.max(data)])}>