Skip to content

Editor ​

图形编辑器,可移动、缩放、旋转、倾斜,支持多选、框选、打组、锁定、层级,可配置样式。

支持自定义 编辑工具、 内部编辑器。

关键属性 ​

target:UI | UI[] ​

设置需要编辑的元素, 默认通过 编辑选择器 自动选取 editable 元素(不用设置 draggable )。

hoverTarget:UI ​

设置 hover 状态的元素, 默认通过 编辑选择器 自动选取 editable 元素。

visible: boolean ​

是否显示编辑器, 默认为 true。

隐藏后,交互功能也将禁用。

hittable: boolean ​

编辑器是否响应交互事件,默认为 true。

设为 false 后,将禁用编辑器交互。

配置属性 ​

config: IEditorConfig ​

全局编辑器配置,实例化时传入,可实时修改(调用 updateEditTool() 方法更新)。

mergeConfig: IEditorConfig ​

实际使用的编辑器配置(只读),合并了 config 与元素的 editConfig。

只读属性 ​

editing: boolean ​

是否处于编辑状态,选择元素后即进入编辑状态。

innerEditing: boolean ​

是否处于内部编辑状态,双击单个元素进入内部编辑状态(有内部编辑器的情况下)。

groupOpening: boolean ​

是否处于打开组状态,双击组可进入打开状态,方便选择组内元素。

list: UI[] ​

当前选中的元素列表,未选中时为空数组。

multiple: boolean ​

是否选中了多个元素。

single: boolean ​

是否只选中了单个元素。

dragging: boolean ​

是否正在拖拽编辑器,包含拖拽控制点、边。

高性能列表 ​

leafList: LeafList ​

当前选中的元素列表, 未选中时为空列表对象.

openedGroupList: LeafList ​

当前处于打开状态的组列表, 未选中时为空列表对象.

辅助属性 ​

element: UI ​

选中元素的唯一代表。

单选时为选中元素, 多选时为模拟元素(代替多个元素),一般用来同步布局编辑框。

editBox: EditBox ​

编辑框,负责编辑框的显示与交互。

buttons: Group ​

按钮组,放置旋转控制点及自定义按钮,整体 around 对齐, 位于编辑器底部,可以 进行配置。

editTool: EditTool ​

当前使用的编辑工具。

用来编辑元素的尺寸、外形,选中元素时会自动载入,可 自定义编辑工具。

innerEditor: InnerEditor ​

当前使用的内部编辑器。

用来编辑文本、路径等内部细节,通过双击元素打开, 可 自定义内部编辑器

selector: IEditSelect ​

选择器,负责单选、多选、框选元素的交互,渲染元素选中、hover 线框。

关键方法 ​

选中元素 ​

select ( target:UI | UI[] ) ​

选中元素。

cancel ( ) ​

取消选中元素。

hasItem ( item: UI ): boolean ​

是否已选中某个元素。

addItem ( item: UI ) ​

新增一个元素到选中列表。

removeItem ( item:UI ) ​

从选中列表中移出元素。

打组 ​

group ( custom: IGroup | IGroupInputData): IGroup ​

将选中的元素进行打组,支持传入一个自定义的 Group 实例 或 json 对象。

新的 group 将增加如下属性:

ts
group.editable = true
group.hitChildren = false

ungroup ( ): UI[] ​

将选中的元素进行解组。

开关组 ​

openGroup ( IGroup ) ​

打开组, 模拟双击打开组的功能。

closeGroup ( IGroup ) ​

关闭组。

内部编辑 ​

openInnerEditor( target?: UI ) ​

打开元素的内部编辑器。

closeInnerEditor() ​

关闭内部编辑器。

锁定 ​

lock ( ) ​

锁定选中的元素。

元素可以被单选,但是不能编辑。

unlock ( ) ​

解锁选中的元素。

层级 ​

toTop ( ) ​

移动选中元素到最顶层(所属 Group 中)。

toBottom ( ) ​

移动选中元素到最底层(所属 Group 中)。

更新 ​

update ( ) ​

手动更新编辑器的布局、样式等。

updateEditTool() ​

更新编辑工具,选择元素后自动调用此方法。

手动操作 ​

move ( x: number | IPointData, y = 0): void ​

位移选中元素 增量操作, 支持直接传入 坐标对象。

scaleOf ( origin: IPointData | IAlign, scaleX: number, scaleY = scaleX) ​

以 element 元素的 inner 坐标 origin 为原点,缩放选中元素 增量操作。

rotateOf ( origin: IPointData | IAlign, rotation: number) ​

以 element 元素的 inner 坐标 origin 为原点,旋转选中元素 增量操作。

skewOf ( origin: IPointData | IAlign, skewX: number, skewY = 0) ​

以 element 元素的 inner 坐标 origin 为原点,倾斜选中元素 增量操作。

ts
// 当前选中元素
const { element } = app.editor
const box = element.boxBounds

// 元素的实际内容中心点
const center = {
  x: box.x + box.width / 2,
  y: box.y + box.height / 2,
}

// 想缩放到指定 scale, 需除以元素的 scale,如下:
app.editor.scaleOf(center, scale / element.scale)

// 想旋转到指定 rotation, 需减去元素的 rotation,如下:
app.editor.rotateOf(center, rotation - element.rotation)

// 想倾斜到指定 skewX, 需减去元素的 skewX,如下:
app.editor.skewOf(center, skewX - element.skewX)

配置 ​

编辑器配置 ​

快捷键 ​

按住Ctrl / Command 键:

将光标移动至四条边上,拖动可倾斜元素。

将光标移动至控制点上,拖动可旋转元素。

按住 Alt 键 :中心缩放 / 倾斜 (Alt + Shift 键可组合)。

按住 Shift 键:多选 / 固定比例缩放 / 固定方向移动 / 以对角为中心旋转。

调整大小 ​

编辑器默认通过修改元素宽高、路径坐标来调整大小。

同时也支持通过修改缩放来调整大小, 了解 editSize。

历史记录 ​

交互操作可通过监听 editor 的 drag.start 和 drag.end 事件作为记录历史状态的时机。

操作图形会同时产生多个属性的变更,可以在 app.tree 上监听收集元素的变化做历史记录。

ChildEvent ​

PropertyEvent ​

DragEvent ​

事件 ​

编辑器事件,手动操作也会触发。

EditorEvent ​

EditorMoveEvent ​

EditorScaleEvent ​

EditorRotateEvent ​

EditorSkewEvent ​

EditorGroupEvent ​

InnerEditorEvent ​

编辑工具 ​

用来编辑元素的尺寸、外形,选中元素时会自动载入。

内置了两种编辑工具,可为不同图形元素扩展编辑工具。

EditTool ​

LineEditTool ​

自定义编辑工具 ​

内部编辑器 ​

用来编辑文本、路径等内部细节,通过双击元素打开。

可扩展路径编辑器、文本编辑器。

InnerEditor ​

自定义内部编辑器 ​

继承 ​

Group ​

API ​

Editor ​

示例 ​

点击选中元素 ​

元素必需要有 editable 属性才能被选取, 可通过 app.editor 快速访问编辑器实例。

ts
import { App, Rect } from 'leafer-ui'
import '@leafer-in/editor'

const app = new App({ view: window, editor: {} })

const rect1 = Rect.one({ editable: true, fill: '#FEB027', cornerRadius: [20, 0, 0, 20] }, 100, 100) 
const rect2 = Rect.one({ editable: true, fill: '#FFE04B', cornerRadius: [0, 20, 20, 0] }, 300, 100)

app.tree.add(rect1)
app.tree.add(rect2)

显示底部旋转控制点 ​

默认会继承基础样式,可以进一步 设置 旋转控制点的样式。

ts
import { App, Rect } from 'leafer-ui'
import '@leafer-in/editor'

const app = new App({  
    view: window,
    editor: { rotatePoint: {} }
})

const rect = Rect.one({ editable: true, fill: 'rgb(50,205,121)', cornerRadius: 30 }, 100, 100)
app.tree.add(rect)

app.editor.target = rect

添加底部固定按钮 ​

元素旋转、翻转后仍保持固定方位,可以 设置 按钮组的方位。

ts
import { App, Rect, Box, PointerEvent } from 'leafer-ui'
import '@leafer-in/editor'

const app = new App({ 
    view: window,
    editor: { buttonsFixed: true }
})

const rect = Rect.one({ editable: true, fill: 'rgb(50,205,121)' }, 100, 100)
app.tree.add(rect)
app.tree.add(Rect.one({ editable: true, fill: 'rgb(50,205,121)' }, 100, 300))

const button = Box.one({  // 添加移除按钮
    around: 'center',
    fill: '#FEB027',
    cornerRadius: 20,
    cursor: 'pointer',
    children: [{ tag: 'Text', fill: 'white', text: '移除', padding: [7, 10] }]
})

app.editor.buttons.add(button)

button.on(PointerEvent.TAP, () => { // 点击删除元素,并取消选择
    app.editor.list.forEach(rect => rect.remove())
    app.editor.target = null
})

app.editor.target = rect

显示中间控制点,并修改样式 ​

默认会继承基础样式、旋转角度, 可以精确 设置 每个控制点的样式。

ts
import { App, Rect } from 'leafer-ui'
import '@leafer-in/editor'

const app = new App({  
    view: window,
    editor: {
        point: { cornerRadius: [0, 0, 10, 0] },
        middlePoint: { width: 12, height: 4, cornerRadius: 2 }
    }
})

const rect = Rect.one({ editable: true, fill: 'rgb(50,205,121)', cornerRadius: 30 }, 100, 100)
app.tree.add(rect)

app.editor.target = rect

监听选择事件 ​

ts
import { App, Rect } from 'leafer-ui'
import { EditorEvent } from '@leafer-in/editor'

const app = new App({
    view: window,
    editor: {}
})

app.tree.add(Rect.one({ fill: 'rgb(50,205,121)', editable: true }, 100, 100))
app.tree.add(Rect.one({ fill: 'rgb(50,205,121)', editable: true }, 300, 100))

app.editor.on(EditorEvent.SELECT, (e: EditorEvent) => { 
    console.log(e.editor.list)
})

手动旋转元素 ​

ts
import { App, Rect } from 'leafer-ui'
import '@leafer-in/editor'

const app = new App({ view: window, editor: {} })

const rect = Rect.one({ editable: true, fill: '#FEB027', cornerRadius: [20, 0, 0, 20] }, 100, 100)

app.tree.add(rect)
app.tree.add(Rect.one({ editable: true, fill: '#FFE04B', rotation: 10, cornerRadius: [0, 20, 20, 0] }, 300, 100))


app.editor.select(rect) // 选中 rect

setTimeout(() => {

    // 手动旋转到45度 
    const rotation = 45

    // 围绕中心旋转到指定 rotation, 需减去元素的 rotation,如下:
    app.editor.rotateOf('center', rotation - rect.rotation)

}, 2000)

创建图形模式 ​

ts
import { App, DragEvent, Rect } from 'leafer-ui'
import '@leafer-in/editor'


const app = new App({ view: window, editor: {} })

app.tree.add(Rect.one({ editable: true, fill: '#FEB027', cornerRadius: [20, 0, 0, 20] }, 100, 100))
app.tree.add(Rect.one({ editable: true, fill: '#FFE04B', rotation: 10, cornerRadius: [0, 20, 20, 0] }, 300, 100))

app.editor.select(app.tree.children[0])

setTimeout(() => {

    // 2秒后进入创建图形模式 
    app.editor.visible = false
    app.tree.hitChildren = false

    // 创建图形(拖拽)
    let rect: Rect

    app.on(DragEvent.START, () => {
        rect = new Rect({ editable: true, fill: 'rgb(50,205,121)' })
        app.tree.add(rect)
    })

    app.on(DragEvent.DRAG, (e: DragEvent) => {
        if (rect) rect.set(e.getPageBounds())
    })

}, 2000)

Released under the MIT License.