/** * 坐标映射工具类 - 用于测试和验证坐标转换的准确性 */ interface DeviceInfo { density: number densityDpi: number hasNavigationBar: boolean aspectRatio: number realScreenSize: { width: number; height: number } appScreenSize: { width: number; height: number } navigationBarSize: { width: number; height: number } } interface CoordinateTestResult { success: boolean accuracy: number // 准确度百分比 avgError: number // 平均误差(像素) maxError: number // 最大误差(像素) testPoints: Array<{ input: { x: number; y: number } expected: { x: number; y: number } actual: { x: number; y: number } error: number }> } export class CoordinateMapper { /** * 测试坐标映射准确性 */ static testCoordinateMapping( deviceWidth: number, deviceHeight: number, displayWidth: number, displayHeight: number, deviceInfo?: DeviceInfo ): CoordinateTestResult { console.log('🧪 开始坐标映射准确性测试') // 生成测试点 const testPoints = [ // 屏幕角落 { x: 0, y: 0 }, { x: deviceWidth - 1, y: 0 }, { x: 0, y: deviceHeight - 1 }, { x: deviceWidth - 1, y: deviceHeight - 1 }, // 屏幕中心 { x: deviceWidth / 2, y: deviceHeight / 2 }, // 常见按钮位置 { x: deviceWidth * 0.8, y: deviceHeight * 0.9 }, // 右下角按钮 { x: deviceWidth * 0.5, y: deviceHeight * 0.8 }, // 底部中央按钮 { x: deviceWidth * 0.2, y: deviceHeight * 0.1 }, // 左上角按钮 // 键盘区域 { x: deviceWidth * 0.25, y: deviceHeight * 0.6 }, { x: deviceWidth * 0.5, y: deviceHeight * 0.6 }, { x: deviceWidth * 0.75, y: deviceHeight * 0.6 }, // 导航栏区域(如果有) ...(deviceInfo?.hasNavigationBar ? [ { x: deviceWidth * 0.2, y: deviceHeight + 50 }, { x: deviceWidth * 0.5, y: deviceHeight + 50 }, { x: deviceWidth * 0.8, y: deviceHeight + 50 } ] : []) ] const results: CoordinateTestResult['testPoints'] = [] let totalError = 0 let maxError = 0 for (const point of testPoints) { // 模拟正向转换:设备坐标 → 显示坐标 const displayCoords = this.deviceToDisplay(point.x, point.y, deviceWidth, deviceHeight, displayWidth, displayHeight) // 模拟反向转换:显示坐标 → 设备坐标 const backToDevice = this.displayToDevice(displayCoords.x, displayCoords.y, deviceWidth, deviceHeight, displayWidth, displayHeight, deviceInfo) // 计算误差 const error = Math.sqrt(Math.pow(point.x - backToDevice.x, 2) + Math.pow(point.y - backToDevice.y, 2)) totalError += error maxError = Math.max(maxError, error) results.push({ input: point, expected: point, actual: backToDevice, error }) } const avgError = totalError / testPoints.length const accuracy = Math.max(0, 100 - (avgError / Math.min(deviceWidth, deviceHeight) * 100)) const result: CoordinateTestResult = { success: avgError < 5, // 平均误差小于5像素认为成功 accuracy, avgError, maxError, testPoints: results } console.log('🧪 坐标映射测试结果:', { success: result.success, accuracy: `${accuracy.toFixed(2)}%`, avgError: `${avgError.toFixed(2)}px`, maxError: `${maxError.toFixed(2)}px`, testPointsCount: testPoints.length }) return result } /** * 设备坐标转换为显示坐标 */ private static deviceToDisplay( deviceX: number, deviceY: number, deviceWidth: number, deviceHeight: number, displayWidth: number, displayHeight: number ): { x: number; y: number } { const scaleX = displayWidth / deviceWidth const scaleY = displayHeight / deviceHeight const scale = Math.min(scaleX, scaleY) const actualDisplayWidth = deviceWidth * scale const actualDisplayHeight = deviceHeight * scale const offsetX = (displayWidth - actualDisplayWidth) / 2 const offsetY = (displayHeight - actualDisplayHeight) / 2 return { x: deviceX * scale + offsetX, y: deviceY * scale + offsetY } } /** * 显示坐标转换为设备坐标(增强版本) */ private static displayToDevice( displayX: number, displayY: number, deviceWidth: number, deviceHeight: number, displayWidth: number, displayHeight: number, deviceInfo?: DeviceInfo ): { x: number; y: number } { const scaleX = displayWidth / deviceWidth const scaleY = displayHeight / deviceHeight const scale = Math.min(scaleX, scaleY) const actualDisplayWidth = deviceWidth * scale const actualDisplayHeight = deviceHeight * scale const offsetX = (displayWidth - actualDisplayWidth) / 2 const offsetY = (displayHeight - actualDisplayHeight) / 2 const adjustedX = displayX - offsetX const adjustedY = displayY - offsetY let deviceX = adjustedX / scale let deviceY = adjustedY / scale // 应用设备特性修正 if (deviceInfo) { const density = deviceInfo.density if (density > 2) { deviceX = Math.round(deviceX * 10) / 10 deviceY = Math.round(deviceY * 10) / 10 } else { deviceX = Math.round(deviceX) deviceY = Math.round(deviceY) } // 导航栏区域修正 if (deviceInfo.hasNavigationBar && deviceInfo.navigationBarSize.height > 0) { const navBarHeight = deviceInfo.navigationBarSize.height const threshold = deviceHeight - navBarHeight if (deviceY > threshold) { deviceY = Math.min(deviceY, deviceHeight + Math.min(navBarHeight, 150)) } } } return { x: Math.max(0, Math.min(deviceWidth, deviceX)), y: Math.max(0, Math.min(deviceHeight, deviceY)) } } /** * 生成坐标映射诊断报告 */ static generateDiagnosticReport( deviceWidth: number, deviceHeight: number, displayWidth: number, displayHeight: number, deviceInfo?: DeviceInfo ): string { const testResult = this.testCoordinateMapping(deviceWidth, deviceHeight, displayWidth, displayHeight, deviceInfo) let report = `📊 坐标映射诊断报告\n` report += `==========================================\n` report += `设备分辨率: ${deviceWidth}x${deviceHeight}\n` report += `显示分辨率: ${displayWidth}x${displayHeight}\n` report += `设备信息: ${deviceInfo ? '已提供' : '未提供'}\n` report += `\n` report += `测试结果:\n` report += `- 测试状态: ${testResult.success ? '✅ 通过' : '❌ 失败'}\n` report += `- 准确度: ${testResult.accuracy.toFixed(2)}%\n` report += `- 平均误差: ${testResult.avgError.toFixed(2)}px\n` report += `- 最大误差: ${testResult.maxError.toFixed(2)}px\n` report += `- 测试点数: ${testResult.testPoints.length}\n` report += `\n` if (!testResult.success) { report += `❌ 问题点分析:\n` testResult.testPoints .filter(p => p.error > 5) .forEach((p, i) => { report += ` ${i + 1}. 输入(${p.input.x.toFixed(1)}, ${p.input.y.toFixed(1)}) → 输出(${p.actual.x.toFixed(1)}, ${p.actual.y.toFixed(1)}) 误差: ${p.error.toFixed(2)}px\n` }) } if (deviceInfo) { report += `\n📱 设备特征:\n` report += `- 密度: ${deviceInfo.density}\n` report += `- DPI: ${deviceInfo.densityDpi}\n` report += `- 长宽比: ${deviceInfo.aspectRatio.toFixed(3)}\n` report += `- 虚拟按键: ${deviceInfo.hasNavigationBar ? '是' : '否'}\n` if (deviceInfo.hasNavigationBar) { report += `- 导航栏尺寸: ${deviceInfo.navigationBarSize.width}x${deviceInfo.navigationBarSize.height}\n` } } report += `==========================================\n` return report } } export default CoordinateMapper