You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
high-mini/uni_modules/almost-lottery/components/almost-lottery/almost-lottery.vue

956 lines
28 KiB

<template>
<view class="almost-lottery">
<view class="almost-lottery__wrap" :style="{ width: lotterySize + 'rpx', height: lotterySize + 'rpx' }">
<view class="lottery-action"
:style="{ width: actionSize + 'rpx', height: actionSize + 'rpx', left: canvasMarginOutside + 'rpx' }">
</view>
<view class="str-margin-outside" :style="{ left: strMarginOutside + 'rpx' }"></view>
<view class="img-margin-str" :style="{ left: imgMarginStr + 'rpx' }"></view>
<view class="img-size" :style="{ width: imgWidth + 'rpx', height: imgHeight + 'rpx' }"></view>
<template v-if="lotteryImg">
<image class="almost-lottery__bg" mode="widthFix" :src="lotteryBg" :style="{
width: lotteryPxSize + 'px',
height: lotteryPxSize + 'px'
}"></image>
<image class="almost-lottery__canvas-img" mode="widthFix" :src="lotteryImg" :style="{
width: canvasPxSize + 'px',
height: canvasPxSize + 'px',
transform: `rotate(${canvasAngle + targetAngle}deg)`,
transitionDuration: `${transitionDuration}s`
}"></image>
<image class="almost-lottery__action almost-lottery__action-bg" mode="widthFix" :src="actionBg" :style="{
width: actionPxSize + 'px',
height: actionPxSize + 'px',
transform: `rotate(${actionAngle + targetActionAngle}deg)`,
transitionDuration: `${transitionDuration}s`
}" @click="handleActionStart"></image>
</template>
<!-- 正在绘制转盘时的提示文本 -->
<text class="almost-lottery__tip" v-else>{{ almostLotteryTip }}</text>
</view>
<!-- 为了兼容 app ctx.measureText 所需的标签 -->
<text class="almost-lottery__measureText" :style="{ fontSize: higtFontSize + 'px' }">{{ measureText }}</text>
<!-- #ifdef MP-ALIPAY -->
<canvas :class="className" :id="canvasId" :width="higtCanvasSize" :height="higtCanvasSize" :style="{
width: higtCanvasSize + 'px',
height: higtCanvasSize + 'px'
}" />
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<canvas :class="className" :canvas-id="canvasId" :width="higtCanvasSize" :height="higtCanvasSize" :style="{
width: higtCanvasSize + 'px',
height: higtCanvasSize + 'px'
}" />
<!-- #endif -->
</view>
</template>
<script>
const systemInfo = uni.getSystemInfoSync()
import {
getStore,
setStore,
clearStore,
clacTextLen,
downloadFile,
pathToBase64
} from '@/uni_modules/almost-lottery/utils/almost-utils.js'
export default {
name: 'AlmostLottery',
props: {
// 设计稿的像素比基准值
pixelRatio: {
type: Number,
default: 2
},
// canvas 标识
canvasId: {
type: String,
default: 'almostLottery'
},
// 抽奖转盘的整体尺寸
lotterySize: {
type: Number,
default: 600
},
// 抽奖按钮的尺寸
actionSize: {
type: Number,
default: 200
},
// canvas边缘距离转盘边缘的距离
canvasMarginOutside: {
type: Number,
default: 90
},
// 奖品列表
prizeList: {
type: Array,
required: true,
validator: (value) => {
return value.length > 1
}
},
// 中奖奖品在列表中的下标
prizeIndex: {
type: Number,
required: true
},
// 奖品区块对应背景颜色
colors: {
type: Array,
default: () => [
'#FFFFFF',
'#FFBF05'
]
},
// 转盘外环背景图
lotteryBg: {
type: String,
default: '/uni_modules/almost-lottery/static/almost-lottery/almost-lottery__bg2x.png'
},
// 抽奖按钮背景图
actionBg: {
type: String,
default: '/uni_modules/almost-lottery/static/almost-lottery/almost-lottery__action2x.png'
},
// 是否绘制奖品名称
prizeNameDrawed: {
type: Boolean,
default: true
},
// 是否开启奖品区块描边
stroked: {
type: Boolean,
default: false
},
// 描边颜色
strokeColor: {
type: String,
default: '#FFBF05'
},
// 旋转的类型
rotateType: {
type: String,
default: 'roulette'
},
// 旋转动画时间 单位s
duration: {
type: Number,
default: 8
},
// 旋转的圈数
ringCount: {
type: Number,
default: 8
},
// 指针位置
pointerPosition: {
type: String,
default: 'edge',
validator: (value) => {
return value === 'edge' || value === 'middle'
}
},
// 文字方向
strDirection: {
type: String,
default: 'horizontal',
validator: (value) => {
return value === 'horizontal' || value === 'vertical'
}
},
// 字体颜色
strFontColors: {
type: Array,
default: () => [
'#FFBF05',
'#FFFFFF'
]
},
// 文字的大小
strFontSize: {
type: Number,
default: 24
},
// 奖品文字距离边缘的距离
strMarginOutside: {
type: Number,
default: 0
},
// 奖品图片距离奖品文字的距离
imgMarginStr: {
type: Number,
default: 40
},
// 奖品文字多行情况下的行高
strLineHeight: {
type: Number,
default: 1.2
},
// 奖品文字总长度限制
strMaxLen: {
type: Number,
default: 12
},
// 奖品文字多行情况下第一行文字长度
strLineLen: {
type: Number,
default: 6
},
// 奖品图片的宽
imgWidth: {
type: Number,
default: 80
},
// 奖品图片的高
imgHeight: {
type: Number,
default: 80
},
// 是否绘制奖品图片
imgDrawed: {
type: Boolean,
default: true
},
// 转盘绘制成功的提示
successMsg: {
type: String,
default: '奖品准备就绪,快来参与抽奖吧'
},
// 转盘绘制失败的提示
failMsg: {
type: String,
default: '奖品仍在准备中,请稍后再来...'
},
// 是否开启画板的缓存
canvasCached: {
type: Boolean,
default: false
}
},
data() {
return {
// 画板className
className: 'almost-lottery__canvas',
// 抽奖转盘的整体px尺寸
lotteryPxSize: 0,
// 画板的px尺寸
canvasPxSize: 0,
// 抽奖按钮的px尺寸
actionPxSize: 0,
// 奖品文字距离转盘边缘的距离
strMarginPxOutside: 0,
// 奖品图片相对奖品文字的距离
imgMarginPxStr: 0,
// 奖品图片的宽、高
imgPxWidth: 0,
imgPxHeight: 0,
// 画板导出的图片
lotteryImg: '',
// 旋转到奖品目标需要的角度
targetAngle: 0,
targetActionAngle: 0,
// 旋转动画时间 单位 s
transitionDuration: 0,
// 是否正在旋转
isRotate: false,
// 当前停留在那个奖品的序号
stayIndex: 0,
// 当前中奖奖品的序号
targetIndex: 0,
// 是否存在可用的缓存转盘图
isCacheImg: false,
oldLotteryImg: '',
// 转盘绘制时的提示
almostLotteryTip: '奖品准备中...',
// 解决 app 不支持 measureText 的问题
// app 已在 2.9.3 的版本中提供了对 measureText 的支持,将在后续版本逐渐稳定后移除相关兼容代码
measureText: ''
}
},
computed: {
// 高清尺寸
higtCanvasSize() {
return this.canvasPxSize * systemInfo.pixelRatio
},
// 高清字体
higtFontSize() {
return (this.strFontSize / this.pixelRatio) * systemInfo.pixelRatio
},
// 高清行高
higtHeightMultiple() {
return (this.strFontSize / this.pixelRatio) * this.strLineHeight * systemInfo.pixelRatio
},
// 根据奖品列表计算 canvas 旋转角度
canvasAngle() {
let result = 0
let prizeCount = this.prizeList.length
let prizeClip = 360 / prizeCount
let diffNum = 90 / prizeClip
if (this.pointerPosition === 'edge' || this.rotateType === 'pointer') {
result = -(prizeClip * diffNum)
} else {
result = -(prizeClip * diffNum + prizeClip / 2)
}
return result
},
actionAngle() {
return 0
},
// 外圆的半径
outsideRadius() {
return this.higtCanvasSize / 2
},
// 内圆的半径
insideRadius() {
return 20 * systemInfo.pixelRatio
},
// 文字距离边缘的距离
textRadius() {
return this.strMarginPxOutside * systemInfo.pixelRatio || (this.higtFontSize / 2)
},
// 根据画板的宽度计算奖品文字与中心点的距离
textDistance() {
const textZeroY = Math.round(this.outsideRadius - (this.insideRadius / 2))
return textZeroY - this.textRadius
}
},
watch: {
// 监听获奖序号的变动
prizeIndex(newVal, oldVal) {
if (newVal > -1) {
this.targetIndex = newVal
this.onRotateStart()
} else {
console.info('旋转结束,prizeIndex 已重置')
}
}
},
methods: {
// 开始旋转
onRotateStart() {
if (this.isRotate) return
this.isRotate = true
// 奖品总数
let prizeCount = this.prizeList.length
let baseAngle = 360 / prizeCount
let angles = 0
if (this.rotateType === 'pointer') {
if (this.targetActionAngle === 0) {
// 第一次旋转
angles = (this.targetIndex - this.stayIndex) * baseAngle + baseAngle / 2 - this.actionAngle
} else {
// 后续旋转
// 后续继续旋转 就只需要计算停留的位置与目标位置的角度
angles = (this.targetIndex - this.stayIndex) * baseAngle
}
// 更新目前序号
this.stayIndex = this.targetIndex
// 转 8 圈,圈数越多,转的越快
this.targetActionAngle += angles + 360 * this.ringCount
console.log('targetActionAngle', this.targetActionAngle)
} else {
if (this.targetAngle === 0) {
// 第一次旋转
// 因为第一个奖品是从0°开始的,即水平向右方向
// 第一次旋转角度 = 270度 - (停留的序号-目标序号) * 每个奖品区间角度 - 每个奖品区间角度的一半 - canvas自身旋转的度数
angles = (270 - (this.targetIndex - this.stayIndex) * baseAngle - baseAngle / 2) - this.canvasAngle
} else {
// 后续旋转
// 后续继续旋转 就只需要计算停留的位置与目标位置的角度
angles = -(this.targetIndex - this.stayIndex) * baseAngle
}
// 更新目前序号
this.stayIndex = this.targetIndex
// 转 8 圈,圈数越多,转的越快
this.targetAngle += angles + 360 * this.ringCount
}
// 计算转盘结束的时间,预加一些延迟确保转盘停止后触发结束事件
let endTime = this.transitionDuration * 1000 + 100
let endTimer = setTimeout(() => {
clearTimeout(endTimer)
endTimer = null
this.isRotate = false
this.$emit('draw-end')
}, endTime)
let resetPrizeTimer = setTimeout(() => {
clearTimeout(resetPrizeTimer)
resetPrizeTimer = null
// 每次抽奖结束后都要重置父级组件的 prizeIndex
this.$emit('reset-index')
}, endTime + 50)
},
// 点击 开始抽奖 按钮
handleActionStart() {
if (!this.lotteryImg) return
if (this.isRotate) return
this.$emit('draw-start')
},
// 渲染转盘
async onCreateCanvas() {
// 获取 canvas 画布
const canvasId = this.canvasId
const ctx = uni.createCanvasContext(canvasId, this)
// canvas 的宽高
let canvasW = this.higtCanvasSize
let canvasH = this.higtCanvasSize
// 根据奖品个数计算 角度
let prizeCount = this.prizeList.length
let baseAngle = Math.PI * 2 / prizeCount
// 设置字体
ctx.setFontSize(this.higtFontSize)
// 注意,开始画的位置是从0°角的位置开始画的。也就是水平向右的方向。
// 画具体内容
for (let i = 0; i < prizeCount; i++) {
let prizeItem = this.prizeList[i]
// 当前角度
let angle = i * baseAngle
// 保存当前画布的状态
ctx.save()
// x => 圆弧对应的圆心横坐标 x
// y => 圆弧对应的圆心横坐标 y
// radius => 圆弧的半径大小
// startAngle => 圆弧开始的角度,单位是弧度
// endAngle => 圆弧结束的角度,单位是弧度
// anticlockwise(可选) => 绘制方向,true 为逆时针,false 为顺时针
ctx.beginPath()
// 外圆
ctx.arc(canvasW * 0.5, canvasH * 0.5, this.outsideRadius, angle, angle + baseAngle, false)
// 内圆
ctx.arc(canvasW * 0.5, canvasH * 0.5, this.insideRadius, angle + baseAngle, angle, true)
// 每个奖品区块背景填充颜色
if (this.colors.length === 2) {
ctx.setFillStyle(this.colors[i % 2])
} else {
ctx.setFillStyle(this.colors[i])
}
// 填充颜色
ctx.fill()
// 设置文字颜色
if (this.strFontColors.length === 1) {
ctx.setFillStyle(this.strFontColors[0])
} else if (this.strFontColors.length === 2) {
ctx.setFillStyle(this.strFontColors[i % 2])
} else {
ctx.setFillStyle(this.strFontColors[i])
}
// 开启描边
if (this.stroked) {
// 设置描边颜色
ctx.setStrokeStyle(`${this.strokeColor}`)
// 描边
ctx.stroke()
}
// 开始绘制奖品内容
// 重新映射画布上的 (0,0) 位置
let translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * this.textDistance
let translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * this.textDistance
ctx.translate(translateX, translateY)
// 绘制奖品名称
let rewardName = this.strLimit(prizeItem.prizeName)
// rotate方法旋转当前的绘图,因为文字是和当前扇形中心线垂直的
ctx.rotate(angle + (baseAngle / 2) + (Math.PI / 2))
// 设置文本位置并处理换行
if (this.strDirection === 'horizontal') {
// 是否需要换行
if (rewardName && this.prizeNameDrawed) {
let realLen = clacTextLen(rewardName).realLen
let isLineBreak = realLen > this.strLineLen
if (isLineBreak) {
// 获得多行文本数组
let firstText = ''
let lastText = ''
let firstCount = 0
for (let j = 0; j < rewardName.length; j++) {
firstCount += clacTextLen(rewardName[j]).byteLen
if (firstCount <= (this.strLineLen * 2)) {
firstText += rewardName[j]
} else {
lastText += rewardName[j]
}
}
rewardName = firstText + ',' + lastText
let rewardNames = rewardName.split(',')
// 循环文本数组,计算每一行的文本宽度
for (let j = 0; j < rewardNames.length; j++) {
if (ctx.measureText && ctx.measureText(rewardNames[j]).width > 0) {
// 文本的宽度信息
let tempStrSize = ctx.measureText(rewardNames[j])
let tempStrWidth = -(tempStrSize.width / 2).toFixed(2)
ctx.fillText(rewardNames[j], tempStrWidth, j * this.higtHeightMultiple)
} else {
this.measureText = rewardNames[j]
// 等待页面重新渲染
await this.$nextTick()
let textWidth = await this.getTextWidth()
let tempStrWidth = -(textWidth / 2).toFixed(2)
ctx.fillText(rewardNames[j], tempStrWidth, j * this.higtHeightMultiple)
// console.log(rewardNames[j], textWidth, j)
}
}
} else {
if (ctx.measureText && ctx.measureText(rewardName).width > 0) {
// 文本的宽度信息
let tempStrSize = ctx.measureText(rewardName)
let tempStrWidth = -(tempStrSize.width / 2).toFixed(2)
ctx.fillText(rewardName, tempStrWidth, 0)
} else {
this.measureText = rewardName
// 等待页面重新渲染
await this.$nextTick()
let textWidth = await this.getTextWidth()
let tempStrWidth = -(textWidth / 2).toFixed(2)
ctx.fillText(rewardName, tempStrWidth, 0)
}
}
}
} else {
let rewardNames = rewardName.split('')
for (let j = 0; j < rewardNames.length; j++) {
if (ctx.measureText && ctx.measureText(rewardNames[j]).width > 0) {
// 文本的宽度信息
let tempStrSize = ctx.measureText(rewardNames[j])
let tempStrWidth = -(tempStrSize.width / 2).toFixed(2)
ctx.fillText(rewardNames[j], tempStrWidth, j * this.higtHeightMultiple)
} else {
this.measureText = rewardNames[j]
// 等待页面重新渲染
await this.$nextTick()
let textWidth = await this.getTextWidth()
let tempStrWidth = -(textWidth / 2).toFixed(2)
ctx.fillText(rewardNames[j], tempStrWidth, j * this.higtHeightMultiple)
// console.log(rewardNames[j], textWidth, i)
}
}
}
// 绘制奖品图片,文字竖向展示时,不支持图片展示
if (this.imgDrawed && prizeItem.prizeImage && this.strDirection !== 'vertical') {
// App-Android平台 系统 webview 更新到 Chrome84+ 后 canvas 组件绘制本地图像 uni.canvasToTempFilePath 会报错
// 统一将图片处理成 base64
// https://ask.dcloud.net.cn/question/103303
let reg = /^(https|http)/g
// 处理远程图片
if (reg.test(prizeItem.prizeImage)) {
let platformTips = ''
// #ifdef APP-PLUS
platformTips = ''
// #endif
// #ifdef MP
platformTips = '需要处理好下载域名的白名单问题,'
// #endif
// #ifdef H5
platformTips = '需要处理好跨域问题,'
// #endif
console.warn(`###当前数据列表中的奖品图片为网络图片,${platformTips}开始尝试下载图片...###`)
let res = await downloadFile(prizeItem.prizeImage)
console.log('处理远程图片', res)
if (res.ok) {
let tempFilePath = res.tempFilePath
// #ifndef MP
prizeItem.prizeImage = await pathToBase64(tempFilePath)
// #endif
// #ifdef MP
prizeItem.prizeImage = tempFilePath
// #endif
} else {
this.handlePrizeImgSuc({
ok: false,
data: res.data,
msg: res.msg
})
}
} else {
console.log('处理非远程图片', prizeItem.prizeImage)
// #ifndef MP
if (prizeItem.prizeImage.indexOf(';base64,') === -1) {
prizeItem.prizeImage = await pathToBase64(prizeItem.prizeImage)
}
// #endif
}
let prizeImageX = -(this.imgPxWidth * systemInfo.pixelRatio / 2)
let prizeImageY = this.imgMarginPxStr * systemInfo.pixelRatio
let prizeImageW = this.imgPxWidth * systemInfo.pixelRatio
let prizeImageH = this.imgPxHeight * systemInfo.pixelRatio
ctx.drawImage(prizeItem.prizeImage, prizeImageX, prizeImageY, prizeImageW, prizeImageH)
}
ctx.restore()
}
// 保存绘图并导出图片
ctx.draw(true, () => {
let drawTimer = setTimeout(() => {
clearTimeout(drawTimer)
drawTimer = null
// #ifdef MP-ALIPAY
ctx.toTempFilePath({
destWidth: this.higtCanvasSize,
destHeight: this.higtCanvasSize,
success: (res) => {
// console.log(res.apFilePath)
this.handlePrizeImg({
ok: true,
data: res.apFilePath,
msg: '画布导出生成图片成功'
})
},
fail: (err) => {
this.handlePrizeImg({
ok: false,
data: err,
msg: '画布导出生成图片失败'
})
}
})
// #endif
// #ifndef MP-ALIPAY
uni.canvasToTempFilePath({
canvasId: this.canvasId,
success: (res) => {
// 在 H5 平台下,tempFilePath 为 base64
// console.log(res.tempFilePath)
this.handlePrizeImg({
ok: true,
data: res.tempFilePath,
msg: '画布导出生成图片成功'
})
},
fail: (err) => {
this.handlePrizeImg({
ok: false,
data: err,
msg: '画布导出生成图片失败'
})
}
}, this)
// #endif
}, 500)
})
},
// 处理导出的图片
handlePrizeImg(res) {
if (res.ok) {
let data = res.data
if (!this.canvasCached) {
this.lotteryImg = data
this.handlePrizeImgSuc(res)
return
}
// #ifndef H5
if (this.isCacheImg) {
uni.getSavedFileList({
success: (sucRes) => {
let fileList = sucRes.fileList
// console.log('getSavedFileList Cached', fileList)
let cached = false
if (fileList.length) {
for (let i = 0; i < fileList.length; i++) {
let item = fileList[i]
if (item.filePath === data) {
cached = true
this.lotteryImg = data
console.info('经查,本地缓存中存在的转盘图可用,本次将不再绘制转盘')
this.handlePrizeImgSuc(res)
break
}
}
}
if (!cached) {
console.info('经查,本地缓存中存在的转盘图不可用,需要重新初始化转盘绘制')
this.initCanvasDraw()
}
},
fail: (err) => {
this.initCanvasDraw()
}
})
} else {
uni.saveFile({
tempFilePath: data,
success: (sucRes) => {
let filePath = sucRes.savedFilePath
// console.log('saveFile', filePath)
setStore(`${this.canvasId}LotteryImg`, filePath)
this.lotteryImg = filePath
this.handlePrizeImgSuc({
ok: true,
data: filePath,
msg: '画布导出生成图片成功'
})
},
fail: (err) => {
this.handlePrizeImg({
ok: false,
data: err,
msg: '画布导出生成图片失败'
})
}
})
}
// #endif
// #ifdef H5
setStore(`${this.canvasId}LotteryImg`, data)
this.lotteryImg = data
this.handlePrizeImgSuc(res)
// console info
let consoleText = this.isCacheImg ? '缓存' : '导出'
console.info(`当前为 H5 端,使用${consoleText}中的 base64 图`)
// #endif
} else {
console.error('处理导出的图片失败', res)
uni.hideLoading()
// #ifdef H5
console.error('###当前为 H5 端,下载网络图片需要后端配置允许跨域###')
// #endif
// #ifdef MP
console.error('###当前为小程序端,下载网络图片需要配置域名白名单###')
// #endif
}
},
// 处理图片完成
handlePrizeImgSuc(res) {
uni.hideLoading()
this.$emit('finish', {
ok: res.ok,
data: res.data,
msg: res.ok ? this.successMsg : this.failMsg
})
this.almostLotteryTip = res.ok ? this.successMsg : this.failMsg
},
// 兼容 app 端不支持 ctx.measureText
// 已知问题:初始绘制时,低端安卓机 平均耗时 2s
// hbx 2.8.12+ 已在 app 端支持
getTextWidth() {
console.warn('正在采用兼容方式获取文本的 size 信息,虽然没有任何问题,如果可以,请将此 systemInfo 及 hbx 版本号 反馈给作者', systemInfo)
let query = uni.createSelectorQuery().in(this)
let nodesRef = query.select('.almost-lottery__measureText')
return new Promise((resolve, reject) => {
nodesRef.fields({
size: true,
}, (res) => {
resolve(res.width)
}).exec()
})
},
// 处理文字溢出
strLimit(value) {
let maxLength = this.strMaxLen
if (!value || !maxLength) return value
return clacTextLen(value).realLen > maxLength ? value.slice(0, maxLength - 1) + '..' : value
},
// 检查本地缓存中是否存在转盘图
checkCacheImg() {
console.log('检查本地缓存中是否存在转盘图')
// 检查是否已有缓存的转盘图
// 检查是否与本次奖品数据相同
this.oldLotteryImg = getStore(`${this.canvasId}LotteryImg`)
let oldPrizeList = getStore(`${this.canvasId}PrizeList`)
let newPrizeList = JSON.stringify(this.prizeList)
if (this.oldLotteryImg) {
if (oldPrizeList === newPrizeList) {
console.log(`经查,本地缓存中存在转盘图 => ${this.oldLotteryImg}`)
this.isCacheImg = true
console.log('需要继续判断这张缓存图是否可用')
this.handlePrizeImg({
ok: true,
data: this.oldLotteryImg,
msg: '画布导出生成图片成功'
})
return
}
}
console.log('经查,本地缓存中不存在转盘图')
this.initCanvasDraw()
},
// 初始化绘制
initCanvasDraw() {
console.log('开始初始化转盘绘制')
this.isCacheImg = false
this.lotteryImg = ''
clearStore(`${this.canvasId}LotteryImg`)
setStore(`${this.canvasId}PrizeList`, this.prizeList)
this.onCreateCanvas()
},
// 预处理初始化
async beforeInit() {
// 处理 rpx 自适应尺寸
let lotterySize = await new Promise((resolve) => {
uni.createSelectorQuery().in(this).select('.almost-lottery__wrap').boundingClientRect((
rects) => {
resolve(rects)
// console.log('处理 lottery rpx 的自适应', rects)
}).exec()
})
let actionSize = await new Promise((resolve) => {
uni.createSelectorQuery().in(this).select('.lottery-action').boundingClientRect((
rects) => {
resolve(rects)
// console.log('处理 action rpx 的自适应', rects)
}).exec()
})
let strMarginSize = await new Promise((resolve) => {
uni.createSelectorQuery().in(this).select('.str-margin-outside').boundingClientRect((
rects) => {
resolve(rects)
// console.log('处理 str-margin-outside rpx 的自适应', rects)
}).exec()
})
let imgMarginStr = await new Promise((resolve) => {
uni.createSelectorQuery().in(this).select('.img-margin-str').boundingClientRect((
rects) => {
resolve(rects)
// console.log('处理 img-margin-str rpx 的自适应', rects)
}).exec()
})
let imgSize = await new Promise((resolve) => {
uni.createSelectorQuery().in(this).select('.img-size').boundingClientRect((rects) => {
resolve(rects)
// console.log('处理 img-size rpx 的自适应', rects)
}).exec()
})
this.lotteryPxSize = Math.floor(lotterySize.width)
this.actionPxSize = Math.floor(actionSize.width)
this.canvasPxSize = this.lotteryPxSize - Math.floor(actionSize.left) + Math.floor(lotterySize.left)
this.strMarginPxOutside = Math.floor(strMarginSize.left) - Math.floor(lotterySize.left)
this.imgMarginPxStr = Math.floor(imgMarginStr.left) - Math.floor(lotterySize.left)
this.imgPxWidth = Math.floor(imgSize.width)
this.imgPxHeight = Math.floor(imgSize.height)
let stoTimer = setTimeout(() => {
clearTimeout(stoTimer)
stoTimer = null
// 判断画板是否设置缓存
if (this.canvasCached) {
this.checkCacheImg()
} else {
this.initCanvasDraw()
}
this.transitionDuration = this.duration
}, 50)
}
},
mounted() {
this.$nextTick(() => {
let stoTimer = setTimeout(() => {
clearTimeout(stoTimer)
stoTimer = null
this.beforeInit()
}, 50)
})
}
}
</script>
<style lang="scss" scoped>
.almost-lottery {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.almost-lottery__wrap {
position: relative;
// background-color: red;
}
.lottery-action,
.str-margin-outside,
.img-margin-str,
.img-size {
position: absolute;
left: 0;
top: 0;
z-index: -1;
// background-color: blue;
}
.almost-lottery__wrap {
display: flex;
justify-content: center;
align-items: center;
}
.almost-lottery__action,
.almost-lottery__bg,
.almost-lottery__canvas {
position: absolute;
}
.almost-lottery__canvas {
left: -9999px;
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
}
.almost-lottery__canvas-img,
.almost-lottery__action-bg {
display: block;
transition: transform cubic-bezier(.34, .12, .05, .95);
}
.almost-lottery__tip {
color: #FFFFFF;
font-size: 24rpx;
text-align: center;
}
.almost-lottery__measureText {
position: absolute;
left: 0;
top: 0;
white-space: nowrap;
font-size: 12px;
opacity: 0;
}
</style>