效果图有点low,忍一忍吧
最近做项目,需求是在地图上实现一个基站,虽然基站是由扇形组成的2D图标(就像一个风扇)
来个图吧:
但是有个要求
用户可以配置任意多个扇形,任意角度大小,任意方向的扇形,后期基站某个扇叶坏了,可能还得配置颜色为红色
其他需求就不多赘述了,来看看这个可以任意配置的风(基)扇(站)怎么实现吧。
本来一开始想让UI多出几个图标,但是想到需求描述,就感觉不太现实。
于是我打算用svg画一个,但是svg我不太熟啊,于是去问度娘,找到一个教程
是这样的:
如何快速绘制任意角度的扇形? - wangmeijian - 博客园
大致就是利用svg设置虚线,设置虚线起始位置偏移量实现的,大家可以自己看看。
我按照方法撸了一遍,根据需求实现了下图:
效果看得家,实现起来也简单。但是,需求图标,是有边框的,这个方法利用虚线,扇形面积是由线宽实现的,所以...
重新找方法吧,前端难啊
研究了svg基本图形,有线条、文字、矩形、圆、椭圆,跟扇形搭不上边,然后还有一个path,可以实现任意路径的图形。
但是path里那一堆,啥玩意儿啊,一会M、一会A、一会L,得没办法只能慢慢研究了
预研了一遍path属性d的值,突然看到一篇教程:
短小精悍,关键我看了path相关的东西,这文章居然能看懂。
所以,我们看看我的实现步骤吧(废话有点多)
1. 创建一个vue文件,fan-svg.vue,插入一个svg标签,大致如下:
<svg width="102" height="102" xmlns="http://www.w3.org/2000/svg" >
<g>
...
</g>
</svg>
2.再插入一个path标签
<path class="fan_path" d="`M51 51 A50 50 0 0 0 Z" />
思路大致就是,画笔移动到点位(51,51)的位置。先画一条直线,然后画一个弧线,再画直线到圆心位置闭合成一个扇形
<path class="fan_path" d="`M51 51 Lx1 y1 A50 50 0 0 0 x2 y2 Z" />
简略介绍下d的值几个字母的意思:
M: 移动到一个坐标位置,我这里设置(51, 51),留了一像素的线条宽度
L: 画线到某个点位(x1, y1)
A: 弧线命令,后面的参数第一、第二个是弧线的半径(rx, ry),后面是哪个参数分别是旋转角度、弧线方向、弧线大小;我设置为3个0,分别是旋转0度、内向弧、小弧度,也就是下图的第一个图
上图:x弧线方向、y弧线大小
看不明白的参考:
路径 - SVG | MDNhttps://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial/Paths 点(x1, y1) (x2, y2)是两个弧线的控制点,同时也是扇形两条直线边的端点。这两个点决定了扇形的角度,所以我要做的就是,通过用户设置的角度大小,计算出两个点的位置。
3. 计算弧线在圆周上的控制点
我们假设x轴线方向是我们的0度方向,根据数学公式已知角度,计算圆弧上的点的公式;
圆上每个点的X坐标=a + Math.sin(2Math.PI / 360) * r ;Y坐标=b + Math.cos(2Math.PI / 360) * r;
计算出一组数据:
computed: {
fanLists() {
return this.fanList.map(t => {
const angle1 = t.dir - (t.angle / 2);
const angle2 = t.dir + (t.angle / 2);
const x1 = 51 + Math.sin(Math.PI / 180 * angle1) * 50;
const y1 = 51 + Math.cos(Math.PI / 180 * angle1) * 50;
const x2 = 51 + Math.sin(Math.PI / 180 * angle2) * 50;
const y2 = 51 + Math.cos(Math.PI / 180 * angle2) * 50;
return Object.assign({}, t, {x1, y1, x2, y2})
})
}
},
然后我循环path标签,每个path标签都是一个扇形
<path
class="fan_path"
v-for="(t,i) in fanLists"
:key="i"
:d="`M300 100 L${t.x1} ${t.y1} A50 50 0 0 0 ${t.x2} ${t.y2} Z`"
></path>
有点像了,给图形加个色先:
<g
fill="rgba(255, 255, 0, 0.5)"
stroke="orange"
>
...
</g>
但是感觉跟我假设的x轴方向,为0度方向好像不对,而且根据我的原始数据,好像是逆时针绘制的;
初始化数据:
[
{angle: 30, dir: 0},
{angle: 15, dir: 30},
{angle: 30, dir: 45},
{angle: 30, dir: 90},
{angle: 60, dir: 180},
{angle: 22, dir: 270},
{angle: 22, dir: 300},
]
4. 调整svg绘制方向
其实需求是要求x轴向为0度方向的
于是我给g标签加上以下代码:
<g
fill="rgba(255, 255, 0, 0.5)"
stroke="orange"
transform-origin="300 100"
style="transform: rotateY(180deg) rotateZ(90deg);"
>
...
</g>
再给path标签加个鼠标样式:
.fan_path {
cursor: pointer;
}
.fan_path:hover {
fill: #42b983;
}
效果:
哈,效果棒棒的;
客户需求是,扇叶有可能重合,这个重合是我故意设置的;
以上就是我用svg实现的扇形绘制方法;
当然,项目中并没有用到,改用canvas绘制了,原因是每次添加地图覆盖物比添加地图图层要方便,我只需要根据数据生成一张canvas画布,再转换成base64,将base64URL制作成ICON,会比引用svg制作要方便很多;
也就是应用场景不方便
权当学习svg,略微补上一点我的不足吧
感谢大家,喜欢点个赞,不喜勿喷。码字不易,且行且发财;