初始化
This commit is contained in:
268
uni_modules/mumu-camera/components/mumu-camera/mumu-camera.vue
Normal file
268
uni_modules/mumu-camera/components/mumu-camera/mumu-camera.vue
Normal file
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="canvasBox" v-show='isUse'>
|
||||
<view class="trachBox" :style="{backgroundColor: !trackStatus ?'aliceblue' : 'khaki'}" @click='handlerTrach'
|
||||
v-if='isUseTorch'>
|
||||
<img src="./track.svg" class='trach'>
|
||||
</view>
|
||||
<view class="shutterBox" @click='hanlderShutter' hover-class="avtive">
|
||||
<view class="shutter"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="error" v-show='!isUse'>
|
||||
<view class="on1">相机权限被拒绝,请尝试如下操作:</view>
|
||||
<view>· 刷新页面后重试;</view>
|
||||
<view>· 在系统中检测当前App或浏览器的相机权限是否被禁用;</view>
|
||||
<view>· 如果依然不能体验,建议在微信中打开链接;</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
exact: {
|
||||
type: String,
|
||||
default: 'environment' // environment 后摄像头 user 前摄像头
|
||||
},
|
||||
//水印
|
||||
watermark: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUse: false,
|
||||
|
||||
windowWidth: 0,
|
||||
windowHeight: 0,
|
||||
video: null,
|
||||
canvas: null,
|
||||
canvas2d: null,
|
||||
cameraCanvas: null,
|
||||
cameraCanvas2d: null,
|
||||
|
||||
|
||||
|
||||
// 闪光灯
|
||||
track: null,
|
||||
isUseTorch: false,
|
||||
trackStatus: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if(origin.indexOf('https') === -1) throw '请在 https 环境中使用本插件。'
|
||||
|
||||
this.windowWidth = document.documentElement.clientWidth || document.body.clientWidth
|
||||
this.windowHeight = document.documentElement.clientHeight || document.body.clientHeight
|
||||
this.$nextTick(() => {
|
||||
this.video = document.createElement('video')
|
||||
this.video.width = this.windowWidth
|
||||
this.video.height = this.windowHeight
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
this.canvas = canvas
|
||||
canvas.id = 'canvas'
|
||||
canvas.width = this.windowWidth
|
||||
canvas.height = this.windowHeight
|
||||
canvas.style = 'position: fixed;top: 0;left: 0;z-index:10;'
|
||||
this.canvas2d = canvas.getContext('2d')
|
||||
|
||||
// 设置当前宽高 满屏
|
||||
const canvasBox = document.querySelector('.canvasBox')
|
||||
canvasBox.append(this.video)
|
||||
canvasBox.append(canvas)
|
||||
canvasBox.style = `width:${this.windowWidth}px;height:${this.windowHeight}px;`
|
||||
|
||||
const cameraCanvas = document.createElement('canvas')
|
||||
this.cameraCanvas = cameraCanvas
|
||||
cameraCanvas.id = 'cameraCanvas'
|
||||
cameraCanvas.width = this.windowWidth
|
||||
cameraCanvas.height = this.windowHeight
|
||||
cameraCanvas.style = 'display:none;'
|
||||
canvasBox.append(canvas)
|
||||
this.cameraCanvas2d = cameraCanvas.getContext('2d')
|
||||
|
||||
this.openScan()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
openScan() {
|
||||
let width = this.transtion(this.windowHeight)
|
||||
let height = this.transtion(this.windowWidth)
|
||||
|
||||
const videoParam = {
|
||||
audio: false,
|
||||
video: {
|
||||
facingMode: { exact: this.exact },
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
navigator.mediaDevices.getUserMedia(videoParam).then((stream) => {
|
||||
this.isUse = true
|
||||
this.video.srcObject = stream
|
||||
this.video.setAttribute('playsinline', true)
|
||||
this.video.setAttribute('webkit-playsinline', true)
|
||||
this.video.play()
|
||||
this.makeWatermark(this.canvas2d)
|
||||
|
||||
this.track = stream.getVideoTracks()[0];
|
||||
setTimeout(() => {
|
||||
this.isUseTorch = this.track.getCapabilities().torch || null
|
||||
}, 500)
|
||||
}).catch((err) => {
|
||||
console.log('设备不支持', err);
|
||||
this.isUse = false
|
||||
})
|
||||
},
|
||||
|
||||
async makeWatermark(ctx2d) {
|
||||
if (this.watermark.length === 0) return
|
||||
for (let item of this.watermark) {
|
||||
switch (item.type) {
|
||||
case 'img':
|
||||
const [getImgErr, { path: imgPath }] = await uni.getImageInfo({
|
||||
src: item.url
|
||||
});
|
||||
if (getImgErr) throw item.url + '没有找到'
|
||||
const img = await this.getImg(imgPath)
|
||||
ctx2d.drawImage(img, item.x, item.y, item.w, item.h)
|
||||
|
||||
break;
|
||||
case 'text':
|
||||
const color = item.font_color || "#000"
|
||||
const fontSize = item.font_size || 16
|
||||
|
||||
ctx2d.fillStyle = color
|
||||
ctx2d.font = `${fontSize}px normal`
|
||||
ctx2d.fillText(item.text, item.x, item.y)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
getImg(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = path
|
||||
img.onload = (res) => {
|
||||
resolve(img)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
transtion(number) {
|
||||
return number * 2
|
||||
},
|
||||
|
||||
// 快门
|
||||
async hanlderShutter() {
|
||||
this.cameraCanvas2d.drawImage(this.video, 0, 0, this.windowWidth, this.windowHeight)
|
||||
await this.makeWatermark(this.cameraCanvas2d)
|
||||
const img = this.cameraCanvas.toDataURL('image/png')
|
||||
this.$emit('success', img)
|
||||
},
|
||||
|
||||
handlerTrach() {
|
||||
console.log(12312)
|
||||
this.trackStatus = !this.trackStatus
|
||||
this.track.applyConstraints({
|
||||
advanced: [{ torch: this.trackStatus }]
|
||||
})
|
||||
},
|
||||
|
||||
closeCamera() {
|
||||
if (this.video.srcObject) {
|
||||
this.video.srcObject.getTracks().forEach((track) => {
|
||||
track.stop()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
destroyed() {
|
||||
this.closeCamera()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.canvasBox {
|
||||
position: relative;
|
||||
|
||||
.shutterBox {
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
left: 50%;
|
||||
bottom: 100rpx;
|
||||
background-color: aliceblue;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 2rpx 4rpx 8rpx rgba(000, 000, 000, 0.3);
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
|
||||
.shutter {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border: 10rpx solid #333;
|
||||
border-radius: 100rpx;
|
||||
|
||||
|
||||
}
|
||||
|
||||
&.avtive::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: rgba(000, 000, 000, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.trachBox {
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
left: 30%;
|
||||
bottom: 100rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 100rpx;
|
||||
box-shadow: 2rpx 4rpx 8rpx rgba(000, 000, 000, 0.3);
|
||||
z-index: 30;
|
||||
|
||||
.trach {
|
||||
width: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #fff;
|
||||
padding: 40rpx;
|
||||
font-size: 24rpx;
|
||||
.on1 {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
1
uni_modules/mumu-camera/components/mumu-camera/track.svg
Normal file
1
uni_modules/mumu-camera/components/mumu-camera/track.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg t="1653986844275" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2276" width="48" height="48"><path d="M563.7 766.7H457c-9.3 0-16.8 7.5-16.8 16.8v1.2c0 9.3 7.5 16.8 16.8 16.8h106.7c9.3 0 16.8-7.5 16.8-16.8v-1.2c0-9.3-7.5-16.8-16.8-16.8zM532 829.8h-43.2c-9.4 0-17.1 7.6-17.1 17.1v0.6c0 9.4 7.6 17.1 17.1 17.1H532c9.4 0 17.1-7.6 17.1-17.1v-0.6c0-9.4-7.7-17.1-17.1-17.1zM510.4 252.6h0.6c9.4 0 17.1-7.6 17.1-17.1v-43.2c0-9.4-7.6-17.1-17.1-17.1h-0.6c-9.4 0-17.1 7.6-17.1 17.1v43.2c0 9.4 7.7 17.1 17.1 17.1zM273.1 488.5l-42.9-5.4c-9.4-1.2-17.9 5.4-19.1 14.8l-0.1 0.5c-1.2 9.4 5.4 17.9 14.8 19.1l42.9 5.4c9.4 1.2 17.9-5.4 19.1-14.8l0.1-0.6c1.2-9.3-5.4-17.9-14.8-19zM812.8 497.9c-1.2-9.4-9.7-16-19.1-14.8l-42.9 5.4c-9.4 1.2-16 9.7-14.8 19.1l0.1 0.6c1.2 9.4 9.7 16 19.1 14.8l42.9-5.4c9.4-1.2 16-9.7 14.8-19.1l-0.1-0.6zM339.1 344.6c6-7.3 5-18-2.2-24L303.6 293c-7.3-6-18-5-24 2.2l-0.4 0.4c-6 7.3-5 18 2.2 24l33.3 27.6c7.3 6 18 5 24-2.2l0.4-0.4zM754.7 295.6l-0.4-0.4c-6-7.3-16.8-8.3-24-2.2L697 320.6c-7.3 6-8.3 16.8-2.2 24l0.4 0.4c6 7.3 16.8 8.3 24 2.2l33.3-27.6c7.2-5.9 8.2-16.7 2.2-24zM510.7 302.8c-100.4 0-182.1 81.7-182.1 182.1 0 36.1 25.3 89.4 54.7 151.2 15.8 33.2 32.1 67.6 43.9 98.7v0.7h166.4l0.5 0.2c11-27.2 25.5-57.8 39.5-87.4C664.1 583.9 693 523 693 484.9c-0.2-100.4-81.9-182.1-182.3-182.1z m91.4 330.7C591.5 656 580.6 679 571 700.9H450.9c-10.9-26.1-23.7-53.2-36.3-79.7-25.2-53.1-51.3-108-51.3-136.3 0-81.3 66.1-147.4 147.4-147.4s147.4 66.1 147.4 147.4c0 30.3-28.5 90.4-56 148.6z" fill="#333333" p-id="2277"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user