SVG画扇形,可以改变数量、扇形角度、扇形方向

效果图有点low,忍一忍吧

最近做项目,需求是在地图上实现一个基站,虽然基站是由扇形组成的2D图标(就像一个风扇)

来个图吧:

但是有个要求

用户可以配置任意多个扇形,任意角度大小,任意方向的扇形,后期基站某个扇叶坏了,可能还得配置颜色为红色

其他需求就不多赘述了,来看看这个可以任意配置的风(基)扇(站)怎么实现吧。

本来一开始想让UI多出几个图标,但是想到需求描述,就感觉不太现实。

于是我打算用svg画一个,但是svg我不太熟啊,于是去问度娘,找到一个教程

是这样的:

如何快速绘制任意角度的扇形? - wangmeijian - 博客园

大致就是利用svg设置虚线,设置虚线起始位置偏移量实现的,大家可以自己看看。

我按照方法撸了一遍,根据需求实现了下图:

 效果看得家,实现起来也简单。但是,需求图标,是有边框的,这个方法利用虚线,扇形面积是由线宽实现的,所以...

重新找方法吧,前端难啊

研究了svg基本图形,有线条、文字、矩形、圆、椭圆,跟扇形搭不上边,然后还有一个path,可以实现任意路径的图形

但是path里那一堆,啥玩意儿啊,一会M、一会A、一会L,得没办法只能慢慢研究了

预研了一遍path属性d的值,突然看到一篇教程:

使用SVG绘制圆形、扇形、文字实现转盘抽奖效果_朱维娜的博客-CSDN博客_svg扇形效果图如下:思路:1.先引入SVG<!--html--><!--因为转盘中的文字及奖品个数都是动态的,所以在js中生成svg字符串,利用vue的v-html渲染到页面--><svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg" v-https://blog.csdn.net/zhu_06/article/details/81812504

短小精悍,关键我看了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度方向,根据数学公式已知角度,计算圆弧上的点的公式;

js 求圆周每个点坐标解决 threejs 获取2D圆上的每个点 - Nayek - 博客园JS Math.sin() 与 Math.cos() 用法 Math.sin(x) x 的正玄值。返回值在 -1.0 到 1.0 之间; Math.cos(x) x 的余弦值。返回的是 -1.0 到https://www.cnblogs.com/nayek/p/15566658.html根据公式

圆上每个点的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,略微补上一点我的不足吧

感谢大家,喜欢点个赞,不喜勿喷。码字不易,且行且发财;

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值