@canvas-components/print-design
v0.1.15
Published
Framework-agnostic Canvas print design engine.
Readme
@canvas-components/print-design
原生 Canvas 打印设计核心。文档和元素尺寸使用毫米保存,页面预览按 CSS 像素绘制,导出时可指定 DPI。此包不依赖 React。
插件编写指南按打印设计版本存放在 插件指南目录。当前 vnext 内容是设计草案,现有版本尚未提供插件注册 API。
安装
pnpm add @canvas-components/print-design条形码、二维码和图表元素分别复用仓库中的 barcode、qrcode 和 chart 包。
基础用法
import {
createPrintDesignDocument,
PrintDesign,
} from "@canvas-components/print-design";
const design = new PrintDesign(document.querySelector("#editor")!, {
document: createPrintDesignDocument(),
onChange(nextDocument) {
console.log(nextDocument);
},
}).mount();
design.addElement({
type: "text",
x: 20,
y: 24,
width: 60,
height: 12,
text: "打印模板",
fontSize: 18,
});
const pngCanvas = await design.exportPageToCanvasAsync(undefined, { dpi: 300 });
design.destroy();PrintDesign 提供页面和元素增删改、选区、撤销重做、JSON 文档读写、PNG Canvas/Blob 导出及浏览器打印方法。exportPageToCanvasAsync 和 exportPageToBlob 会等待插件的图片、字体等资源完成准备;同步 exportPageToCanvas 仅适用于无需等待资源的页面。图片使用浏览器可访问的 URL 或 data URL;跨域图片需要来源服务器允许 Canvas 读取。
核心包不附带字体文件。未指定或未安装所选字体时,画布与打印 HTML 按浏览器和操作系统的字体栈回退。
连接线使用 type: "connector"。start 和 end 可通过 elementId 绑定页面上的组件,anchor 可选择 auto、四边中点、四角,或多边形的 edge:0 / vertex:0 等控制点。lineType 支持 straight、curve、polyline;还可设置 stroke、strokeWidth、arrowSize、showStartArrow、showEndArrow、text 和沿线比例 textPosition。连接线可经过其他组件,由元素层级决定显示在组件上方或下方;绑定组件移动后路径会自动重新计算。React 设计器里拖动连接线端点可吸附到组件边缘控制点,拖动线上文本可调整位置。
选中单个组件后,拖动四边的加号可创建绑定起点的连接线;拖到目标组件内部或边缘控制点时自动绑定终点。拖动期间的创建操作作为一次历史记录,支持撤销。
括号组件使用 type: "shape",shape 支持左/右中括号、左/右大括号、中括号组和大括号组共六种预设。画布与打印共用路径;可设置 stroke、strokeWidth 和 lineStyle(实线、虚线、点线),并通过元素宽高调整大小。
曲线组件也使用 type: "shape",shape 可设为 curve-quadratic、curve-cubic 或 curve-multi。curvePoints 以元素宽高为基准保存归一化锚点和控制点,curvature 范围为 0~2;多段曲线由连续三次贝塞尔段组成。text 沿路径绘制,curveTextTrack 控制文字位于上方、中间或下方,curveTextPosition 控制沿路径的位置。Canvas 与 HTML 打印共用曲线几何。
流程组件使用 type: "flow",参考 list-table 单元格时间轴的节点、连接线、标题和内容布局。静态模式编辑 items;动态模式设置 dataMode: "binding" 与节点数组 dataPath,数组项默认读取 content、title、color、position、loading 和 icon,也可通过 itemFields 映射其他字段。动态路径缺失时可使用 fallbackToStatic 回退,空数组始终显示为空。mode 支持右侧、左侧和左右交替,variant 支持描边与填充,reverse 可倒序显示。画布与 HTML 打印共用流程布局和绑定结果。
设置 debug: true 可在画布显示元素边界、选区与指针命中目标;传入 PrintDesignDebugOptions 对象可分别控制这些辅助层。
画布默认显示毫米刻度尺与辅助线;可通过 showRulers、showGuides、showMarginGuides 分别控制刻度尺、可编辑辅助线和打印边距辅助线。打印边距线按页面四边边距绘制,可在页面属性中配置,编辑器工具栏的“打印边距”按钮可控制显隐。辅助线以当前页面原点为坐标基准,可拖放在纸张外的画布区域,并会延伸连接到刻度尺。拖动刻度尺可创建辅助线,拖动辅助线可调整位置或拖回刻度尺删除;选中辅助线后按 Delete/Backspace 也可删除。
画布辅助配置
左侧“配置”面板(React 编辑器)可控制刻度尺、辅助线、打印边距和最近组件间距的显示,并调整以下原生选项:
snapToGuides:默认开启。组件边缘和中心吸附到辅助线;辅助线吸附到纸张边缘、中心、打印边距和组件位置。按住 Alt 临时关闭。snapTolerance:默认 6 CSS 像素,不随缩放改变屏幕吸附距离。dragThreshold:默认 4 CSS 像素。选中后超过此距离才开始移动、缩放、旋转、辅助线拖拽或画布平移。showMeasurements:默认开启,标注选中组件与上下左右投影相交的最近可见组件间距,单位毫米;旋转组件使用外接矩形测量。zoomDuration:默认 180 毫秒,设为 0 关闭缩放过渡。
在画布上使用滚轮可纵向平移,按住 Shift 滚轮可横向平移,Ctrl/⌘ 加滚轮可缩放。也可按住空格拖拽或拖拽纸张空白/外部区域平移查看;平移和缩放不会修改打印文档或导出内容。 鼠标滚轮的大步进采用平滑过渡,触控板的小幅连续滚动直接跟随输入。 滚轮和拖拽平移最多偏离画布可见区域宽高的 200%。
刻度与辅助线外观
左侧“配置”面板支持调整刻度尺字号/背景和辅助线数值字号/背景,原生实例可通过以下选项或 updateOptions() 实时设置:
| 选项 | 默认值 | 说明 |
| ------------------------- | --------- | --------------------------- |
| rulerFontSize | 9 | 刻度尺字号,8–16 CSS px |
| rulerBackground | #f8fafc | 刻度尺背景色 |
| guideFontSize | 9 | 辅助线数值字号,8–24 CSS px |
| guideBackground | #cffafe | 辅助线圆角标签背景色 |
| guideSelectedBackground | #ffedd5 | 选中辅助线的标签背景色 |
标签随字号自动调整尺寸,保持与纸张 8px 间距。
辅助线颜色可通过配置面板或原生选项设置:guideColor 控制普通辅助线(默认青色),marginGuideColor 控制打印边距辅助线(默认紫色)。纸张内线条与纸张外延长线同步更新,选中标记保留高亮。
图表数据
图表元素可设置 chartData:mode: "static" 使用 categories 和 series[].values;mode: "binding" 从实例 data 的 source 数组路径读取记录,以 categoryField 生成分类、series[].field 读取数值。路径支持点路径和数组索引(例如 orders[0].items),数值字符串可自动转换,缺失或非数值按 0 处理。切换模式保留静态数据。
画布、导出与打印使用同一份绑定结果,导出时可通过 exportPageToCanvasAsync(pageId, { data }) 覆盖实例数据并等待插件资源。饼图、环形图、雷达图与仪表盘使用单个 option.series 对象,兼容历史模板中的单项数组写法。
画布文本编辑
双击未锁定的静态文本可进入原位编辑:Enter 或失焦保存,Shift+Enter 换行,Esc 取消,Tab 保存并返回画布。编辑框跟随文本的坐标、缩放、旋转和字体;提交作为一次文档修改,可撤销/重做。只读状态和包含 {{字段路径}} 的绑定文本不进入静态编辑;切换页面、删除元素或外部更新原文时会丢弃过期草稿。
表格组件
表格元素由 @canvas-components/print-design-plugin 的 table 插件提供;columns 使用插件的 TableColumn[] 声明式配置,支持嵌套表头、字段路径、cellType、金额格式、列样式与汇总。打印文档必须使用可 JSON 序列化的数据,不包含 render、onCell 等函数。
import type { TableElement } from "@canvas-components/print-design-plugin/native";
const table: TableElement = {
id: "order-table",
type: "table",
x: 10,
y: 30,
width: 180,
height: 80,
dataMode: "binding",
dataPath: "order.items",
dataSource: [],
showHeader: true,
rowHeight: 8,
headerRowHeight: 9,
fontSize: 10,
columns: [
{ title: "商品", dataIndex: ["product", "name"], width: 240 },
{
title: "金额",
dataIndex: "amount",
cellType: "money",
width: 120,
align: "right",
summary: { type: "sum", showTypePrefix: false },
},
],
};dataMode: "static" 使用 dataSource,binding 使用实例或导出参数的 data 中对应数组;路径支持 orders[0].items。几何尺寸与行高单位为毫米,字号为 pt;列宽和列内样式保留 list-table 的 96 DPI 逻辑像素单位,画布缩放和导出 DPI 会统一换算。表格按实际记录数扩高,预览与打印按行分页,后续组件随表格实际高度移动。列固定、排序、筛选、拖拽等交互控件不参与打印绘制。
在画布中将鼠标移到表格的列分隔线,出现横向调整光标后拖拽即可改变相邻两列的宽度;无需先选中表格。表格整体宽度保持不变,调整结果支持撤销与重做。
表格的“统一单元格布局”可设置水平对齐、垂直对齐、内容超出方式及四边内边距;每列的“单元格布局”可以单独覆盖,未设置的内边距逐边继承表格设置,也可恢复统一布局。内容超出方式包括超出裁切、自动换行、超出显示省略号和压缩字形。前三种保持原字号;内边距单位沿用列宽的 96 DPI 逻辑像素。旧版 ellipsis 列配置继续有效。
表格默认不填充背景。colors.header、colors.body、colors.summary 可分别设置 { backgroundColor, color },背景可设为 "transparent";配置对画布、导出和打印同时生效,列级 headerStyle、cellStyle、summaryStyle 优先。示例:colors: { header: { backgroundColor: "#e8f0fe", color: "#172033" }, body: { backgroundColor: "transparent" }, summary: { backgroundColor: "#fff7e6" } }。
borderMode 支持 "show"、"hide"、"preprint"、"binding"。"preprint" 为表格边框套打模式:设计和预览显示边框,实际打印时边框颜色透明且保留宽度;"hide" 和动态数据关闭边框时,打印也使用透明边框。绑定时使用 borderPath 读取预览数据,值为 false、0、空字符串或缺失时隐藏边框。cells 可按零起始的 rowIndex、columnIndex 覆盖颜色与边框;单元格的 contentMode: "preprint" 使其内容在设计和预览中显示、实际打印时透明度为 0,不影响该单元格的边框和布局。rowSpan、colSpan 定义合并区域,diagonal 可设为 "down" 或 "up",并由 diagonalStart、diagonalEnd 指定两侧内容。分页会尽量保持合并区域完整。多级表头按列树逐层绘制;headerCells 使用相同的行列索引与跨度单独保存表头手动合并,并在画布与 HTML 打印中生效。
对角线单元格支持两个单线方向,diagonalCount 默认 1;设置多条后进入角头模式,diagonalCorner 可选左上、右上、左下、右下四个共用角点,终点沿对侧边缘等分。diagonalSections 按外侧边缘顺序配置每个区域的文本和样式,样式可设置字号(pt)、字体、颜色、加粗、倾斜和对齐。diagonalMode: "preprint" 让对角线在设计时显示、实际打印时透明;单元格内容的套打模式单独控制分区文字。旧版 diagonalStart、diagonalEnd 及对应样式字段继续可用;设计画布与打印输出使用相同的分区位置。示例模板“分条整经扦经工艺单”的“批号/捻度”单元格展示了单条对角线配置。
动态记录可配置与 ListTable 相同的 mergeCell 规则,例如 mergeCell: { row: { keys: ["orderType", "project"], columns: ["orderType", "project"] }, column: { keys: ["left", "right"] } }。row.keys 按连续记录的字段值分组,row.columns 指定实际合并的列,省略时使用 keys;column.keys 使同一行中相邻且值相同的目标列合并。画布、预览、分页和 HTML 打印使用同一组规则,手动 cells 合并优先。
静态数据表格支持双击数据单元格原位编辑:Enter / Tab 或失焦保存,Esc 取消,Shift+Enter 换行,支持输入法与撤销重做。数值、布尔和 JSON 字段保留原类型并校验输入;表头、汇总行、绑定数据、锁定和只读表格不进入编辑。
设计画布选中表格后绘制行号、列字母和左上角全选选择器。selectComponentSelector 可选择整行、整列或全表;insertTableRow 向静态数据插入空行,insertTableColumn 在可见叶列旁插入新列。插入时会移动或扩展已有手动合并区域,并纳入撤销历史。
辅助线图层选中后可在右侧属性面板精确设置毫米位置(允许负数和纸张外坐标),位置修改支持撤销重做。原生 API 为 updateGuide(axis, index, position)。面板同时提供方向与参照边说明、删除及全局辅助线外观/吸附设置。
所有元素类型均可配置图层层级:右侧支持输入层级编号(1 为底层)和置顶、上移、下移、置底;左侧图层列表按顶层到底层排列,可拖拽前方手柄调整顺序,放下时提交一次历史。操作保留选区并支持撤销重做。原生 setElementLayer(elementId, layerIndex) 使用从 0 开始的底层索引,moveElementLayer 提供相对移动。
图层支持嵌套组合:左侧 Ctrl/⌘ 点击切换多选,Shift 点击范围多选;右键菜单提供组合与取消组合,不常驻占用列表空间。画布 Shift/Ctrl/⌘ 点击多选后可使用 Ctrl/⌘+G 组合、Ctrl/⌘+Shift+G 取消最外层组合。组合成员整体选中和移动,左侧按组合树展示并支持同级拖拽排序,所有文档操作支持撤销重做。组合路径 groupPath 随 JSON 保存;纯原生核心不依赖 React。
基础组件数据绑定
文本、图片、条形码、二维码、形状和分割线支持 dataConfig: { mode: "static" | "binding", bindings?: Record<string, string> }。绑定映射的键为组件字段:文本 text、图片 src、条码/二维码 value、形状 fill/stroke/strokeWidth、分割线 stroke/strokeWidth;值为设计器 data 中的路径(如 order.items[0].name),也支持 {{order.id}} 模板。图表和表格继续使用 chartData 和 dataMode/dataPath。
绑定在绘制副本上解析,保留文档中的静态值;路径缺失或数据类型不适用时使用静态值。静态模式直接绘制原值;未声明 dataConfig 的旧文本/编码组件继续解析已有的 {{path}} 模板。动态文本不允许画布双击编辑,静态文本仍支持。
动态基础字段的默认内容直接存于原组件属性,空字符串、null、缺失或类型无效时回退,0/false 不回退。图表 chartData.fallbackToStatic 与表格 fallbackToStatic 可显式启用缺失数据源回退,分别使用静态分类/系列和 dataSource;空数组仍为有效动态数据。绑定悬停提示仅属于设计器辅助绘制,不影响打印导出。
ListTable 记录集与图表接入
传入 data 的命名字段可使用 PrintDesignRecordCollection(dataSource + 可选 columns)或原生 ListTableChartData(labels、keys、series[].data)。表格的 dataPath 可直接指向记录集对象,图表的 chartData.source 可指向记录集或已转换的图表数据;直接图表源不需要 categoryField/系列字段映射。原始数组绑定继续兼容。框架适配层无需被原生核心引用。
