79 lines
3.0 KiB
JavaScript
79 lines
3.0 KiB
JavaScript
|
|
// 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 };
|
|||
|
|
}
|