08_微信小程序之大转盘svg实现

08_微信小程序之大转盘svg实现

一.关于微信小程序对svg的支持

这里先准备一个静态的svg文件做测试

<!--components/turntable-svg/images/secs.svg-->
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g transform="rotate(-67.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(-22.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(22.5,160,160)"><path fill="rgb(239,119,131)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(67.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(112.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(157.5,160,160)"><path fill="rgb(239,119,131)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(202.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
  <g transform="rotate(247.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g>
</svg>

那么接下来我们用image标签来显示下服务器端的一个svg,这里我把上述的svg放到了ftp上

<!--index.wxml-->
<view class="container">
  <image style="width:600rpx; height: 600rpx;" src="{{ftp_director}}/secs.svg"></image>
</view>

在这里插入图片描述

可以看到,微信小程序的image标签是能够正常显示svg类型的网络图片的

接下来,我们把svg文件放到小程序静态资源下,再用image加载看下

<!--index.wxml-->
<view class="container">
  <image style="width:600rpx; height: 600rpx;" src="../../components/turnable-svg/images/secs.svg"></image>
</view>

在这里插入图片描述

可以看到,同样也是能够正常显示的

那么问题来了,实现大转盘功能需要我们根据奖品数量去动态生成扇形数量,组成圆盘,通过上述两种办法明显达不到我们要的效果,那么应该怎么办呢?那么我们可不可以将svg的内容直接设置在image标签上类似base64的方式显示出图片呢,答案当然是可以😄,那么我们继续,接下来才是重点哦

<!--index.wxml-->
<view class="container">
  <image style="width:600rpx; height: 600rpx;" src="{{svg}}"></image>
</view>
//index.js
//获取应用实例
const app = getApp()

Page({
  data: {
    svgRawStr: '<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g transform="rotate(-67.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(-22.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(22.5,160,160)"><path fill="rgb(239,119,131)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(67.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(112.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(157.5,160,160)"><path fill="rgb(239,119,131)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(202.5,160,160)"><path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g><g transform="rotate(247.5,160,160)"><path fill="rgb(254,244,61)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path></g></svg>',
    svg: ""
  },
  onLoad: function() {
    var svgRawStr = this.data.svgRawStr
    var svg = "data:image/svg+xml," + svgRawStr
    this.setData({
      svg: svg
    })
  }
})

在这里插入图片描述

可以看到,同样也是支持的,微信小程序的image标签还是挺强大的

既然我们可以将svg的内容作为一个字符串正常显示在image标签上,而这个字符串我们是可以通过设置的奖品去动态生成的,从而达到我们想要的效果,通过奖品动态生成圆盘

好了,既然有了思路,那我们就基于svg来一步一步实现大转盘的自定义组件

二.界面布局

<!--components/turnable-svg/index.wxml-->
<view class="turntable" style="width:{{size}}rpx; height:{{size}}rpx;">
  <image class="outer" src="./images/outer.png"></image>
  <view class="secs"></view>
  <image class="start" src="./images/start.png"></image>
</view>
/* components/turnable-svg/index.wxss */
.turntable {
  position: relative;
  margin-left: 50%;
  transform: translateX(-50%);
}

.outer {
  width: 100%;
  height: 100%;
}

.secs {
  position: absolute;
  left: 40rpx;
  top: 40rpx;
  width: calc(100% - 80rpx);
  height: calc(100% - 80rpx);
}

.start {
  position: absolute;
  width: 112rpx;
  height: 124rpx;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
  z-index: 99;
}
// components/turnable-svg/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    size: {
      type: Number,
      value: 600,
      observer: function(newVal, oldVal) {
        this.setData({
          size: newVal
        })
      }
    },
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {

  }
})

在这里插入图片描述

三.根据奖品个数绘制扇形组成圆盘

svg绘制规则

<path fill="rgb(215,215,215)" d=" M160, 160 L273.1370849898476, 46.86291501015236 A160, 160 0 0, 1 320, 159.99999999999997 z"></path>
<!--参数:
fill是填充的颜色
在d中,如何是绘画半圆的画,
M x,y其中的x,y表述圆心的坐标
L x1,y1标识从x,y到x1,y1的直线。
A表示绘画扇形
A rx,ry ratation_deg,flag1,flag2,x2,y2
其中rx表示x轴的半径
ry表示y轴的半径
ratation_deg 表示绘画的旋转角度,一般为0,
flag1,flag2表示绘画是按照大,还是按照小,也就是按照顺时针还是逆时针来进行绘画。x2,y2和x,y联成的直线为开始线,按照顺时针或者逆时针进行绘画,当和x,y和x1,y1连成的直线为终结线,绘画结束。z表示绘画的路径要闭合,同时file="none"。-->

确定第一个扇形(与圆右端点重和的扇形),假设扇形半径为r,圆形坐标为c(x, y),夹角为alpha,其中一个端点为(2r,r),则另一个端点坐标为

(cx + r*cos(alpha), cy - r*sin(alpha))
<!--components/turnable-svg/index.wxml-->
<!--components/turnable-svg/index.wxml-->
<view class="turntable" style="width:{{size}}rpx; height:{{size}}rpx;">
  <image class="outer" src="./images/outer.png"></image>
  <view class="secs" style="background-size: cover; background-image: url('{{svg}}')"></view>
  <image class="start" src="./images/start.png"></image>
</view>
// components/turnable-svg/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    size: {
      type: Number,
      value: 600,
      observer: function(newVal, oldVal) {
        this.setData({
          size: newVal
        })
      }
    },
    prizeList: {
      type: Array,
      value: [],
      observer: function(newVal, oldVal) {
        this.setData({
          prizeList: newVal
        })
        this.initTurntable()
      }
    }
  },

  lifetimes: {
    ready: function() {
      this.initTurntable()
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    
  },

  /**
   * 组件的方法列表
   */
  methods: {
    initTurntable: function() {
      var that = this
      const query = that.createSelectorQuery()
      query.select('.secs')
        .fields({ node: true, size: true })
        .exec((res) => {

          var size = res[0].width
          //圆心坐标
          var centerX = res[0].width/2
          var centerY = res[0].height/2

          that.setData({
            centerX: centerX,
            centerY: centerY
          })

          //半径
          var radius = size/2

          //奖品数量
          var num = that.data.prizeList.length

          // 扇形旋转转角度
          var rotateDeg = 360 / num / 2 - 90

          var colors = ['#D7D7D7', '#FEF43E', '#EF7683']
          //参数d
          var mx = centerX
          var my = centerY
          var lx = size
          var ly = centerY
          var ax = centerX
          var ay = centerY
          var deg = 0
          var flag1 = 0
          var flag2 = 1
          var dx = centerX + radius * Math.cos((360 / num)  * (Math.PI / 180))
          var dy = centerY - radius * Math.sin((360 / num)  * (Math.PI / 180))

          var svgRawStr = `<svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">`
          //绘制扇形
          for(var i = 0; i < num; i++) {
            var k = i%3
            var rotate = 360 / num * i + rotateDeg
            var sec = `<g transform="rotate(${rotate},${centerX},${centerY})"><path fill="${colors[k]}" d="M${mx}, ${my} L${lx}, ${ly} A${ax}, ${ay} 0 0, 0 ${dx}, ${dy} z"></path></g>`
            svgRawStr += sec
          }
          svgRawStr += "</svg>"
          var svg = "data:image/svg+xml," + encodeURIComponent(svgRawStr)
          that.setData({
            svg: svg
          })
        })
    }
  }
})

在这里插入图片描述

三.关于转盘转动以及奖品摆放可参考 微信小程序之大转盘自定义组件编写 时候不早了,洗洗睡了,不然明天上班要迟到了😄

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值