/**
* 样式与坐标转换的共享工具(HTML / SVG 共用)。
*
* 布局结果内部统一使用 mm;SVG/HTML 输出按需换算为 px。
* 样式统一转成 CSS 声明,保证各 Renderer 视觉一致(§15)。
*/
import type { ResolvedStyle } from "@report/core"
import { mmToPx } from "@report/layout"
import type { RenderOptions } from "./types.js"
/** 把 mm 值按目标单位换算为数值(SVG/HTML 里直接写数字)。 */
export function toUnit(value: number, options: RenderOptions): number {
return options.unit === "px" ? mmToPx(value) : value
}
/** 单位后缀。 */
export function unitSuffix(options: RenderOptions): string {
return options.unit === "px" ? "px" : "mm"
}
/**
* 把已解析样式转成 CSS 声明字符串。
*
* 字号在文档中是 pt,HTML/SVG 里也以 pt 表达,保证与布局测量一致。
* 边框只输出四边统一值;逐边覆盖的边框由 Renderer 按需处理。
*/
export function styleToCss(style: ResolvedStyle): string {
const parts: string[] = []
parts.push(`font-family:${style.fontFamily}`)
parts.push(`font-size:${style.fontSize}pt`)
parts.push(`font-weight:${style.fontWeight}`)
parts.push(`font-style:${style.fontStyle}`)
parts.push(`line-height:${style.lineHeight}`)
parts.push(`color:${style.color}`)
if (style.background && style.background !== "transparent") {
parts.push(`background:${style.background}`)
}
parts.push(`text-align:${style.align}`)
parts.push(`text-decoration:${style.textDecoration}`)
if (style.border) {
const width = style.border.width ?? 0.1
const color = style.border.color ?? "#000000"
const lineStyle = style.border.style ?? "solid"
parts.push(`border:${width}mm ${lineStyle} ${color}`)
}
return parts.join(";")
}
/** 把已解析样式转成 SVG 文本属性(fill / font-size 等)。 */
export function styleToSvgTextAttrs(style: ResolvedStyle): Record {
const attrs: Record = {
fill: style.color,
"font-family": style.fontFamily,
"font-size": `${style.fontSize}pt`,
"font-weight": String(style.fontWeight),
"font-style": style.fontStyle,
}
if (style.textDecoration === "underline") attrs["text-decoration"] = "underline"
if (style.textDecoration === "line-through") attrs["text-decoration"] = "line-through"
return attrs
}