// src/composables/useCanvasPointer.js import { ref } from "vue"; /** * @param {{ phone, toBuffer, getWs: (index:number)=>WebSocket|null }} deps * 依赖项对象,包含手机信息、缓冲转换和WebSocket获取函数 */ export function useCanvasPointer(deps) { const { phone, toBuffer, getWs } = deps; const canvasRef = ref({}); // { [udid]: HTMLCanvasElement } - 存储设备ID到Canvas元素的映射 const frameMeta = ref({}); // { [udid]: { w,h, rotation? } } - 存储设备ID到帧元数据的映射 /** * 初始化画布 * @param {string} udid - 设备唯一标识符 */ function initCanvas(udid) { const canvas = canvasRef.value[udid]; if (!canvas) return; const dpr = window.devicePixelRatio || 1; // 获取设备像素比 // 设置画布样式尺寸 canvas.style.width = `${phone.value.width * 1.4}px`; canvas.style.height = `${phone.value.height * 1.4}px`; // 设置画布实际像素尺寸 canvas.width = phone.value.width * 1.4 * dpr; canvas.height = phone.value.height * 1.4 * dpr; const ctx = canvas.getContext("2d"); ctx.scale(dpr, dpr); // 可选:参考网格(已设为透明) ctx.strokeStyle = "#ffffff00"; for (let x = 0; x <= phone.value.width; x += 100) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, phone.value.height); ctx.stroke(); } } function getCanvasCoordinate(event, udid) { const canvas = canvasRef.value[udid]; const rect = canvas.getBoundingClientRect(); const rx = (event.clientX - rect.left) / rect.width; const ry = (event.clientY - rect.top) / rect.height; const meta = frameMeta.value[udid] || { w: 320, h: 720, rotation: 0 }; let x = rx * meta.w; let y = ry * meta.h; switch (meta.rotation ?? 0) { case 90: [x, y] = [meta.w - y, x]; break; case 180: [x, y] = [meta.w - x, meta.h - y]; break; case 270: [x, y] = [y, meta.h - x]; break; } x = Math.max(0, Math.min(meta.w - 1, x)); y = Math.max(0, Math.min(meta.h - 1, y)); return { x: Math.round(x), y: Math.round(y), w: meta.w, h: meta.h }; } // 统一发包:point 用帧坐标,screenSize 用帧宽高 function sendPointer(udid, index, action /* 0 down,1 up,2 move */, x, y) { const meta = frameMeta.value[udid] || { w: 320, h: 720, rotation: 0 }; const payload = { type: 2, action, pointerId: 0, position: { point: { x, y }, screenSize: { width: meta.w, height: meta.h } }, pressure: action === 1 ? 0 : 1, buttons: action === 1 ? 0 : 1, }; const ws = getWs(index); if (ws && ws.readyState === WebSocket.OPEN) { ws.send(toBuffer(payload)); } } return { canvasRef, frameMeta, initCanvas, getCanvasCoordinate, sendPointer }; }