region-editor
v1.0.15
Published
基于 Vue 3 的区域绘图编辑器,支持 Canvas 绘制直线/矩形,自动识别封闭区域并设置颜色和标签
Maintainers
Readme
region-editor
基于 Vue 3 的区域绘图编辑器,在 Canvas 画布上绘制直线/矩形,自动识别封闭区域并支持颜色标注和标签。零第三方运行时依赖,所有几何算法自实现。
功能特性
- 直线 / 矩形绘制工具
- 吸附功能:自动对齐到已有顶点或线段
- 自动识别封闭区域,并为每个区域独立设置填充颜色(支持 rgba 透明度)和文字标签
- 通过新增线段对已有区域进行分割
- Alt + 拖拽顶点,实时变形图形
- 撤销 / 重做(Ctrl+Z / Ctrl+Y)
- 绘制 / 只读双模式(支持 prop 外部控制)
- 滚轮缩放(以鼠标位置为中心),中键 / Alt+拖拽平移画布
- 右键菜单:设置标签、删除元素,支持自定义菜单项
- Delete / Backspace 键删除选中元素
- 数据导入导出(通过 API 方法)
安装
npm install region-editorVue 3 为 peer dependency,请确保项目中已安装:
npm install vue快速开始
<template>
<DrawingEditor
ref="editorRef"
:readonly="false"
:contextMenuItems="menuItems"
@region-select="onRegionSelect"
@context-menu-action="onContextMenuAction"
/>
</template>
<script setup>
import DrawingEditor from 'region-editor'
import 'region-editor/dist/style.css'
import { ref } from 'vue'
const editorRef = ref(null)
const menuItems = [
{ id: 'export', label: '📤 导出数据' },
{ id: 'delete-all', label: '🗑 删除全部', danger: true },
]
function onRegionSelect({ id, extraData, color, area }) {
console.log('选中区域:', id, extraData, area)
}
function onContextMenuAction({ action, region, line }) {
if (action === 'export') {
const json = editorRef.value.getJson()
console.log(json)
}
}
</script>API
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| readonly | Boolean | false | 是否初始为只读模式 |
| contextMenuItems | Array | [] | 自定义右键菜单项,每项 { id, label, danger? } |
Events
| 事件名 | 触发时机 | 参数 |
|--------|---------|------|
| @region-select | 选中封闭区域时 | { id, extraData, color, area, edgeIds } |
| @region-deselect | 取消选中时 | { id } |
| @context-menu-action | 点击自定义菜单项时 | { action, region?, line? } |
| @mode-change | 切换绘制/只读模式时 | { mode: 'draw' \| 'readonly' } |
方法(通过 ref 调用)
| 方法 | 说明 |
|------|------|
| getData() | 返回完整绘制数据对象 |
| getJson() | 返回完整绘制数据的 JSON 字符串 |
| getTag() | 返回所有区域的标签信息 [{ id, extraData, area }] |
| selectedRegion | 当前选中区域的响应式引用,可直接读写属性,同步渲染 |
| getSelectedRegion() | 返回当前选中区域对象(深拷贝),无选中时返回 null |
| updateSelectedRegion(props) | 更新选中区域属性,同步渲染,参数见下方 |
| setData(jsonObj) | 从数据对象还原绘制内容 |
// 获取数据
const data = editorRef.value.getData()
// 从数据还原
editorRef.value.setData(data)数据格式
{
"version": 1,
"lines": [
{ "id": "line_xxx", "start": { "x": 100, "y": 200 }, "end": { "x": 300, "y": 200 } }
],
"regions": [
{
"id": "region_xxx",
"edgeIds": ["line_xxx", "..."],
"color": "rgba(255, 182, 193, 0.35)",
"extraData": { "label": ["第一行", "第二行"] },
"area": 40000
}
],
"viewport": { "zoom": 1, "panX": 0, "panY": 0 }
}修改选中区域
选中区域后有两种方式修改其属性:
方式一:直接读写 selectedRegion(响应式引用)
const region = editorRef.value.selectedRegion
if (region) {
region.color = 'rgba(0, 255, 127, 0.5)'
region.extraData.label = ['第一行', '第二行']
}方式二:updateSelectedRegion 方法(自动记录撤销)
// label 支持字符串数组(每项一行),也可以是单个字符串
editorRef.value.updateSelectedRegion({
color: 'rgba(0, 255, 127, 0.5)',
label: ['测试区域', '编号001'],
})
// 也可以合并自定义 extraData 字段
editorRef.value.updateSelectedRegion({
extraData: { label: ['新标签'], priority: 'high', owner: '张三' },
})updateSelectedRegion 参数说明:
| 字段 | 类型 | 说明 |
|------|------|------|
| color | String | 区域填充颜色(rgba 字符串) |
| label | String[] | 多行标签文本数组,一项绘制一行 |
| extraData | Object | 合并到 extraData 的自定义字段 |
自定义右键菜单
通过 contextMenuItems prop 传入自定义菜单项,点击时触发 @context-menu-action 事件:
<template>
<DrawingEditor
:contextMenuItems="[
{ id: 'custom-action', label: '🔧 自定义操作' },
{ id: 'danger-action', label: '⚠ 危险操作', danger: true },
]"
@context-menu-action="handleAction"
/>
</template>
<script setup>
function handleAction({ action, region, line }) {
switch (action) {
case 'custom-action':
// region 为选中区域对象,line 为选中线段对象
break
case 'danger-action':
break
}
}
</script>自定义菜单项在只读模式下也会显示(仅自定义项,不含内置的设置标签/删除等编辑项)。
操作说明
| 操作 | 方式 | |------|------| | 绘制直线/矩形 | 工具栏选择工具,在画布上拖拽 | | 选中线段 | 点击线段 | | 选中区域 | 点击封闭区域内部 | | 设置区域标签 | 右键区域 → 设置标签 | | 移动顶点 | Alt + 左键拖拽顶点 | | 平移画布 | 中键拖拽 / Alt + 左键拖拽空白处 | | 缩放 | 滚轮 | | 删除 | Delete / Backspace 键 | | 撤销/重做 | Ctrl+Z / Ctrl+Y | | 右键菜单 | 右键点击线段或区域 | | 模式切换 | 工具栏「绘制」/「只读」按钮 |
浏览器兼容性
支持所有现代浏览器(Chrome、Firefox、Safari、Edge)。内置三级 UUID 降级策略,同时兼容 HTTPS 和 HTTP 环境:
crypto.randomUUID()→crypto.getRandomValues()→Math.random()
无需任何 polyfill,无其他特殊要求。
License
MIT
