这里先准备一个静态的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上
<view class="container">
<image style="width:600rpx; height: 600rpx;" src="{{ftp_director}}/secs.svg">image>
view>
可以看到,微信小程序的image标签是能够正常显示svg类型的网络图片的
接下来,我们把svg文件放到小程序静态资源下,再用image加载看下
<view class="container">
<image style="width:600rpx; height: 600rpx;" src="../../components/turnable-svg/images/secs.svg">image>
view>
可以看到,同样也是能够正常显示的
那么问题来了,实现大转盘功能需要我们根据奖品数量去动态生成扇形数量,组成圆盘,通过上述两种办法明显达不到我们要的效果,那么应该怎么办呢?那么我们可不可以将svg的内容直接设置在image标签上类似base64的方式显示出图片呢,答案当然是可以,那么我们继续,接下来才是重点哦
//index.js
//获取应用实例
const app = getApp()
Page({
data: {
svgRawStr: '',
svg: ""
},
onLoad: function() {
var svgRawStr = this.data.svgRawStr
var svg = "data:image/svg+xml," + svgRawStr
this.setData({
svg: svg
})
}
})
可以看到,同样也是支持的,微信小程序的image标签还是挺强大的
既然我们可以将svg的内容作为一个字符串正常显示在image标签上,而这个字符串我们是可以通过设置的奖品去动态生成的,从而达到我们想要的效果,通过奖品动态生成圆盘
好了,既然有了思路,那我们就基于svg来一步一步实现大转盘的自定义组件
<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>
确定第一个扇形(与圆右端点重和的扇形),假设扇形半径为r,圆形坐标为c(x, y),夹角为alpha,其中一个端点为(2r,r),则另一个端点坐标为
(cx + r*cos(alpha), cy - r*sin(alpha))
<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 = `" 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 = `${rotate} ,${centerX},${centerY})">${colors[k]} " d="M${mx}, ${my} L${lx}, ${ly} A${ax}, ${ay} 0 0, 0 ${dx}, ${dy} z">`
svgRawStr += sec
}
svgRawStr += ""
var svg = "data:image/svg+xml," + encodeURIComponent(svgRawStr)
that.setData({
svg: svg
})
})
}
}
})