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 };
|
||
}
|