canvas/unpackage/dist/dev/mp-weixin/pages/index/transform-canvas.js
2025-08-13 18:14:56 +08:00

303 lines
8.6 KiB
JavaScript

"use strict";
const common_vendor = require("../../common/vendor.js");
const _sfc_main = {
props: {
width: Number,
// 画布实际宽度(像素)
height: Number,
// 画布实际高度(像素)
imgUrl: String,
// 图片URL
matrix: {
// 变换矩阵
type: Object,
default: () => ({
a: 1,
b: 0,
c: 0,
d: 1,
tx: 0,
ty: 0
})
},
areaData: {},
seatData: {},
selectedCodes: {}
},
data() {
return {
canvasContext: null,
image: null,
dpr: 1,
canvasDisplayWidth: 800,
// 默认显示尺寸
canvasDisplayHeight: 600,
canvasActualWidth: 800,
// 实际像素尺寸
canvasActualHeight: 600,
nowSelectedCodes: this.selectedCodes
};
},
watch: {
selectedCodes: {
handler(newVal) {
this.nowSelectedCodes = newVal;
},
immediate: true
},
imgUrl: {
handler(newUrl) {
if (newUrl)
this.loadImage(newUrl);
},
immediate: true
},
width: {
handler() {
this.updateCanvasSize();
},
immediate: true
},
height: {
handler() {
this.updateCanvasSize();
},
immediate: true
},
matrix: {
deep: true,
immediate: true,
// 添加立即触发
handler() {
this.$nextTick(this.redraw);
}
},
areaData: {
deep: true,
handler() {
this.$nextTick(this.redraw);
}
},
seatData: {
deep: true,
handler() {
this.$nextTick(this.redraw);
}
}
},
mounted() {
this.initCanvas();
},
methods: {
invertPoint(x, y) {
const inverted = this.matrix.invertPoint(x, y);
return inverted;
},
// 添加点击检测方法
checkHitArea(x, y) {
if (!this.areaData)
return null;
const inverted = this.matrix.invertPoint(x, y, this.dpr);
common_vendor.index.__f__("log", "at pages/index/transform-canvas.vue:107", "checkHitArea", inverted);
for (const area of this.areaData) {
if (this.pointInPolygon(inverted.x, inverted.y, area.polygon)) {
return area;
}
}
return null;
},
pointInPolygon(x, y, polygon) {
const points = [];
for (let i = 0; i < polygon.length; i += 2) {
points.push([polygon[i], polygon[i + 1]]);
}
let inside = false;
let j = points.length - 1;
for (let i = 0; i < points.length; j = i++) {
const [xi, yi] = points[i];
const [xj, yj] = points[j];
if (this.pointOnLineSegment(x, y, xi, yi, xj, yj))
return true;
if (yi <= y && yj > y || yj <= y && yi > y) {
const slope = (xj - xi) / (yj - yi);
if (x <= xi + (y - yi) * slope) {
inside = !inside;
}
}
}
return inside;
},
// 添加点是否在线段上的检查
pointOnLineSegment(x, y, x1, y1, x2, y2) {
const dx = x2 - x1;
const dy = y2 - y1;
const segmentLength = Math.sqrt(dx * dx + dy * dy);
const vx = x - x1;
const vy = y - y1;
const dotProduct = vx * dx + vy * dy;
const t = dotProduct / (segmentLength * segmentLength);
if (t >= 0 && t <= 1) {
const projX = x1 + t * dx;
const projY = y1 + t * dy;
const distance = Math.sqrt((x - projX) * 2 + (y - projY) * 2);
return distance < 5;
}
return false;
},
initCanvas() {
const query = common_vendor.index.createSelectorQuery().in(this);
query.select("#myCanvas").fields({ node: true, size: true }).exec(async (res) => {
if (!res[0])
return;
this.canvas = res[0].node;
this.ctx = res[0].node.getContext("2d");
this.dpr = common_vendor.index.getSystemInfoSync().pixelRatio;
this.updateCanvasSize();
if (this.imgUrl) {
await this.loadImage(this.imgUrl);
}
});
},
updateCanvasSize() {
this.canvasDisplayWidth = this.width;
this.canvasDisplayHeight = this.height;
this.canvasActualWidth = this.width;
this.canvasActualHeight = this.height;
if (this.canvas) {
this.canvas.width = this.canvasActualWidth;
this.canvas.height = this.canvasActualHeight;
this.redraw();
}
},
async loadImage(src) {
try {
if (!this.canvas) {
await this.initCanvas();
}
this.image = await new Promise((resolve, reject) => {
if (!this.canvas) {
return;
}
const image = this.canvas.createImage();
image.src = src;
image.onload = () => resolve(image);
image.onerror = reject;
});
this.redraw();
} catch (e) {
common_vendor.index.__f__("error", "at pages/index/transform-canvas.vue:238", "图片加载失败:", e);
this.image = null;
}
},
// 在redraw方法中添加视图判断
checkSeatHit(x, y) {
if (!this.seatData)
return null;
const inverted = this.matrix.invertPoint(x, y, this.dpr);
for (const seat of this.seatData) {
const dx = seat.x - inverted.x;
const dy = seat.y - inverted.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 8) {
return seat;
}
}
return null;
},
redraw() {
var _a, _b, _c;
if (!this.ctx)
return;
this.ctx.save();
this.ctx.resetTransform();
this.ctx.clearRect(0, 0, this.canvasActualWidth, this.canvasActualHeight);
this.ctx.scale(this.dpr, this.dpr);
const { a, b, c, d, tx, ty } = this.matrix;
this.ctx.setTransform(a, b, c, d, tx, ty);
if (this.image && ((_a = this.$parent) == null ? void 0 : _a.currentView) === "area") {
this.ctx.drawImage(
this.image,
0,
0,
this.canvasDisplayWidth,
this.canvasDisplayHeight
);
}
if (this.areaData && this.areaData.length > 0 && ((_b = this.$parent) == null ? void 0 : _b.currentView) === "area") {
this.drawAreas();
}
if (this.seatData && this.seatData.length > 0 && ((_c = this.$parent) == null ? void 0 : _c.currentView) === "seat") {
this.drawSeats();
}
this.ctx.restore();
},
// 添加绘制区域方法
drawAreas() {
this.areaData.forEach((area) => {
const points = [];
for (let i = 0; i < area.polygon.length; i += 2) {
points.push([area.polygon[i], area.polygon[i + 1]]);
}
this.ctx.beginPath();
points.forEach(([x, y], index) => {
if (index === 0)
this.ctx.moveTo(x, y);
else
this.ctx.lineTo(x, y);
});
this.ctx.closePath();
this.ctx.strokeStyle = "rgba(255, 0, 0, 0.7)";
this.ctx.lineWidth = 2;
this.ctx.stroke();
this.ctx.fillStyle = "rgba(0, 255, 0, 0.2)";
this.ctx.fill();
});
},
drawSeats() {
this.ctx.save();
const { a, b, c, d, tx, ty } = this.matrix;
this.ctx.setTransform(a, b, c, d, tx, ty);
const scale = Math.sqrt(a * a + b * b);
this.seatData.forEach((seat) => {
const x = seat.x;
const y = seat.y;
const radius = 8 / scale;
if (this.nowSelectedCodes.has(seat.code) && seat.status === 1) {
this.ctx.beginPath();
this.ctx.arc(x, y, radius + 1, 0, Math.PI * 2);
this.ctx.strokeStyle = "#FFD700";
this.ctx.lineWidth = 2 / scale;
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.arc(x, y, radius, 0, Math.PI * 2);
this.ctx.fillStyle = "rgba(255, 215, 0, 0.3)";
this.ctx.fill();
this.ctx.strokeStyle = "#fff";
this.ctx.lineWidth = 1 / scale;
this.ctx.lineCap = "round";
this.ctx.beginPath();
this.ctx.moveTo(x - 2.5, y);
this.ctx.lineTo(x - 0.5, y + 1.5);
this.ctx.lineTo(x + 2.5, y - 2);
this.ctx.stroke();
} else {
this.ctx.beginPath();
this.ctx.arc(x, y, radius, 0, Math.PI * 2);
this.ctx.fillStyle = seat.status === 1 ? "#4cd964" : "#dd524d";
this.ctx.fill();
}
});
this.ctx.restore();
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: `${$data.canvasDisplayWidth}px`,
b: `${$data.canvasDisplayHeight}px`
};
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
wx.createComponent(Component);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/transform-canvas.js.map