<template>
<div class="component">
<div class="bg">
<div class="lotterybg" :style="`background: url(`+canvasUrl+`)center center / cover no-repeat`">
<canvas
:style="canvasStyle"
id="myCanvas"
></canvas>
</div>
</div>
<div v-for="(item,index) in prizeList" :key="index">
<img
:src="item.picUrl"
class="imgSrc"
/>
</div>
<!-- <img src="https://www.17sucai.com/preview/5730/2018-03-05/2/images/an_go.png" id="start" @click="play" /> -->
<div id="award" :style="awardStyle"><span id="awardBall" :style="`background: url(`+awardImgUrl+`)center center / cover no-repeat`">
</span></div>
</div>
</template>
<script src="./js/point"></script>
// <script src="./js/hidpi-canvas.min"></script>
<script>
import Ball from './js/point'
export default {
name: 'twistedEgg',
props: {
canvasUrl: {
editor: {
type: 'image',
label: '扭蛋机背景图',
},
type: String,
default: 'https://vueweb.oss-cn-qingdao.aliyuncs.com/vueweb/resource/ymm_1632812102882.png',
},
isData: {
type: Boolean,
default: false,
editor: {
type: 'boolean',
label: '是否数据源'
}
},
dataScoped: {
type: String,
default: '',
editor: {
type: 'string',
label: '数据源名称(dataHub)'
}
},
imgUrl: {
type: Array,
default () {
return [
{
url: 'https://vueweb.oss-cn-qingdao.aliyuncs.com/vueweb/resource/ymm_1632810357807.png'
}
]
},
editor: {
ignore: true
}
},
canvasWidth: {
default: 300,
type: Number,
editor: {
type: 'number',
label: '扭蛋区域的宽',
}
},
canvasHeight: {
default: 292,
type: Number,
editor: {
type: 'number',
label: '扭蛋区域的高',
}
},
canvasTop: {
default: -26,
type: Number,
editor: {
type: 'number',
label: '扭蛋区域距离顶部的距离',
}
},
canvasLeft: {
default: 26,
type: Number,
editor: {
type: 'number',
label: '扭蛋区域距离左侧的值',
}
},
canvasBorderRadius: {
default: '0',
type: String,
editor: {
type: 'string',
label: '扭蛋区域的圆角',
}
},
canvasPadding: {
default: 0,
type: Number,
editor: {
type: 'number',
label: '扭蛋区域内边距',
}
},
ballWidth: {
default: 65,
type: Number,
editor: {
type: 'number',
label: '扭蛋宽',
}
},
ballHeight: {
default: 66,
type: Number,
editor: {
type: 'number',
label: '扭蛋高',
}
},
awardPosition: {
type: String,
default: ' 50px;height: 50px;top: 380px;left:10px',
editor: {
type: 'string',
label: '出口位置'
}
},
functionPop: {
type: String,
editor: {
type: 'string',
label: '抽奖完成奖品弹出框方法:',
},
},
},
computed: {
// 数据源列表
prizeList () {
if (this.isData) {
if (!this.isEmpty(this.$parent.DataHub) && !this.isEmpty(this.$parent.DataHub[this.dataScoped])) {
return this.$parent.DataHub[this.dataScoped]
} else {
return []
}
} else {
return this.fakeDataSource
}
},
canvasStyle () {
let style = {
top: this.canvasTop + 'px',
left: this.canvasLeft + 'px',
borderRadius: this.canvasBorderRadius,
padding: this.canvasPadding + 'px',
}
return style
},
awardStyle () {
return `${this.awardPosition};color:${this.itemTextColor};`
},
},
data () {
return {
canvas: '',
ctx: '',
ballList: [],
ballNum: '',
awardList: [],
scale: 1,
fakeDataSource: [
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/5.png',
},
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/7.png',
},
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/6.png',
}, {
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/5.png',
},
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/5.png',
},
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/7.png',
},
{
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/6.png',
}, {
'picUrl': 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/5.png',
},
],
awardImgUrl: 'https://vueweb.oss-cn-qingdao.aliyuncs.com/platform/5.png',
}
},
editorMethods: {
},
watch: {
},
mounted () {
this.demo()
},
methods: {
demo () {
this.canvas = document.getElementById('myCanvas')
this.scale = window.devicePixelRatio
this.canvas.width = this.canvasWidth * this.scale
this.canvas.height = this.canvasHeight * this.scale
this.canvas.style.width = this.canvas.width / this.scale + 'px'
this.canvas.style.height = this.canvas.height / this.scale + 'px'
this.ctx = this.canvas.getContext('2d')
this.ballList = Array.from(document.getElementsByClassName('imgSrc'))
this.ballNum = this.ballList.length // 扭蛋机里面的小球数
for (let i = 0; i < this.ballNum; i++) { // 随机生成各色小球
this.awardList[i] = new Ball(this.canvas, this.ballList[i], this.ballWidth, this.ballHeight, i) // 新建小球对象
}
},
isEmpty (str) {
if (typeof str == 'undefined' || str == null || str == '') {
return true
} else {
return false
}
},
play () {
var award = document.getElementById('awardBall')
award.removeAttribute('class', 'dropBall')
if (this.awardList.length === 0) { // 奖池中没有小球
this.init()
} else {
window.clearInterval(this.timer) // 清除计时器
this.timer = setInterval(() => {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) // 清空画布
for (let i = 0; i < this.awardList.length; i++) {
this.awardList[i].run(this.ctx, this.canvas, this.ballWidth, this.ballHeight)
} // 使小球运动
}, 15)
this.clear()
}
},
init () { // 初始化
for (let i = 0; i < this.ballNum; i++) { // 随机生成各色小球
let index = Math.floor(4 * Math.random())
this.awardList[i] = new Ball(this.canvas, index, this.ballList[index]) // 新建小球对象
}
window.clearInterval(this.timer) // 清除计时器
this.timer = setInterval(() => {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) // 清空画布
for (let i = 0; i < this.awardList.length; i++) {
this.awardList[i].run(this.ctx, this.canvas, this.ballWidth, this.ballHeight)
} // 使小球运动
}, 100)
this.clear()
},
clear () {
var award = document.getElementById('awardBall')
document.getElementById('awardBall').style.display = 'inline'
setTimeout(() => {
window.clearInterval(this.timer) // 清除计时器
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) // 清空画布
for (let i = 0; i < this.ballNum; i++) { // 随机生成各色小球
this.awardList[i] = new Ball(this.canvas, this.ballList[i], this.ballWidth, this.ballHeight, i) // 新建小球对象
}
award.setAttribute('class', 'dropBall')
}, 1500)
let that = this
setTimeout(() => {
if (!that.functionPop) {
return
}
eval(`that.${that.functionPop}()`)
}, 1600)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" type="text/stylus" scoped>
.component {
width: 100%;
height: 100%;
}
.bg {
position: absolute;
width: 100%;
height: 100%;
}
.lotterybg {
position: absolute;
background-size: contain;
overflow: visible;
width: 100%;
height: 100%;
}
#myCanvas {
position: absolute;
border: none;
// background-color: rgb(118, 185, 185);
}
#start {
position: absolute;
z-index: 3;
width: 50px;
margin-top: 370px;
margin-left: 50%;
}
.imgSrc {
display:none;
position: absolute;
}
#award {
position: absolute;
border: none;
}
.awardImgUrl{
width :100%;
height :100%
}
#awardBall{
display :none
}
.dropBall {
content: "";position: absolute;left: 0;top: 0;
width: 100%;height: 100%;
display: block;
background-size: contain;
animation: drop 1s ease-out forwards;
-webkit-animation: drop 1s ease-out forwards;
}
@keyframes drop {
0% {
transform: scale(0.7);
}
50% {
transform: scale(1);
}
51% {
transform: translateY(0px);
}
100% {
transform: translateY(10px);
}
}
@-webkit-keyframes drop {
0% {
-webkit-transform: scale(0.7);
}
50% {
-webkit-transform: scale(1);
}
51% {
-webkit-transform: translateY(0px);
}
100% {
-webkit-transform: translateY(10px);
}
}
</style>
point.js
class Ball {
constructor (canvas, img, width, height, index) {
//scale 是为了解决移动端图片模糊问题 有点乱,后期再整理
this.scale = window.devicePixelRatio
//小球随机位置设置到容器下半部分,不至于悬浮在上面
this.x = this.rand(canvas.width - width * this.scale)
this.y = this.rand(canvas.height - height * this.scale - (canvas.height / 2)) + canvas.height / 2
this.img = img
this.index = index
if (width) {
canvas.getContext('2d').drawImage(this.img, this.x, this.y, width * this.scale, height * this.scale)
}
this.init()
}
init () {
do {
this.speedX = this.rand(20) - 10
} while (this.speedX < 5)
do {
this.speedY = this.rand(20) - 10
} while (this.speedY < 5)
}
rand (num) {
return Math.random() * num
}
run (ctx, canvas, width, height) {
this.x += this.speedX
this.y += this.speedY
if (this.x > canvas.width - width * this.scale) {
this.speedX = -this.speedX
}
if (this.x < 0) {
this.speedX = Math.abs(this.speedX)
}
if (this.y > canvas.height - height * this.scale) {
this.speedY = -this.speedY
}
if (this.y < 0) {
this.speedY = Math.abs(this.speedY)
}
canvas.getContext('2d').drawImage(this.img, this.x, this.y, width * this.scale, height * this.scale)
}
}
export default Ball