import type { Dimensions } from '../types'; export interface DimensionOptions { sizeW: number; sizeH: number; bleed: number; padding: number; gridW: number; gridH: number; } /** * 解析卡牌尺寸和网格配置 */ export function calculateDimensions(options: DimensionOptions): Dimensions { // 实际卡牌尺寸(含出血) const cardWidth = options.sizeW + options.bleed * 2; const cardHeight = options.sizeH + options.bleed * 2; // 网格区域尺寸(减去 padding) const gridAreaWidth = options.sizeW - options.padding * 2; const gridAreaHeight = options.sizeH - options.padding * 2; // 每个网格单元的尺寸(mm) const cellWidth = gridAreaWidth / options.gridW; const cellHeight = gridAreaHeight / options.gridH; // 网格区域起点(相对于卡牌左上角,含 bleed 和 padding) const gridOriginX = options.bleed + options.padding; const gridOriginY = options.bleed + options.padding; return { cardWidth, cardHeight, gridAreaWidth, gridAreaHeight, cellWidth, cellHeight, gridW: options.gridW, gridH: options.gridH, gridOriginX, gridOriginY, }; } /** * 计算 layer 位置样式(单位:mm) * 根据 orientation 旋转元素,同时保持覆盖相同的区域 * * orientation 含义: * - n (0°): 正常方向,内容从上到下阅读 * - e (90°): 顺时针旋转 90°,内容从右到左阅读(右侧为顶部) * - s (180°): 旋转 180°,内容从下到上阅读 * - w (270°): 顺时针旋转 270°,内容从左到右阅读(左侧为顶部) */ export function getLayerStyle( layer: { x1: number; y1: number; x2: number; y2: number; orientation?: 'n' | 's' | 'e' | 'w' }, dims: Dimensions ): { left: string; top: string; width: string; height: string; transform?: string; 'transform-origin'?: string; } { const cellWidth = dims.cellWidth; const cellHeight = dims.cellHeight; // 计算原始矩形的边界(相对于网格区域起点) const baseLeft = (layer.x1 - 1) * cellWidth; const baseTop = (layer.y1 - 1) * cellHeight; const baseWidth = (layer.x2 - layer.x1 + 1) * cellWidth; const baseHeight = (layer.y2 - layer.y1 + 1) * cellHeight; const orientation = layer.orientation ?? 'n'; // 根据方向决定旋转角度 // n: 0°, e: 90°, s: 180°, w: 270° const rotationMap: Record<'n' | 's' | 'e' | 'w', number> = { n: 0, e: 90, s: 180, w: 270 }; const rotation = rotationMap[orientation]; // 对于 e/w 方向,需要交换宽高 if (orientation === 'e' || orientation === 'w') { // 计算旋转后的位置,使得元素覆盖相同的区域 // 旋转 90°/270°后,原来的宽度变成高度,高度变成宽度 // 需要调整 left/top 使得旋转后的元素中心与原始矩形中心重合 // 元素尺寸交换 const width = baseHeight; const height = baseWidth; // 计算新起点,使得旋转后覆盖相同区域 // 旋转中心设为元素中心,旋转后元素覆盖的区域与原始区域相同 const left = baseLeft + (baseWidth - width) / 2; const top = baseTop + (baseHeight - height) / 2; return { left: `${left}mm`, top: `${top}mm`, width: `${width}mm`, height: `${height}mm`, transform: `rotate(${rotation}deg)`, 'transform-origin': 'center center' }; } // n 或 s 方向,宽高不变 if (orientation === 's') { return { left: `${baseLeft}mm`, top: `${baseTop}mm`, width: `${baseWidth}mm`, height: `${baseHeight}mm`, transform: `rotate(180deg)`, 'transform-origin': 'center center' }; } // n 方向(默认) return { left: `${baseLeft}mm`, top: `${baseTop}mm`, width: `${baseWidth}mm`, height: `${baseHeight}mm` }; }