Files
smart_storage_app/components/new-canvas/index.vue
2025-06-30 10:21:25 +08:00

361 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view style="width: 100%;height: 100%;position: relative;">
<zero-loading v-show="loading && !noloading" position="absolute" v-if="loading && !noloading"></zero-loading>
<canvas :id="cId" type="2d" :style="{width:width,height:height}" :canvas-id="cId"></canvas>
</view>
</template>
<script>
export default {
data() {
return {
windowWidth: 0,
type: 'app',
ctx: null,
textArr: [],
imgArr: [],
lineArr: [],
circleArr: [],
rectArr: [],
loading: true,
canvasWidth: null,
canvasHeight: null
}
},
props: {
cId: {
type: [String, Number],
default: 'canvas'
},
width: {
type: [String, Number],
default: '100%'
},
height: {
type: [String, Number],
default: '100%'
},
canvasData: {
type: Array,
default: () => {
return []
}
},
noloading: {
type: Boolean,
default: false
}
},
watch: {
canvasData: {
handler(val) {
if (val && val.length) {
this.getSystemInfo()
}
},
deep: true,
immediate: true
}
},
mounted() {
// this.getSystemInfo()
},
methods: {
getSystemInfo() {
const self = this
// 获取屏幕尺寸
uni.getSystemInfo({
success: (res) => {
this.windowWidth = res.windowWidth
},
})
uni.getSystemInfo({
success: function(res) {
// const platform = res.hostName.toLowerCase()
if (res.uniPlatform || res.uniPlatform === 'app') {
self.type = 'app'
//获取app的canvas的dom
self.getAppDom()
} else {
self.type = 'wx'
//获取小程序的canvas的dom
self.getWXDom()
}
}
})
},
clear() {
if (this.type === 'wx') {
this.ctx.globalCompositeOperation = 'destination-out';
this.ctx.beginPath();
this.ctx.fillStyle = 'red';
this.ctx.fillRect(0, 0, 8000, 80000);
this.ctx.fill();
this.ctx.globalCompositeOperation = 'source-over';
// this.ctx.draw();
} else {
// this.ctx.clearRect(2000, 2000, 2000, 2000);
// this.ctx.fillStyle = '#ffffff'
// this.ctx.draw(true);
}
},
//获取app的canvas DOM
getAppDom() {
var context = uni.createCanvasContext(`${this.cId}`)
this.ctx = context
this.draw(null)
},
//获取微信的canvas DOM
getWXDom() {
// const instance = getCurrentInstance()
let query = wx.createSelectorQuery().in(this)
query
.select(`#${this.cId}`)
.fields({
node: true,
size: true
}, () => {})
.exec(this.initCanvas.bind(this))
},
initCanvas(res) {
const width = res[0].width
const height = res[0].height
const canvas = res[0].node
this.ctx = canvas.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = width * dpr
canvas.height = height * dpr
this.canvasWidth = canvas.width
this.canvasHeight = canvas.height
this.ctx.scale(dpr, dpr)
this.draw(canvas)
},
draw(canvas) {
this.textArr = []
this.circleArr = []
this.rectArr = []
this.imgArr = []
this.lineArr = []
this.canvasData.forEach((item) => {
if (item.type === 'text') {
this.textArr.push(item)
}
if (item.type === 'image') {
this.imgArr.push(item)
}
if (item.type === 'line') {
this.lineArr.push(item)
}
if (item.type === 'circle') {
this.circleArr.push(item)
}
if (item.type === 'rect') {
this.rectArr.push(item)
}
})
if (this.imgArr.length) {
this.drawImages(this.imgArr, canvas ? canvas : null)
}
if (this.lineArr.length) {
this.drawLine(this.lineArr)
}
if (this.circleArr.length) {
this.drawCircle(this.circleArr)
}
if (this.rectArr.length) {
this.drawRect(this.rectArr)
}
if (this.textArr.length) {
this.drawText(this.textArr)
}
// this.drawLine(this.lineArr)
// this.drawCircle(this.circleArr)
// this.drawRect(this.rectArr)
// this.drawText(this.textArr)
if (this.type === 'app') {
this.ctx.draw()
}
this.loading = false
},
drawRect(draw) {
draw.forEach((item, index) => {
let x = this.fitSize(item.coord[0][0])
let y = this.fitSize(item.coord[0][1])
let w = this.fitSize(item.coord[1][0])
let h = this.fitSize(item.coord[1][1])
this.ctx.beginPath();
if (this.type === 'app') {
if (item.rectType === 'stroke') {
this.ctx.setStrokeStyle(item.borderColor); // 设置边框颜色
this.ctx.setLineWidth(item.width); // 设置边框宽度
this.ctx.strokeRect(x, y, w, h); // 绘制无填充矩形
} else {
this.ctx.setFillStyle(item.background || 'transparent');
this.ctx.fillRect(x, y, w, h);
}
} else {
if (item.rectType === 'stroke') {
this.ctx.strokeStyle = item.borderColor
this.ctx.lineWidth = item.width
this.ctx.strokeRect(x, y, w, h);
} else {
this.ctx.fillStyle = item.background || 'transparent'
this.ctx.fillRect(x, y, w, h);
}
}
})
},
countChineseAndEnglishCharacters(str, x) {
var chineseCount = str.match(/[\u4e00-\u9fa5]/g)
? str.match(/[\u4e00-\u9fa5]/g).length
: 0;
var englishCount = str.match(/[a-zA-Z]/g)
? str.match(/[a-zA-Z]/g).length
: 0;
var otherCount = str.length - chineseCount - englishCount;
const obj = {
otherCount: otherCount,
chineseCount: chineseCount,
englishCount: englishCount,
};
return (
obj.englishCount * 6 + obj.chineseCount * 12 + obj.otherCount * 7.5 + x
);
},
drawText(draw) {
draw.forEach((item, index) => {
if (item.font.length) {
if (item.font.length > 1) {
item.font.forEach((item2, index2) => {
if (this.type === 'app') {
this.ctx.setFontSize(item2.size)
} else {
this.ctx.fontSize = item2.size
}
this.ctx.fillStyle = item2.color
const x = this.countChineseAndEnglishCharacters(item.font[0].text,item.coord[0][0])
this.ctx.fillText(item2.text, this.fitSize( index2 === 1 ? x : item.coord[0][0]), this.fitSize(item.coord[0][1]))
this.ctx.closePath()
})
} else {
if (this.type === 'app') {
this.ctx.setFontSize(item.font[0].size)
} else {
this.ctx.fontSize = item.font[0].size
}
this.ctx.fillStyle = item.font[0].color
this.ctx.fillText(item.font[0].text, this.fitSize(item.coord[0][0]), this.fitSize(item
.coord[0][1]))
this.ctx.closePath()
}
}
})
},
drawImages(draw, canvas) {
let x,
y,
w,
h = 0
draw.forEach((item) => {
if (item.coord.length >= 2) x = item.coord[0][0]
y = item.coord[0][1]
w = item.coord[1][0]
h = item.coord[1][1]
if (this.type === 'wx') {
let img = canvas.createImage()
img.src = item.url
img.onload = () => {
this.ctx.drawImage(
img,
this.fitSize(item.coord[0][0]),
this.fitSize(item.coord[0][1]),
this.fitSize(item.coord[1][0]),
this.fitSize(item.coord[1][1])
)
this.drawLine(this.lineArr)
this.drawCircle(this.circleArr)
this.drawRect(this.rectArr)
this.drawText(this.textArr)
if (this.type === 'app') {
this.ctx.draw()
}
this.loading = false
}
} else {
this.ctx.drawImage(item.url, this.fitSize(x), this.fitSize(y), this.fitSize(w),
this
.fitSize(h))
}
})
},
drawLine(draw) {
draw.forEach((item) => {
let x1 = this.fitSize(item.coord[0][0])
let y1 = this.fitSize(item.coord[0][1])
let x2 = this.fitSize(item.coord[1][0])
let y2 = this.fitSize(item.coord[1][1])
this.ctx.beginPath()
this.ctx.moveTo(x1, y1)
this.ctx.lineTo(x2, y2)
if (this.type === 'app') {
this.ctx.setStrokeStyle(item.color)
this.ctx.setLineWidth(item.width)
} else {
this.ctx.strokeStyle = item.color
this.ctx.lineWidth = item.width
}
if (item.dash && item.dash.length > 0) {
//虚线
this.ctx.setLineDash(item.dash)
}
this.ctx.stroke()
this.ctx.closePath()
})
},
drawCircle(draw) {
draw.forEach((item) => {
let x = this.fitSize(item.coord[0][0])
let y = this.fitSize(item.coord[0][1])
let r = this.fitSize(item.r)
this.ctx.beginPath()
this.ctx.arc(x, y, r, 0, Math.PI * 2, false)
this.ctx.fillStyle = item.color
this.ctx.fill()
this.ctx.closePath()
})
},
fitSize(coordinate) {
let newWindowWidth = this.windowWidth //这个windowWidth指的是该设备宽度可以onLoad监听页面加载中获取
let v = 375 / newWindowWidth //375是设计稿的大小得到的v值是设计稿和设备宽度的比例关系也可理解成在设计稿的大小基础上放大或缩小的倍数
return coordinate / v //返回的是当前坐标值或者大小与v的比例
}
},
}
</script>
<style>
</style>