Skip to content

Repository files navigation

@codehz/draw-call

一个声明式 Canvas 绘图库,提供 Flexbox 布局引擎和组件化渲染系统。使用类似 UI 框架的方式来绘制 Canvas 内容,让 Canvas 绘图变得简单直观。

✨ 特性

  • Flexbox 布局引擎 - 支持完整的 Flexbox 布局,包括方向、对齐、间距等
  • 组件化渲染 - 提供 Box、Text、Image、Svg、Stack、RichText、CustomDraw、Transform 等组件
  • 丰富的样式支持 - 渐变、阴影、边框、圆角等
  • 文本排版 - 自动换行、省略号、行高控制、富文本支持等
  • SVG 图形 - 支持矩形、圆形、椭圆、路径等 SVG 图形
  • 2D 变换 - 支持旋转、倾斜等 2D 变换操作
  • 自定义绘制 - 支持自定义 Canvas 绘制逻辑
  • 跨平台 - 支持浏览器和 Node.js 环境
  • TypeScript - 完整的类型支持

📦 安装

bun install @codehz/draw-call

🚀 快速开始

浏览器环境

import{createCanvas,Box,Text}from"@codehz/draw-call";// 获取 canvas 元素constcanvasEl=document.getElementById("canvas")asHTMLCanvasElement;// 创建 Canvas 实例constcanvas=createCanvas({width: 400,height: 300,pixelRatio: window.devicePixelRatio||1,canvas: canvasEl,});// 渲染内容canvas.render(Box({width: "fill",height: "fill",background: "#ffffff",padding: 20,children: [Text({content: "Hello, draw-call!",font: {size: 24,weight: "bold"},color: "#333333",}),],}));

Node.js 环境

import{createCanvas,Box,Text}from"@codehz/draw-call";import{createNodeCanvas}from"@codehz/draw-call/node";// 创建 Canvas 实例constcanvas=createNodeCanvas({width: 400,height: 300,pixelRatio: 2,});// 渲染内容canvas.render(Box({width: "fill",height: "fill",background: "#ffffff",padding: 20,children: [Text({content: "Hello, draw-call!",font: {size: 24,weight: "bold"},color: "#333333",}),],}));// 保存为图片constbuffer=awaitcanvas.toBuffer("image/png");awaitBun.write("output.png",buffer);

📚 组件

Box

容器组件,支持 Flexbox 布局和丰富的样式。

Box({width: 200,height: 100,background: "#ffffff",border: {radius: 8,width: 1,color: "#e0e0e0"},shadow: {offsetY: 2,blur: 8,color: "rgba(0,0,0,0.08)"},padding: 20,direction: "row",justify: "center",align: "center",children: [...],})

Text

文本组件,支持自动换行、行高控制等。

Text({content: "这是一段文本",font: {size: 16,weight: "bold",family: "sans-serif"},color: "#333333",align: "center",lineHeight: 1.5,wrap: true,maxLines: 3,ellipsis: true,});

RichText

富文本组件,支持同时展示多种样式的文本,每个文本段落可以有不同的字体、颜色、背景、装饰等。

RichText({spans: [{text: "普通文本 ",color: "#333333",},{text: "加粗文本 ",font: {size: 16,weight: "bold"},color: "#333333",},{text: "彩色文本 ",font: {size: 16,weight: "bold"},color: "#667eea",},{text: "带背景 ",color: "#ffffff",background: "#764ba2",},{text: "带下划线",underline: true,color: "#333333",},{text: "删除线",strikethrough: true,color: "#999999",},],lineHeight: 1.5,align: "left",maxLines: 5,ellipsis: true,});

Image

图片组件,支持多种适配模式,以及源图像素裁剪。

Image({src: imageBitmap,width: 200,height: 150,// 源图像素裁剪(先 crop,再按 fit/position 绘制到布局框)crop: {x: 10,y: 20,width: 100,height: 80},fit: "cover",// contain | cover | fill | none | scale-downposition: {x: "center",y: "center"},// 绘制时临时关闭图片平滑(未设置则沿用画布设置)imageSmoothingEnabled: false,border: {radius: 8},});

Svg

SVG 图形组件,支持多种图形元素。

import{svg}from"@codehz/draw-call";Svg({width: 200,height: 100,viewBox: {width: 200,height: 100},children: [svg.rect({x: 10,y: 10,width: 50,height: 30,fill: "#667eea"}),svg.circle({cx: 100,cy: 50,r: 20,fill: "#764ba2"}),svg.path({d: "M150 50 Q170 30, 190 50",stroke: {color: "#333",width: 2}}),],});

Stack

堆叠组件,子元素绝对定位。

Stack({width: 200,height: 200,align: "center",justify: "center",children: [Box({width: 100,height: 100,background: "#ff0000"}),Box({width: 50,height: 50,background: "#00ff00"}),],});

Transform

2D 变换组件,支持旋转、倾斜等变换操作。

Transform({children: Box({width: 100,height: 100,background: "#667eea",}),transform: {rotate: Math.PI/4,// 旋转 45 度},transformOrigin: ["50%","50%"],// 变换原点});

CustomDraw

自定义绘制组件,提供受控的绘制上下文。原生 Canvas API 可通过 ctx.canvas 访问,save/restore/transform 由 CustomDrawContext 管理。

CustomDraw({width: 200,height: 100,draw: (ctx,options)=>{// 使用原生 Canvas API 进行绘制ctx.canvas.fillStyle="#667eea";ctx.canvas.fillRect(10,10,180,80);ctx.canvas.fillStyle="#ffffff";ctx.canvas.font="bold 16px sans-serif";ctx.canvas.textAlign="center";ctx.canvas.fillText("Custom Draw",100,60);},});

🎨 样式

尺寸

盒模型采用 CSS border-boxwidth / height 包含 border 与 padding,内容区为 width − border×2 − padding。边框完全绘制在元素框内。

// 固定像素值(border-box 总值)
width: 100;// 百分比
width: "50%";// 自动计算(内容 + padding + border)
width: "auto";// 填充可用空间
width: "fill";

颜色

// CSS 颜色字符串
background: "#ff0000";
background: "rgb(255, 0, 0)";
background: "red";// 渐变import{linearGradient,radialGradient}from"@codehz/draw-call";// 线性渐变
background: linearGradient(135,"#667eea","#764ba2");// 带位置色标的线性渐变
background: linearGradient(90,[0,"#667eea"],[0.5,"#764ba2"],[1,"#f093fb"]);// 径向渐变
background: radialGradient({startX: 0.5,startY: 0.5,endRadius: 0.5},"#667eea","#764ba2");

边框

边框计入 width/height,并以内缩方式绘制(不向外溢出)。背景铺满整个 border-box,边框叠在背景之上。

border: {width: 2,color: "#e0e0e0",radius: 8,// 或 [8, 8, 8, 8] 分别对应左上、右上、右下、左下}

阴影

shadow: {offsetX: 0,offsetY: 4,blur: 16,color: "rgba(0,0,0,0.12)",}

间距

// 四边相同
padding: 20
margin: 10// 分别设置
padding: {top: 10,right: 20,bottom: 10,left: 20}
margin: {top: 5,right: 10,bottom: 5,left: 10}

创建画布时设置 fitContent: true,画布逻辑尺寸会按内容自适应,并包含最外层元素的 margin

constcanvas=createCanvas({width: 400,height: 300,fitContent: true,});// 画布最终约为 120×70(100×50 内容 + 四边 margin 10)canvas.render(Box({width: 100,height: 50,margin: 10,background: "#fff",}));

📐 布局

Flexbox 布局

Box({direction: "row",// row | columnjustify: "center",// flex-start | center | flex-end | space-between | space-around | space-evenlyalign: "center",// flex-start | center | flex-end | stretch | baselinegap: 10,wrap: true,children: [...],})

弹性布局

Box({direction: "row",children: [Box({width: 100}),// 固定宽度Box({flex: 1}),// 占据剩余空间Box({flex: 2}),// 占据 2 份剩余空间],});

🔧 高级用法

自定义字体(Node.js)

import{GlobalFonts}from"@napi-rs/canvas";GlobalFonts.registerFromPath("/path/to/font.ttf","CustomFont");Text({content: "自定义字体",font: {family: "CustomFont",size: 16},});

导出图片

// 导出为 PNGconstbuffer=awaitcanvas.toBuffer("image/png");// 导出为 JPEGconstbuffer=awaitcanvas.toBuffer("image/jpeg",{quality: 0.9});// 导出为 WebPconstbuffer=awaitcanvas.toBuffer("image/webp",{quality: 0.8});

获取布局信息

constlayoutNode=canvas.render(Box({width: 200,height: 100,children: [...],}));console.log(layoutNode.layout.width);// 200console.log(layoutNode.layout.height);// 100console.log(layoutNode.layout.x);// 0console.log(layoutNode.layout.y);// 0

📖 示例

查看 examples 目录获取更多示例:

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages