319 lines
6.4 KiB
Vue
319 lines
6.4 KiB
Vue
<template>
|
|
<view>
|
|
<view :id="canvasId" class="box-ly-b" style="position: relative;">
|
|
<view :style="{width: width+'rpx', height : height+'rpx'}">
|
|
|
|
<view class="blow" v-if="is_show" :style="{width: width+'rpx', height : height+'rpx'}" style="position: absolute;">
|
|
<view class="box-ly-b" :style="{background: themeColor }">
|
|
<view class="result" :style="[{'font-size':txtFontSize+'rpx'},{color: txtColor }]">
|
|
<text>{{result_txt}}</text>
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
<canvas style="position: absolute;" :style="{width: width+'rpx', height : height+'rpx'}" :disable-scroll="true"
|
|
@touchstart="touchstart" @touchend="touchend" @touchmove="touchmove" :canvas-id="canvasId"></canvas>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
let ctx = null;
|
|
export default {
|
|
props: {
|
|
is_show: { //防止画布画好前闪烁
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
|
|
result_txt: {
|
|
type: String,
|
|
default: '结果',
|
|
},
|
|
|
|
themeColor: {
|
|
type: String,
|
|
default: '#33CCCC',
|
|
},
|
|
txtColor: {
|
|
type: String,
|
|
default: '#FFFFFF',
|
|
},
|
|
txtFontSize: {
|
|
type: Number,
|
|
default: 50,
|
|
},
|
|
canvasId: {
|
|
type: String,
|
|
default: 'blow',
|
|
},
|
|
height: {
|
|
type: Number,
|
|
default: 200
|
|
},
|
|
width: {
|
|
type: Number,
|
|
default: 300
|
|
},
|
|
percentage: { //刮开百分之多少的时候开奖
|
|
type: Number,
|
|
default: 45
|
|
},
|
|
touchSize: { //触摸画笔大小
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
fillColor: { //未刮开图层时的填充色
|
|
type: String,
|
|
default: '#ddd'
|
|
},
|
|
watermark: { //水印文字
|
|
type: String,
|
|
default: '刮一刮'
|
|
},
|
|
watermarkColor: { //水印文字颜色
|
|
type: String,
|
|
default: '#c5c5c5'
|
|
},
|
|
watermarkSize: { //水印文字大小
|
|
type: Number,
|
|
default: 14
|
|
},
|
|
title: { //提示文字
|
|
type: String,
|
|
default: '刮一刮开奖'
|
|
},
|
|
titleColor: { //提示文字颜色
|
|
type: String,
|
|
default: '#888'
|
|
},
|
|
titleSize: { //提示文字大小
|
|
type: Number,
|
|
default: 24
|
|
},
|
|
disabled: { //是否禁止刮卡
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
init_show: { //是否初始化
|
|
type : Boolean ,
|
|
default : false
|
|
},
|
|
|
|
},
|
|
data() {
|
|
return {
|
|
|
|
startX: null,
|
|
startY: null,
|
|
computing: false,
|
|
complete: false,
|
|
reset: false,
|
|
ready: false,
|
|
storePoints: []
|
|
};
|
|
},
|
|
watch:{
|
|
init_show(e){
|
|
if(e){
|
|
this.initBlow();
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
ctx = uni.createCanvasContext(this.canvasId, this);
|
|
this.initBlow();
|
|
},
|
|
methods: {
|
|
|
|
|
|
|
|
initBlow: function() {
|
|
this.computing = false;
|
|
this.complete = false;
|
|
this.reset = false;
|
|
this.ready = false;
|
|
ctx.clearRect(0, 0, this.width, this.height);
|
|
//绘制画布
|
|
ctx.setFillStyle(this.fillColor);
|
|
ctx.fillRect(0, 0, this.width, this.height);
|
|
this.ready = true;
|
|
//绘制文字水印
|
|
this.fillWatermark();
|
|
//绘制标题
|
|
this.fillTitle();
|
|
ctx.draw();
|
|
|
|
setTimeout(res => {
|
|
let data = {
|
|
|
|
};
|
|
this.$emit('init', data);
|
|
}, 50)
|
|
|
|
},
|
|
|
|
/**
|
|
* 绘制文字水印
|
|
*/
|
|
fillWatermark: function(e) {
|
|
if (!this.watermark) {
|
|
return;
|
|
}
|
|
var width = this.watermark.length * this.watermarkSize;
|
|
ctx.save();
|
|
ctx.rotate(-10 * Math.PI / 180);
|
|
let x = 0;
|
|
let y = 0;
|
|
let i = 0;
|
|
while ((x <= this.width * 5 || y <= this.height * 5) && i < 300) {
|
|
ctx.setFillStyle(this.watermarkColor);
|
|
ctx.setFontSize(this.watermarkSize);
|
|
ctx.fillText(this.watermark, x, y);
|
|
x += width + width * 1.6;
|
|
if (x > this.width && y <= this.height) {
|
|
x = -Math.random() * 100;
|
|
y += this.watermarkSize * 3;
|
|
}
|
|
i++;
|
|
}
|
|
ctx.restore();
|
|
},
|
|
|
|
/**
|
|
* 绘制标题
|
|
*/
|
|
fillTitle: function(e) {
|
|
if (!this.title) {
|
|
return;
|
|
}
|
|
ctx.setTextAlign("center");
|
|
ctx.setTextBaseline("middle");
|
|
ctx.setFillStyle(this.titleColor);
|
|
ctx.setFontSize(this.titleSize);
|
|
ctx.fillText(this.title, this.width / 2 / 2, this.height / 2 / 2); //因单位是rpx故再除以2
|
|
},
|
|
|
|
touchstart: function(e) {
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
this.startX = e.touches[0].x;
|
|
this.startY = e.touches[0].y;
|
|
},
|
|
|
|
touchend: function(e) {
|
|
this.getFilledPercentage();
|
|
},
|
|
|
|
touchmove: function(e) {
|
|
if (this.complete || this.disabled) {
|
|
return;
|
|
}
|
|
// ctx.globalCompositeOperation = 'destination-out';
|
|
ctx.moveTo(this.startX, this.startY);
|
|
// ctx.beginPath();
|
|
// ctx.arc(this.startX, this.startY, 20, 0, Math.PI * 20);
|
|
// ctx.fill();
|
|
ctx.clearRect(this.startX, this.startY, this.touchSize, this.touchSize);
|
|
ctx.draw(true);
|
|
//记录移动点位
|
|
this.startX = e.touches[0].x;
|
|
this.startY = e.touches[0].y;
|
|
},
|
|
|
|
getFilledPercentage: function(e) {
|
|
if (this.computing) {
|
|
return;
|
|
}
|
|
this.computing = true;
|
|
uni.canvasGetImageData({
|
|
canvasId: this.canvasId,
|
|
x: 0,
|
|
y: 0,
|
|
width: this.width,
|
|
height: this.height,
|
|
success: (res) => {
|
|
let pixels = res.data;
|
|
let transPixels = [];
|
|
for (let i = 0; i < pixels.length; i += 4) {
|
|
if (pixels[i + 3] < 128) {
|
|
transPixels.push(pixels[i + 3]);
|
|
}
|
|
}
|
|
//var percent = (transPixels.length / (pixels.length / 4) * 100).toFixed(2);
|
|
var percent = (transPixels.length / (pixels.length/2) * 100).toFixed(2);
|
|
if (percent >= this.percentage) {
|
|
this.success();
|
|
}
|
|
this.computing = false;
|
|
console.log(percent)
|
|
},
|
|
fail: function(e) {
|
|
console.log(e);
|
|
},
|
|
}, this);
|
|
},
|
|
|
|
success: function(e) {
|
|
this.complete = true;
|
|
if (this.reset) {
|
|
return;
|
|
}
|
|
this.reset = true;
|
|
ctx.moveTo(0, 0);
|
|
ctx.clearRect(0, 0, this.width, this.height);
|
|
ctx.stroke();
|
|
ctx.draw(true);
|
|
this.$emit("complete", {});
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.blow {
|
|
|
|
background-size: contain;
|
|
margin: 0rpx auto;
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
.box-ly-b {
|
|
width: 100%;
|
|
height: 100%;
|
|
// background: #aaaa7f;
|
|
border-radius: 10rpx;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
.result {
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
// font-size: 50rpx;
|
|
// color: #FFFFFF;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
.box-ly-b {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
}
|
|
</style>
|