ReCharts如何借助三角函数绘制Label
前言
Recharts是一个基于React和D3的开源图表库,提供了一系列易于使用的图表组件和可自定义的样式选项。它被设计为简单易用,旨在帮助开发人员快速创建交互式的数据可视化图表。
与Echarts相比,Recharts都有哪些优势?
在比较Recharts和ECharts时,Recharts通常被认为是更轻量级的数据可视化库之一。这是因为Recharts是基于React构建的,它的体积相对较小,而且可以更好地与React应用程序进行集成,因此在使用Recharts时,不需要为了集成图表而额外引入其他JavaScript库。
另外,由于Recharts的设计初衷是为了提供简单易用的API和基于React的组件化开发方式,因此其代码库的规模相对较小,而且在使用上更加直观和易于理解。相比之下,ECharts的代码库相对更大,并且它提供了许多高级功能和复杂的API,需要更长的学习时间和更复杂的配置。
不符合预期的原生UI
这是笔者在某次需求时接到的UI图
在使用Recharts进行饼图生成时,得到的效果如下
真是有点丑,我不能接受
自定义Label
Recharts是一个处理图表的类库,其中的“re”除了指代“React”之外,还有“Redefined”之意,即Recharts支持我们自定义想要的元素。
在自定义元素之前,我们需要先了解一下SVG。SVG是一种基于XML的矢量图形格式,它具有可伸缩性和可编辑性的优点。Recharts可使用SVG来绘制图表元素,因此在自定义图表元素前需要了解SVG的相关知识。
SVG之path
SVG是一种XML语言,可以用来绘制矢量图形。SVG可以通过定义必要的线和形状来创建一个图形。
path是SVG中一个很强大的标签,我们可以使用path来绘制矩形、折线、圆形、多边形,以及一些其他的复杂形状。
先看一段示例代码
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M250 150 L150 350 L350 350 Z" fill="none" stroke="black"/>
</svg>
d属性表示我们要绘画的路径。
M x y:画笔移动到 (x, y),作为起点
L x y :画一条直线到 (x, y)
H x :水平划线到横坐标 x
V y :水平划线到纵坐标 y
Z :闭合路径回到起点(用于创建一个形状)
所以以上示例最终就会画出一个三角形。
那么有了path的支持,我们就可以轻易得画出ui中的折线引导线。
关键在于我们要如何获取到画笔的起点。
图表属性分析
在Recharts自带的renderLabel方法中,我们可以通过props获取一些关键属性
const renderLabel = (props) => {
const { cx, cy, midAngle, outerRadius } = props
}
-
cx:圆心的横坐标
-
cy:圆心的纵坐标
-
midAngle:扇形中心角的一半
-
outerRadius:圆的半径
根据图示,我们所需要的画笔起点,其实就是图上红点对应的位置。
那么直角三角形在已知半径和角度的情况下,如何去获取直角三角形的另外两条边的长度,就得借助我们伟大的三角函数!
三角函数
先来简单复习一下三角函数
有了以上的基本公式后,我们就可以把要求的坐标转化为求三角形边长,即下图中的sx和sy
在已知角度大小的前提下,我们可以求其 和 值
const RADIAN = Math.PI / 180
const sin = Math.sin(-RADIAN * midAngle)
const cos = Math.cos(-RADIAN * midAngle)
❓为什么上面的代码中计算cos和sin时要多添加一个减号
圆中以圆心为起始坐标,可以划分为四个区域,我们称为四个象限。
在第一象限中,引导线画笔起点 (这里并非真正的坐标轴和象限,要忽略正负,而是考虑页面中坐标的相对位置)
又结合cos和sin各自的奇偶性可得, 。
cos与计算sx值相关,sin与计算sy值相关,那么这里以第一象限为例,最终计算出来的sy为负值就很合情理了。
因为我们最终的sy坐标是基于cy的,即
const sy = cy + outerRadius * sin
开画
有了上方提及的所有知识点后,我们就可以轻松计算出画笔起始点的坐标了
const RADIAN = Math.PI / 180
const { cx, cy, midAngle, outerRadius, fill, percent, value } = props
//三角函数基于弧度制,所以需要先转为弧度制获取已知角度的cos和sin值
const sin = Math.sin(-RADIAN * midAngle)
const cos = Math.cos(-RADIAN * midAngle)
//已知cos和sin之后,利用三角函数最终计算出sx和sy的坐标
const sx = cx + outerRadius * cos
const sy = cy + outerRadius * sin
有了起点后,我们需要往外延伸,画出第一条直线。
只需要在原来的基础上加长半径,这样就能得到第二个点的坐标了
//继续往外延伸
const mx = cx + (outerRadius + 15) * cos
const my = cy + (outerRadius + 15) * sin
第三个点的坐标,只需要将x往水平方向延伸即可。需要注意的是往左边延伸,还是右边延伸。
const ex = mx + (cos >= 0 ? 1 : -1) * 42
const ey = my
完整代码
const renderLabel = (props) => {
const RADIAN = Math.PI / 180
const { cx, cy, midAngle, outerRadius, fill, percent, value } = props
const sin = Math.sin(-RADIAN * midAngle)
const cos = Math.cos(-RADIAN * midAngle)
const sx = cx + outerRadius * cos
const sy = cy + outerRadius * sin
const mx = cx + (outerRadius + 15) * cos
const my = cy + (outerRadius + 15) * sin
const ex = mx + (cos >= 0 ? 1 : -1) * 42
const ey = my
const textAnchor = cos >= 0 ? 'start' : 'end'
return (
<g>
<path
d={`M${sx} ${sy} L${mx} ${my} L${ex} ${ey}`}
stroke={'rgba(0,0,0,0.3)'}
fill="none"
/>
<text
x={ex + (cos >= 0 ? 1 : -1) * 5}
y={ey}
textAnchor={textAnchor}
fill={'rgba(0,0,0,0.3)'}
>{`41~50`}</text>
<text
x={ex + (cos >= 0 ? 1 : -1) * 12}
y={ey}
dy={18}
textAnchor={textAnchor}
fill="#222222"
>
{`10%`}
</text>
</g>
)
}
最终效果
转载自:https://juejin.cn/post/7258466145652277304