# LeaferJS LeaferJS 是一款功能强大、轻量高效的 Canvas 2D 图形渲染引擎,专为绘图、UI 交互和图形编辑等场景设计。它提供了丰富的图形元素(矩形、圆形、多边形、路径、文本、图片等)、完整的事件系统(支持捕获/冒泡阶段)以及强大的动画和编辑器插件,让开发者可以快速构建交互式应用、小游戏、配置工具和图形编辑软件。 LeaferJS 采用树状结构组织元素,支持 JSON 导入导出、多种填充和描边样式、遮罩和橡皮擦功能。通过插件机制,可以扩展动画、自动布局、图形编辑器等高级功能。支持在浏览器和 Node.js 环境中运行,兼容 Vue、React 等主流前端框架。 --- ## 创建 Leafer 引擎 Leafer 引擎是整个渲染系统的根节点,负责管理布局和渲染,支持将 view 挂载到 window、div 或 canvas 元素上。 ```typescript import { Leafer, Rect } from 'leafer-ui' // 创建固定宽高的 Leafer 引擎 const leafer = new Leafer({ view: window, // 支持 window、div、canvas 或 id 字符串 width: 800, height: 600, fill: '#333' // 背景色 }) // 添加一个可拖拽的矩形 leafer.add(Rect.one({ fill: '#32cd79', draggable: true }, 100, 100)) // 自适应布局(画布跟随容器大小变化) const responsiveLeafer = new Leafer({ view: window, fill: '#333' // 不设置 width/height 则自动填充整个容器 }) // 自动生长布局(画布自动贴合内容) const growLeafer = new Leafer({ view: window, grow: true, // 启用自动生长 fill: '#333' }) ``` --- ## Rect 矩形元素 绘制矩形和圆角矩形,是最基础的图形元素之一。 ```typescript import { Leafer, Rect } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 标准创建矩形 const rect = new Rect({ x: 100, y: 100, width: 200, height: 150, fill: '#32cd79', // 填充色 stroke: 'black', // 边框色 strokeWidth: 2, // 边框宽度 cornerRadius: 20, // 圆角半径 draggable: true // 可拖拽 }) leafer.add(rect) // 简洁创建方式: Rect.one(样式, x, y, width, height) const rect2 = Rect.one({ fill: '#FEB027' }, 350, 100, 100, 100) leafer.add(rect2) // 不同圆角的矩形 const rect3 = new Rect({ x: 100, y: 300, width: 100, height: 100, fill: '#FF4B4B', cornerRadius: [0, 40, 20, 40] // [左上, 右上, 右下, 左下] }) leafer.add(rect3) ``` --- ## Ellipse 圆形/椭圆元素 绘制圆形、椭圆、扇形、圆环和弧线。 ```typescript import { Leafer, Ellipse } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 圆形 const circle = new Ellipse({ x: 100, y: 100, width: 100, height: 100, fill: '#32cd79' }) leafer.add(circle) // 椭圆 const ellipse = new Ellipse({ x: 250, y: 100, width: 150, height: 100, fill: '#FEB027' }) leafer.add(ellipse) // 扇形圆环 const ring = new Ellipse({ x: 100, y: 250, width: 100, height: 100, startAngle: -60, // 起始角度 endAngle: 180, // 结束角度 innerRadius: 0.5, // 内半径比例 (0-1) fill: '#FF4B4B' }) leafer.add(ring) // 弧线 const arc = new Ellipse({ x: 250, y: 250, width: 100, height: 100, startAngle: 0, endAngle: 270, innerRadius: 0.8, stroke: '#32cd79', strokeWidth: 10 }) leafer.add(arc) ``` --- ## Line 线条元素 绘制直线、折线和平滑曲线。 ```typescript import { Leafer, Line } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 横线 const line = new Line({ x: 100, y: 100, width: 200, strokeWidth: 5, stroke: '#32cd79' }) leafer.add(line) // 斜线 const slopeLine = new Line({ x: 100, y: 150, width: 200, height: 100, strokeWidth: 3, stroke: '#FEB027' }) leafer.add(slopeLine) // 折线 const polyline = new Line({ x: 100, y: 300, points: [0, 0, 50, 80, 100, 20, 150, 100, 200, 50], strokeWidth: 3, stroke: '#FF4B4B' }) leafer.add(polyline) // 平滑曲线 const curve = new Line({ x: 100, y: 450, points: [0, 0, 50, 80, 100, 20, 150, 100, 200, 50], curve: true, // 启用平滑曲线 strokeWidth: 3, stroke: '#79CB4D' }) leafer.add(curve) ``` --- ## Polygon 多边形元素 绘制三角形、正多边形和自由多边形。 ```typescript import { Leafer, Polygon } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 正六边形 const hexagon = new Polygon({ x: 100, y: 100, width: 100, height: 100, sides: 6, // 边数 fill: '#32cd79' }) leafer.add(hexagon) // 圆角六边形 const roundedHex = new Polygon({ x: 250, y: 100, width: 100, height: 100, sides: 6, cornerRadius: 10, fill: '#FEB027' }) leafer.add(roundedHex) // 三角形 const triangle = new Polygon({ x: 100, y: 250, width: 100, height: 100, sides: 3, fill: '#FF4B4B' }) leafer.add(triangle) // 自由多边形 const freePolygon = new Polygon({ x: 250, y: 250, points: [0, 50, 50, 0, 100, 50, 80, 100, 20, 100], fill: '#79CB4D' }) leafer.add(freePolygon) ``` --- ## Star 星形元素 绘制五角星、多角星和星光图形。 ```typescript import { Leafer, Star } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 五角星 const star5 = new Star({ x: 100, y: 100, width: 100, height: 100, corners: 5, // 角数 innerRadius: 0.38, // 内半径比例 fill: '#FEB027' }) leafer.add(star5) // 八角星 const star8 = new Star({ x: 250, y: 100, width: 100, height: 100, corners: 8, innerRadius: 0.5, cornerRadius: 5, // 圆角 fill: '#32cd79' }) leafer.add(star8) // 星光效果 const starburst = new Star({ x: 100, y: 250, width: 100, height: 100, corners: 12, innerRadius: 0.8, fill: '#FF4B4B' }) leafer.add(starburst) ``` --- ## Path 路径元素 使用 SVG 路径字符串绘制任意形状的图形。 ```typescript import { Leafer, Path } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 使用 SVG 路径字符串 const heart = new Path({ x: 100, y: 100, path: 'M50 15 C30 -5, 0 10, 0 35 C0 55, 20 70, 50 90 C80 70, 100 55, 100 35 C100 10, 70 -5, 50 15Z', fill: '#FF4B4B' }) leafer.add(heart) // 使用 pen 画笔快速绘制 const pathWithPen = new Path() pathWithPen.pen .moveTo(200, 100) .lineTo(250, 50) .lineTo(300, 100) .bezierCurveTo(330, 150, 270, 200, 250, 180) .closePath() pathWithPen.fill = '#32cd79' leafer.add(pathWithPen) // 复杂图标路径 const icon = new Path({ x: 100, y: 250, scale: 0.08, path: 'M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm192 472c0 4.4-3.6 8-8 8H544v152c0 4.4-3.6 8-8 8h-64c-4.4 0-8-3.6-8-8V544H320c-4.4 0-8-3.6-8-8v-64c0-4.4 3.6-8 8-8h144V320c0-4.4 3.6-8 8-8h64c4.4 0 8 3.6 8 8v144h152c4.4 0 8 3.6 8 8v64z', fill: '#FEB027' }) leafer.add(icon) ``` --- ## Pen 画笔元素 像绑画一样绘制不同样式的路径组合。 ```typescript import { Leafer, Pen } from 'leafer-ui' const leafer = new Leafer({ view: window }) const pen = new Pen() // 绘制第一个填充形状 pen.setStyle({ fill: '#FF4B4B', windingRule: 'evenodd' }) pen.roundRect(0, 0, 100, 100, 30) // 圆角矩形 pen.arc(50, 50, 25) // 中间挖空的圆 // 绘制第二个形状(不同位置和颜色) pen.setStyle({ x: 120, y: 0, fill: '#FEB027' }) pen.arc(50, 50, 40) // 绘制带描边的形状 pen.setStyle({ x: 240, y: 0, stroke: '#32cd79', strokeWidth: 5 }) pen.moveTo(0, 50) pen.lineTo(40, 10) pen.lineTo(80, 90) pen.lineTo(20, 90) pen.lineTo(60, 10) pen.closePath() leafer.add(pen) ``` --- ## Text 文本元素 绘制文本,支持多行文本和丰富的文本样式。 ```typescript import { Leafer, Text } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 基础文本 const text = new Text({ x: 100, y: 50, text: 'Hello LeaferJS!', fill: '#32cd79', fontSize: 32, fontWeight: 'bold' }) leafer.add(text) // 多行文本 const multilineText = new Text({ x: 100, y: 120, width: 200, // 设置宽度启用自动换行 text: '这是一段很长的文本,会根据设置的宽度自动换行显示。', fill: '#333', fontSize: 16, lineHeight: { type: 'percent', value: 1.8 } // 行高 180% }) leafer.add(multilineText) // 带样式的文本 const styledText = new Text({ x: 100, y: 250, text: 'Styled Text', fill: '#FF4B4B', fontSize: 24, fontFamily: 'Arial', italic: true, textDecoration: 'under', // 下划线 letterSpacing: 2 // 字间距 }) leafer.add(styledText) // 居中对齐文本 const centeredText = new Text({ x: 100, y: 320, width: 200, height: 50, text: '居中文本', fill: '#FEB027', fontSize: 20, textAlign: 'center', // 水平居中 verticalAlign: 'middle' // 垂直居中 }) leafer.add(centeredText) ``` --- ## Image 图片元素 显示图片,支持 PNG、JPG、SVG 等格式。 ```typescript import { Leafer, Image, Platform } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 基础图片加载 const image = new Image({ x: 100, y: 100, url: '/path/to/image.jpg', draggable: true }) leafer.add(image) // 指定尺寸的图片 const sizedImage = new Image({ x: 300, y: 100, width: 200, height: 150, url: '/path/to/image.jpg', cornerRadius: 20 // 圆角图片 }) leafer.add(sizedImage) // 加载 SVG 字符串 const svgString = ` ` const svgImage = new Image({ x: 100, y: 300, url: Platform.toURL(svgString, 'svg'), draggable: true }) leafer.add(svgImage) // 监听图片加载事件 image.on('image.loaded', () => { console.log('图片加载完成') }) image.on('image.error', () => { console.log('图片加载失败') }) ``` --- ## Group 组元素 将多个元素组合在一起,统一管理位置和变换。 ```typescript import { Leafer, Group, Rect, Ellipse, Text } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 创建组 const group = new Group({ x: 100, y: 100, draggable: true // 整个组可拖拽 }) // 添加子元素 const rect = new Rect({ width: 100, height: 80, fill: '#32cd79' }) const circle = new Ellipse({ x: 50, y: 100, width: 60, height: 60, fill: '#FEB027' }) const label = new Text({ x: 10, y: 30, text: 'Group', fill: 'white', fontSize: 16 }) // 批量添加子元素 group.add([rect, circle, label]) leafer.add(group) // 组的变换会影响所有子元素 group.rotation = 15 group.scale = 1.2 ``` --- ## Box 容器元素 类似 HTML 的 div,支持背景色和子元素。 ```typescript import { Leafer, Box, Ellipse, Text } from 'leafer-ui' const leafer = new Leafer({ view: window, fill: '#333' }) // 创建带背景的容器 const box = new Box({ x: 100, y: 100, width: 200, height: 150, fill: '#32cd79', cornerRadius: 10, stroke: '#fff', strokeWidth: 2 }) // 添加子元素 const circle = new Ellipse({ x: 50, y: 25, width: 100, height: 100, fill: '#FEB027', draggable: true }) box.add(circle) leafer.add(box) ``` --- ## Frame 画板元素 继承自 Box,默认白色背景并裁剪超出内容,适用于设计软件中的画板。 ```typescript import { Leafer, Frame, Rect } from 'leafer-ui' const leafer = new Leafer({ view: window, fill: '#333' }) // 创建画板 const frame = new Frame({ x: 100, y: 100, width: 200, height: 200 // 默认白色背景,overflow: hidden }) // 添加超出画板边界的元素(会被裁剪) const rect = new Rect({ x: 150, y: 50, width: 100, height: 100, fill: '#32cd79', draggable: true }) frame.add(rect) leafer.add(frame) ``` --- ## 填充样式 支持纯色、渐变和图案填充。 ```typescript import { Leafer, Rect, Ellipse } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 纯色填充 const solidRect = new Rect({ x: 50, y: 50, width: 100, height: 100, fill: '#32cd79' }) leafer.add(solidRect) // 线性渐变填充 const linearGradient = new Rect({ x: 200, y: 50, width: 100, height: 100, fill: { type: 'linear', from: { x: 0, y: 0 }, to: { x: 1, y: 1 }, stops: [ { offset: 0, color: '#FF4B4B' }, { offset: 0.5, color: '#FEB027' }, { offset: 1, color: '#32cd79' } ] } }) leafer.add(linearGradient) // 径向渐变填充 const radialGradient = new Ellipse({ x: 350, y: 50, width: 100, height: 100, fill: { type: 'radial', stops: ['#FF4B4B', '#FEB027'] } }) leafer.add(radialGradient) // 图案填充 const patternFill = new Rect({ x: 50, y: 200, width: 150, height: 100, fill: { type: 'image', url: '/path/to/pattern.png', mode: 'repeat' // 'cover' | 'fit' | 'repeat' | 'clip' } }) leafer.add(patternFill) // 多重填充叠加 const multiFill = new Rect({ x: 250, y: 200, width: 100, height: 100, fill: [ { type: 'solid', color: '#32cd79' }, { type: 'linear', stops: ['rgba(255,0,0,0.5)', 'transparent'] } ] }) leafer.add(multiFill) ``` --- ## 描边样式 设置元素的边框样式,支持渐变和虚线。 ```typescript import { Leafer, Rect, Line } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 基础描边 const basicStroke = new Rect({ x: 50, y: 50, width: 100, height: 80, stroke: '#32cd79', strokeWidth: 3 }) leafer.add(basicStroke) // 虚线描边 const dashedStroke = new Rect({ x: 200, y: 50, width: 100, height: 80, stroke: '#FF4B4B', strokeWidth: 3, dashPattern: [10, 5], // [实线长度, 间隔长度] dashOffset: 0 // 虚线起点偏移 }) leafer.add(dashedStroke) // 渐变描边 const gradientStroke = new Rect({ x: 350, y: 50, width: 100, height: 80, stroke: { type: 'linear', stops: ['#FF4B4B', '#FEB027'] }, strokeWidth: 4 }) leafer.add(gradientStroke) // 描边样式属性 const styledLine = new Line({ x: 50, y: 180, width: 200, stroke: '#32cd79', strokeWidth: 8, strokeCap: 'round', // 端点形状: 'none' | 'round' | 'square' strokeJoin: 'round' // 拐角处理: 'miter' | 'bevel' | 'round' }) leafer.add(styledLine) // 描边对齐方式 const innerStroke = new Rect({ x: 50, y: 250, width: 80, height: 80, fill: '#FEB027', stroke: '#333', strokeWidth: 6, strokeAlign: 'inside' // 'inside' | 'center' | 'outside' }) leafer.add(innerStroke) ``` --- ## 阴影效果 为元素添加外阴影和内阴影。 ```typescript import { Leafer, Rect } from 'leafer-ui' const leafer = new Leafer({ view: window, fill: '#f5f5f5' }) // 外阴影 const shadowRect = new Rect({ x: 100, y: 100, width: 120, height: 100, fill: 'white', cornerRadius: 10, shadow: { x: 5, // X 偏移 y: 5, // Y 偏移 blur: 15, // 模糊半径 color: 'rgba(0,0,0,0.3)' // 阴影颜色 } }) leafer.add(shadowRect) // 内阴影 const innerShadowRect = new Rect({ x: 280, y: 100, width: 120, height: 100, fill: '#32cd79', cornerRadius: 10, innerShadow: { x: 5, y: 5, blur: 15, color: 'rgba(0,0,0,0.5)' } }) leafer.add(innerShadowRect) // 多重阴影 const multiShadow = new Rect({ x: 100, y: 260, width: 120, height: 100, fill: 'white', cornerRadius: 10, shadow: [ { x: 0, y: 2, blur: 4, color: 'rgba(0,0,0,0.1)' }, { x: 0, y: 8, blur: 16, color: 'rgba(0,0,0,0.15)' } ] }) leafer.add(multiShadow) ``` --- ## 遮罩功能 使用遮罩实现复杂的裁剪效果。 ```typescript import { Leafer, Group, Ellipse, Image } from 'leafer-ui' const leafer = new Leafer({ view: window }) const group = new Group({ x: 100, y: 100 }) // 创建圆形遮罩 const mask = new Ellipse({ width: 150, height: 150, fill: 'black', // 遮罩需要有填充 mask: true // 设为遮罩 }) // 被遮罩的图片 const image = new Image({ width: 150, height: 150, url: '/path/to/image.jpg' }) // 遮罩元素需要放在被遮罩元素之前 group.add([mask, image]) leafer.add(group) // 圆环遮罩 const ringGroup = new Group({ x: 300, y: 100 }) const ringMask = new Ellipse({ width: 150, height: 150, innerRadius: 0.5, // 内半径创建环形 fill: 'black', mask: true }) const ringImage = new Image({ width: 150, height: 150, url: '/path/to/image.jpg' }) ringGroup.add([ringMask, ringImage]) leafer.add(ringGroup) ``` --- ## 事件监听 完善的事件系统,支持捕获和冒泡阶段。 ```typescript import { Leafer, Rect, PointerEvent, DragEvent } from 'leafer-ui' const leafer = new Leafer({ view: window }) const rect = new Rect({ x: 100, y: 100, width: 200, height: 150, fill: '#32cd79', draggable: true }) leafer.add(rect) // 使用 on() 方法监听事件 rect.on(PointerEvent.ENTER, (e: PointerEvent) => { (e.current as Rect).fill = '#42dd89' }) rect.on(PointerEvent.LEAVE, (e: PointerEvent) => { (e.current as Rect).fill = '#32cd79' }) // 监听点击事件 rect.on(PointerEvent.TAP, (e: PointerEvent) => { console.log('点击位置:', e.x, e.y) }) // 监听拖拽事件 rect.on(DragEvent.START, () => console.log('开始拖拽')) rect.on(DragEvent.DRAG, (e: DragEvent) => { console.log('拖拽中,移动距离:', e.moveX, e.moveY) }) rect.on(DragEvent.END, () => console.log('结束拖拽')) // 使用字符串监听 rect.on('pointer.down', () => console.log('按下')) rect.on('pointer.up', () => console.log('抬起')) // 只监听一次 rect.once('pointer.tap', () => console.log('只触发一次')) // 移除事件 const handler = () => console.log('handler') rect.on('pointer.tap', handler) rect.off('pointer.tap', handler) ``` --- ## 初始化事件 在创建元素时直接配置事件监听。 ```typescript import { Leafer, Rect, PointerEvent } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 通过 event 属性初始化事件 const rect = Rect.one({ fill: '#32cd79', draggable: true, event: { [PointerEvent.ENTER]: (e: PointerEvent) => { (e.current as Rect).fill = '#42dd89' }, [PointerEvent.LEAVE]: (e: PointerEvent) => { (e.current as Rect).fill = '#32cd79' }, [PointerEvent.TAP]: () => { console.log('被点击了') } } }, 100, 100, 200, 150) leafer.add(rect) ``` --- ## 交互状态插件 实现 hover、press、selected 等交互状态样式,需安装 @leafer-in/state 插件。 ```typescript import { Leafer, Rect } from 'leafer-ui' import '@leafer-in/state' // 导入交互状态插件 const leafer = new Leafer({ view: window }) // 使用交互状态样式 const button = new Rect({ x: 100, y: 100, width: 150, height: 50, fill: '#32cd79', cornerRadius: 8, cursor: 'pointer', hoverStyle: { // 鼠标悬停样式 fill: '#42dd89', scale: 1.05 }, pressStyle: { // 鼠标按下样式 fill: '#22bd69', scale: 0.98 } }) leafer.add(button) // 可选中元素 const selectable = new Rect({ x: 100, y: 200, width: 100, height: 100, fill: '#FEB027', cornerRadius: 8, cursor: 'pointer', selectedStyle: { // 选中样式 stroke: '#FF4B4B', strokeWidth: 3 } }) selectable.on('tap', () => { selectable.selected = !selectable.selected }) leafer.add(selectable) // 自定义状态 const stateRect = new Rect({ x: 250, y: 200, width: 100, height: 100, fill: '#79CB4D', states: { active: { fill: '#FF4B4B', scale: 1.1 }, warning: { fill: '#FEB027' }, disabled: { fill: '#ccc', opacity: 0.5 } } }) stateRect.state = 'active' // 切换状态 leafer.add(stateRect) ``` --- ## 动画插件 创建丰富的动画效果,需安装 @leafer-in/animate 插件。 ```typescript import { Leafer, Rect } from 'leafer-ui' import { Animate } from '@leafer-in/animate' const leafer = new Leafer({ view: window }) const rect = new Rect({ x: 50, y: 100, width: 50, height: 50, cornerRadius: 25, fill: '#32cd79' }) leafer.add(rect) // 创建摇摆动画 new Animate( rect, { x: 400, cornerRadius: 0 }, // 目标状态 { duration: 1, // 时长(秒) swing: true // 摇摆循环 } ) // 颜色过渡动画 const colorRect = new Rect({ x: 50, y: 200, width: 50, height: 50, fill: '#32cd79' }) leafer.add(colorRect) new Animate( colorRect, { x: 400, fill: '#FF4B4B' }, { duration: 2, swing: true, easing: 'ease-in-out' } ) // 关键帧动画 const keyframeRect = new Rect({ x: 50, y: 300, width: 50, height: 50, cornerRadius: 25, fill: '#FEB027', around: 'center' }) leafer.add(keyframeRect) new Animate( keyframeRect, [ { style: { x: 150, scaleX: 2 }, duration: 0.5 }, { style: { x: 50, scaleX: 1 }, duration: 0.3 }, { style: { x: 400, rotation: 360 }, easing: 'bounce-out' }, { x: 50, rotation: 0 } ], { duration: 3, loop: true, join: true // 加入初始状态作为起始帧 } ) ``` --- ## 元素动画方法 使用元素的 animate() 方法快速创建动画。 ```typescript import { Leafer, Rect } from 'leafer-ui' import '@leafer-in/animate' const leafer = new Leafer({ view: window }) const rect = new Rect({ x: 100, y: 100, width: 100, height: 100, fill: '#32cd79' }) leafer.add(rect) // 使用 animate() 方法 const animation = rect.animate( { x: 400, rotation: 180, fill: '#FF4B4B' }, { duration: 2, easing: 'ease-out' } ) // 控制动画 setTimeout(() => animation.pause(), 1000) // 暂停 setTimeout(() => animation.play(), 2000) // 继续 setTimeout(() => animation.seek(0.5), 3000) // 跳转到50% // 监听动画事件 animation.on('completed', () => console.log('动画完成')) ``` --- ## App 应用结构 创建多层 Leafer 引擎协同工作的应用结构。 ```typescript import { App, Frame, Rect } from 'leafer-ui' import '@leafer-in/editor' // 图形编辑器 import '@leafer-in/viewport' // 视口交互 // 创建应用(自动创建 tree 和 sky 层) const app = new App({ view: window, fill: '#333', tree: { type: 'design' }, // 主内容层 sky: {} // 编辑器层 }) // 配置图形编辑器 app.editor = app.editor || {} // 在 tree 层添加内容 const frame = new Frame({ x: 100, y: 100, width: 400, height: 300, fill: 'white' }) // 添加可编辑的元素 frame.add(Rect.one({ editable: true, // 启用编辑 fill: '#32cd79', cornerRadius: 20 }, 50, 50, 100, 100)) frame.add(Rect.one({ editable: true, fill: '#FEB027', cornerRadius: 20 }, 200, 50, 100, 100)) app.tree.add(frame) ``` --- ## 图形编辑器 使用图形编辑器实现专业的图形编辑功能,需安装 @leafer-in/editor 插件。 ```typescript import { App, Rect, Ellipse } from 'leafer-ui' import '@leafer-in/editor' import '@leafer-in/viewport' const app = new App({ view: window, editor: {} // 启用编辑器 }) // 添加可编辑元素 app.tree.add(Rect.one({ editable: true, fill: '#FEB027', cornerRadius: [20, 0, 0, 20] }, 100, 100, 150, 100)) app.tree.add(Ellipse.one({ editable: true, fill: '#32cd79' }, 300, 100, 100, 100)) // 编辑器 API const editor = app.editor // 选中元素 editor.select(app.tree.children[0]) // 多选 editor.target = [app.tree.children[0], app.tree.children[1]] // 取消选择 editor.cancel() // 监听编辑器事件 editor.on('select', (e) => { console.log('选中元素:', e.target) }) editor.on('EditorMoveEvent.MOVE', (e) => { console.log('移动距离:', e.moveX, e.moveY) }) ``` --- ## 自动布局 Flow 实现类似 Flex 的自动布局,需安装 @leafer-in/flow 插件。 ```typescript import { Leafer, Box } from 'leafer-ui' import { Flow } from '@leafer-in/flow' const leafer = new Leafer({ view: window }) // 创建自动布局容器 const flow = new Flow({ x: 50, y: 50, width: 300, height: 200, fill: '#f5f5f5', flow: 'x', // 布局方向: 'x' | 'y' gap: 10, // 子元素间距 padding: 15, // 内边距 flowAlign: 'center', // 对齐方式 children: [ new Box({ width: 60, height: 40, fill: '#FF4B4B' }), new Box({ width: 60, height: 60, fill: '#FEB027' }), new Box({ width: 60, height: 50, fill: '#32cd79' }) ] }) leafer.add(flow) // 自动换行布局 const wrapFlow = new Flow({ x: 50, y: 300, width: 200, fill: '#f5f5f5', flowWrap: true, // 启用自动换行 gap: { x: 10, y: 15 }, // 分别设置横向和纵向间距 padding: 15, children: [ new Box({ width: 50, height: 40, fill: '#FF4B4B' }), new Box({ width: 50, height: 40, fill: '#FEB027' }), new Box({ width: 50, height: 40, fill: '#32cd79' }), new Box({ width: 50, height: 40, fill: '#79CB4D' }), new Box({ width: 50, height: 40, fill: '#4DCBFF' }) ] }) leafer.add(wrapFlow) ``` --- ## 视口缩放平移 实现画布的缩放和平移功能,需安装 @leafer-in/viewport 插件。 ```typescript import { App, Rect } from 'leafer-ui' import '@leafer-in/viewport' const app = new App({ view: window, tree: { type: 'viewport' } // 启用视口交互 }) // 添加一些内容 for (let i = 0; i < 10; i++) { app.tree.add(Rect.one({ fill: `hsl(${i * 36}, 70%, 60%)`, draggable: true }, i * 120, 100, 100, 100)) } // 手动控制视口 const zoomLayer = app.zoomLayer // 平移视图 zoomLayer.x = 100 zoomLayer.y = 50 // 缩放视图 zoomLayer.scale = 1.5 // 围绕某点缩放 zoomLayer.scaleOf({ x: 200, y: 200 }, 2) // 操作说明: // - 移动端/触摸板: 双指滑动平移,双指捏合缩放 // - 鼠标: 滚轮纵向滚动,Shift+滚轮横向滚动 // - 缩放: Ctrl/Command + 滚轮 ``` --- ## 导出功能 导出元素或画布为图片、JSON 等格式,需安装 @leafer-in/export 插件。 ```typescript import { Leafer, Rect, Group } from 'leafer-ui' import '@leafer-in/export' const leafer = new Leafer({ view: window }) const group = new Group({ x: 50, y: 50 }) group.add(new Rect({ width: 100, height: 100, fill: '#32cd79' })) group.add(new Rect({ x: 50, y: 50, width: 100, height: 100, fill: '#FEB027' })) leafer.add(group) // 导出为 PNG async function exportPNG() { const result = await group.export('png') console.log('PNG data:', result.data) } // 导出为 JPG 并指定质量 async function exportJPG() { const result = await group.export('jpg', { quality: 0.8 }) console.log('JPG data:', result.data) } // 导出为 JSON async function exportJSON() { const result = await group.export('json') console.log('JSON:', result.data) } // 下载文件 async function downloadImage() { await group.export('my-graphic.png', { pixelRatio: 2, // 2倍图 padding: 20 // 内边距 }) } // 导出缩略图 async function exportThumbnail() { const result = await leafer.export('png', { size: { width: 200 }, // 指定宽度,高度自适应 screenshot: true // 截图模式 }) return result.data } // 截图特定区域 async function screenshotArea() { const result = await leafer.export('png', { screenshot: { x: 50, y: 50, width: 200, height: 150 } }) return result.data } ``` --- ## JSON 导入导出 将元素导出为 JSON 或从 JSON 创建元素。 ```typescript import { Leafer, Group, Rect } from 'leafer-ui' const leafer = new Leafer({ view: window }) // 从 JSON 创建元素 const json = { tag: 'Group', x: 100, y: 100, children: [ { tag: 'Rect', width: 100, height: 80, fill: '#32cd79', draggable: true }, { tag: 'Ellipse', x: 50, y: 50, width: 60, height: 60, fill: '#FEB027' }, { tag: 'Text', x: 10, y: 30, text: 'Hello', fill: 'white', fontSize: 16 } ] } // 直接添加 JSON 数据 leafer.add(json) // 导出元素为 JSON const group = leafer.children[0] as Group const exportedJson = group.toJSON() console.log(exportedJson) // 导出为 JSON 字符串 const jsonString = group.toString() console.log(jsonString) // 使用 set() 更新元素 group.set({ x: 200, rotation: 45 }) ``` --- ## 坐标转换 在不同坐标系之间转换坐标点。 ```typescript import { Leafer, Rect, Group, PointerEvent } from 'leafer-ui' const leafer = new Leafer({ view: window }) const group = new Group({ x: 100, y: 100, rotation: 30, scale: 1.5 }) const rect = new Rect({ x: 50, y: 50, width: 100, height: 80, fill: '#32cd79' }) group.add(rect) leafer.add(group) // 监听点击,演示坐标转换 rect.on(PointerEvent.TAP, (e: PointerEvent) => { // 世界坐标(浏览器视口坐标) const worldPoint = { x: e.x, y: e.y } console.log('世界坐标:', worldPoint) // 转换为元素内部坐标 const innerPoint = rect.getInnerPoint(worldPoint) console.log('内部坐标:', innerPoint) // 转换为本地坐标(相对父元素) const localPoint = rect.getLocalPoint(worldPoint) console.log('本地坐标:', localPoint) // 转换为 page 坐标(场景坐标) const pagePoint = rect.getPagePoint(worldPoint) console.log('Page坐标:', pagePoint) }) // 内部坐标转世界坐标 const innerPoint = { x: 50, y: 40 } const worldPoint = rect.getWorldPoint(innerPoint) console.log('内部转世界:', worldPoint) // 获取元素边界 console.log('boxBounds:', rect.boxBounds) console.log('worldBoxBounds:', rect.worldBoxBounds) ``` --- ## 查找元素 查找和定位画布中的元素,需安装 @leafer-in/find 插件。 ```typescript import { Leafer, Group, Rect, Ellipse } from 'leafer-ui' import '@leafer-in/find' const leafer = new Leafer({ view: window }) // 创建带 id 和 className 的元素 const rect1 = new Rect({ id: 'main-rect', className: 'shape', x: 50, y: 50, width: 100, height: 80, fill: '#32cd79' }) const rect2 = new Rect({ id: 'secondary-rect', className: 'shape', x: 200, y: 50, width: 80, height: 80, fill: '#FEB027' }) const circle = new Ellipse({ id: 'my-circle', className: 'shape', x: 350, y: 50, width: 80, height: 80, fill: '#FF4B4B' }) leafer.add([rect1, rect2, circle]) // 通过 id 查找 const foundById = leafer.findId('main-rect') console.log('通过 id 查找:', foundById) // 通过 className 查找(返回数组) const foundByClass = leafer.find('.shape') console.log('通过 className 查找:', foundByClass) // 通过 tag 查找 const foundByTag = leafer.findTag('Rect') console.log('通过 tag 查找:', foundByTag) // 通过函数条件查找 const foundByCondition = leafer.find((item) => item.width > 80) console.log('条件查找:', foundByCondition) // 查找单个元素 const single = leafer.findOne('.shape') console.log('查找单个:', single) // 通过坐标拾取元素 const picked = leafer.pick({ x: 100, y: 90 }) console.log('坐标拾取:', picked) ``` --- LeaferJS 是一个功能完善的 Canvas 2D 图形引擎,适用于构建各类可视化应用。它提供了丰富的基础图形元素、灵活的样式系统和完整的事件机制,使得开发者可以轻松实现从简单图形展示到复杂图形编辑器的各种需求。通过插件机制,可以按需扩展动画、布局、编辑等高级功能,保持核心库的轻量。 在实际开发中,建议根据项目需求选择合适的插件组合:基础绑图只需 leafer-ui 核心库;需要交互动画时添加 @leafer-in/animate 和 @leafer-in/state 插件;构建设计工具时引入 @leafer-in/editor、@leafer-in/viewport 等插件。LeaferJS 的 API 设计直观、文档完善,配合 TypeScript 类型支持,能够显著提升开发效率。