UNPKG

vue3-sketch-ruler

Version:

> 是一个基于 Vue 3 + TypeScript 的标尺组件库,适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。

470 lines (372 loc) 18.4 kB
# vue3-sketch-ruler > 是一个基于 Vue 3 + TypeScript 的标尺组件库,适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。 [![](https://camo.githubusercontent.com/28479a7a834310a667f36760a27283f7389e864a/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f76322d646174657069636b65722e737667)](https://camo.githubusercontent.com/28479a7a834310a667f36760a27283f7389e864a/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f76322d646174657069636b65722e737667) [![build status](https://github.com/kakajun/vue3-sketch-ruler/actions/workflows/gh-pages.yml/badge.svg?branch=master)](https://github.com/kakajun/vue3-sketch-ruler/actions/workflows/gh-pages.yml) [![Cloud Studio Template](https://cs-res.codehub.cn/common/assets/icon-badge.svg)](https://cloudstudio.net/a/21005994397405184?channel=share&sharetype=Markdown) <div align=center> <img src="https://github.com/kakajun/vue3-sketch-ruler/blob/master/packages/docs/src/assets/logo.png" width="392" height="300"> </div> ## 🚀 Features - 💪 Vue 3 Composition API / `<script setup>` - 🔥 基于 TypeScript,类型完整 - 🎯 内置 TransformEngine 变换引擎,零外部依赖 - 🖱️ 多种缩放模式:鼠标中心、视口中心、内容中心 - 📐 可配置参考线(拖拽创建、吸附、锁定) - 🗺️ 内置 Minimap 缩略图导航(支持拖拽视口、点击跳转) - 🔌 插件系统(生命周期钩子 + 自定义渲染器) - 🎨 动画支持:ease-out / damped / exponential / direct - 📦 平台与业务代码通过插槽分离,专注业务即可 ## 🦄 Demo 案例浏览: [https://kakajun.github.io/vue3-sketch-ruler](https://kakajun.github.io/vue3-sketch-ruler) ![image](https://github.com/kakajun/vue3-sketch-ruler/blob/master/packages/docs/src/assets/1.png) [CodePen 示例](https://codepen.io/kakajun/pen/eYwagJb) ## 安装 ```bash npm install --save vue3-sketch-ruler # 或 yarn add vue3-sketch-ruler # 或 pnpm add vue3-sketch-ruler ``` ## 引入方式 ### ESM ```ts import { SketchRuler, Minimap } from 'vue3-sketch-ruler' import type { SketchRulerProps, SketchRulerPlugin } from 'vue3-sketch-ruler' import 'vue3-sketch-ruler/lib/style.css' ``` ### CDN (IIFE) 通过 `<script>` 标签直接引入,挂载到全局变量 `SketchRuler````html <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script src="https://unpkg.com/vue3-sketch-ruler/lib/index.iife.js"></script> <link rel="stylesheet" href="https://unpkg.com/vue3-sketch-ruler/lib/style.css" /> <script> const { SketchRuler: SketchRulerComp } = SketchRuler Vue.createApp({ components: { SketchRuler: SketchRulerComp } }).mount('#app') </script> ``` ### CDN (UMD) UMD 格式兼容 CommonJS、AMD 和浏览器全局变量三种环境: ```html <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script src="https://unpkg.com/vue3-sketch-ruler/lib/index.umd.cjs"></script> <link rel="stylesheet" href="https://unpkg.com/vue3-sketch-ruler/lib/style.css" /> <script> const { SketchRuler: SketchRulerComp } = SketchRuler Vue.createApp({ components: { SketchRuler: SketchRulerComp } }).mount('#app') </script> ``` ## 使用 ### 基础用法 ```vue <template> <div class="wrapper" :style="{ width: width + 'px', height: height + 'px' }"> <SketchRuler ref="sketchRef" v-model:scale="state.scale" :width="width" :height="height" :canvas-width="canvasWidth" :canvas-height="canvasHeight" :thick="state.thick" :lines="state.lines" :is-show-refer-line="state.isShowReferLine" :enable-animation="true" animation-mode="ease-out" @zoomchange="handleZoomChange" @update:lines="handleLinesChange" > <template #default> <div data-type="page" :style="canvasStyle"> <img :src="bgImg" style="width:100%;height:100%" /> </div> </template> <template #toolbar="{ tools, state }"> <div class="btns"> <button @click="tools.reset">还原</button> <button @click="tools.zoomIn">放大</button> <button @click="tools.zoomOut">缩小</button> <button @click="tools.zoomToPreset(1)">100%</button> <span>{{ (state.scale * 100).toFixed(0) }}%</span> </div> </template> </SketchRuler> </div> </template> <script setup lang="ts"> import { reactive, ref } from 'vue' import { SketchRuler } from 'vue3-sketch-ruler' import 'vue3-sketch-ruler/lib/style.css' const sketchRef = ref() const width = 1470 const height = 700 const canvasWidth = 1000 const canvasHeight = 500 const state = reactive({ scale: 1, thick: 20, isShowReferLine: true, lines: { h: [0, 250], v: [0, 500] } }) const canvasStyle = { width: canvasWidth + 'px', height: canvasHeight + 'px' } const handleZoomChange = (detail: { scale: number; x: number; y: number }) => { console.log('zoomchange', detail) } const handleLinesChange = (lines: { h: number[]; v: number[] }) => { console.log('lines changed', lines) } </script> ``` ### 配合 Minimap ```vue <template> <SketchRuler ref="sketchRef" v-model:scale="state.scale" ...> <template #default>...</template> </SketchRuler> <Minimap :content-width="canvasWidth" :content-height="canvasHeight" :viewport-x="viewportOffset.x" :viewport-y="viewportOffset.y" :viewport-width="width" :viewport-height="height" :scale="state.scale" :width="200" :height="150" @navigate="handleNavigate" /> </template> <script setup> import { SketchRuler, Minimap } from 'vue3-sketch-ruler' const sketchRef = ref() const viewportOffset = reactive({ x: 0, y: 0 }) const handleZoomChange = (detail) => { viewportOffset.x = detail.x viewportOffset.y = detail.y } const handleNavigate = (x, y) => { sketchRef.value?.setTransform({ x, y }) } </script> ``` ### 插件系统 ```ts import type { SketchRulerPlugin } from 'vue3-sketch-ruler' const plugins: SketchRulerPlugin[] = [ { name: 'demo-logger', onLineCreate: (ctx) => console.log('line created', ctx.line.id), onLineDelete: (ctx) => console.log('line deleted', ctx.line.id) } ] ``` ## API ### Props | 属性 | 描述 | 类型 | 默认值 | | --- | --- | --- | --- | | width | 容器宽度 | `number` | `1400` | | height | 容器高度 | `number` | `800` | | canvasWidth | 画布宽度 | `number` | `700` | | canvasHeight | 画布高度 | `number` | `700` | | thick | 标尺厚度 | `number` | `16` | | scale | 缩放值(支持 `v-model:scale`) | `number` | `1` | | showRuler | 是否显示标尺 | `boolean` | `true` | | isShowReferLine | 是否显示参考线 | `boolean` | `true` | | lines | 初始化参考线 | `{ h: number[]; v: number[] }` | `{ h: [], v: [] }` | | palette | 标尺样式配置 | `Partial<RulerPalette>` | `{}` | | shadow | 阴影高亮区域 | `{ x, y, width, height }` | `{ x:0, y:0, width:0, height:0 }` | | zoomMode | 缩放原点模式 | `'pointer' \| 'viewport-center' \| 'content-center'` | `'pointer'` | | zoomStep | 缩放步长 | `number` | `0.25` | | minZoom | 最小缩放 | `number` | `0.1` | | maxZoom | 最大缩放 | `number` | `10` | | enableAnimation | 是否启用动画 | `boolean` | `false` | | animationMode | 动画模式 | `'direct' \| 'ease-out' \| 'damped' \| 'exponential'` | `'ease-out'` | | autoCenter | 初始化自动居中 | `boolean` | `true` | | paddingRatio | 自动居中边距比(`0~0.5`) | `number` | `0.2` | | initialOffset | 初始偏移(autoCenter=false 时生效) | `{ x: number; y: number }` | `{ x:0, y:0 }` | | snapThreshold | 吸附阈值 | `number` | `5` | | lockLine | 是否锁定参考线 | `boolean` | `false` | | selfHandle | 自行处理输入事件 | `boolean` | `false` | | showMinorTicks | 是否显示次刻度线 | `boolean` | `false` | | eyeIcon | 左上角眼睛图标 base64 | `string` | 内置图标 | | closeEyeIcon | 左上角闭眼图标 base64 | `string` | 内置图标 | | deleteLabel | 参考线拖出画布时的删除提示 | `string` | `'放开删除'` | | plugins | 插件列表 | `SketchRulerPlugin[]` | `[]` | ### Events | 事件 | 描述 | 回调参数 | | --------------- | ------------------ | ------------------------------ | | update:scale | 缩放值双向绑定 | `number` | | update:offset | 偏移值双向绑定 | `{ x: number; y: number }` | | zoomchange | 缩放/平移变化 | `{ scale, x, y }` | | update:lines | 参考线变化 | `{ h: number[]; v: number[] }` | | update:lockLine | 参考线锁定状态变化 | `boolean` | | onCornerClick | 左上角按钮点击 | `boolean`(参考线显示状态) | ### Slots | 插槽名 | 描述 | 作用域参数 | | --- | --- | --- | | default | 画布内容(**必须用 `<template #default>` 包裹**) | — | | toolbar | 右下角工具栏 | `{ tools: { reset, zoomIn, zoomOut, zoomToPreset, setZoomMode, toggleReferLine }, state: { scale, offset, zoomMode, showReferLine } }` | ### Expose 通过 `ref` 可以调用以下方法: | 方法 | 描述 | | ---------------------------------- | -------------------- | | `setTransform({ x?, y?, scale? })` | 设置变换状态 | | `zoomIn()` | 放大 | | `zoomOut()` | 缩小 | | `reset()` | 重置到初始状态 | | `zoomToPreset(scale)` | 缩放到预设比例 | | `setZoomMode(mode)` | 设置缩放模式 | | `engine` | TransformEngine 实例 | | `guideLines` | 当前参考线数组 | | `cursorClass` | 当前光标类名 | ### Palette | 属性 | 描述 | 默认值 | | -------------------- | -------------- | ---------- | | bgColor | 画布背景 | `#f6f7f9` | | tickColor | 刻度颜色 | `#BABBBC` | | labelColor | 刻度标签颜色 | `#7D8694` | | guideLineColor | 参考线颜色 | `#51d6a9` | | guideLineLockedColor | 锁定参考线颜色 | `#d4d7dc` | | hoverBg | 标签背景色 | `transparent` | | hoverColor | 标签文字色 | `#000` | | borderColor | 尺子边框颜色 | `#eeeeef` | | shadowColor | 阴影高亮色 | `#e9f7fe` | | guideLineStyle | 参考线样式 | `'dashed'` | | guideLineWidth | 参考线宽度 | `1` | | labelEnabled | 是否显示标签 | `true` | ## Minimap API | 属性 | 描述 | 类型 | 默认值 | | -------------- | ----------- | -------- | ------ | | contentWidth | 内容宽度 | `number` | — | | contentHeight | 内容高度 | `number` | — | | viewportX | 视口 X 偏移 | `number` | — | | viewportY | 视口 Y 偏移 | `number` | — | | viewportWidth | 视口宽度 | `number` | — | | viewportHeight | 视口高度 | `number` | — | | scale | 缩放比例 | `number` | — | | width | 缩略图宽度 | `number` | `200` | | height | 缩略图高度 | `number` | `150` | | 事件 | 描述 | 回调参数 | | --------- | -------------- | ------------------------ | | navigate | 导航到指定位置 | `(x: number, y: number)` | | dragstart | 开始拖拽 | — | | dragend | 结束拖拽 | — | ## 2.x → 3.x 迁移指南 v3.x 是架构重构版本,内置 TransformEngine 替代了外部 `simple-panzoom` 依赖,并引入了 Minimap、插件系统、动画系统等全新能力。以下是核心差异与迁移要点: ### 主要 Breaking Changes | 变更项 | 2.x 写法 | 3.x 写法 | 说明 | | --- | --- | --- | --- | | **组件名** | `<SketchRule>` / `<sketch-rule>` | `<SketchRuler>` | 统一为 PascalCase 完整拼写 | | **导入方式** | `import SketchRule from 'vue3-sketch-ruler'` | `import { SketchRuler } from 'vue3-sketch-ruler'` | 改为命名导出,同时仍保留默认导出兼容 | | **工具栏插槽** | `#btn="{ reset, zoomIn, zoomOut }"` | `#toolbar="{ tools, state }"` | `tools` 包含 `reset``zoomIn``zoomOut``zoomToPreset``setZoomMode``toggleReferLine``state` 包含 `scale``offset``zoomMode``showReferLine` | | **缩放事件** | `@zoomStart` | `v-model:scale` / `@update:scale` | 支持双向绑定,无需手动监听缩放开始 | | **参考线事件** | `@handleLine` | `@update:lines` | 统一为 `update:` 风格事件 | | **偏移事件** | 无 | `@update:offset` / `@zoomchange` | 3.x 新增,返回 `{ scale, x, y }` | | **锁定事件** | 无 | `v-model:lockLine` / `@update:lockLine` | 3.x 新增双向绑定 | | **缩放控制** | `panzoomOption` | `zoomMode``zoomStep``minZoom``maxZoom` | 移除 `panzoomOption`,改为内置引擎直接配置 | | **动画系统** | 无 | `enableAnimation``animationMode` | 3.x 新增,支持 `ease-out``damped``exponential``direct` | | **自动居中** | 依赖 panzoom 的 `startX/startY` | `autoCenter``paddingRatio``initialOffset` | `autoCenter``true` 时按 `paddingRatio` 留白后自动居中 | | **阴影文字** | `showShadowText` | 移除 | 3.x 已移除该属性 | | **palette 属性** | `lineType``lineColor``longfgColor``fontColor` | `guideLineStyle``guideLineColor``tickColor``labelColor` | 命名规范化 | | **Expose** | `panzoomInstance` | `engine`(TransformEngine) | 直接暴露内置引擎实例 | | **Expose 方法** | `zoomIn()``zoomOut()``reset()` | 同上,并新增 `setTransform()``zoomToPreset()``setZoomMode()` | 方法更丰富 | | **外部依赖** | `simple-panzoom` | 零外部 panzoom 依赖 | 需从项目中移除 `simple-panzoom` | ### 快速迁移示例 **2.x 代码:** ```vue <template> <sketch-rule ref="sketchruleRef" v-model:scale="state.scale" :panzoomOption="panzoomOption" :palette="{ lineType: 'dashed', lineColor: '#51d6a9' }" @handleLine="handleLinesChange" > <template #default>...</template> <template #btn="{ reset, zoomIn, zoomOut }"> <button @click="reset">还原</button> <button @click="zoomIn">放大</button> <button @click="zoomOut">缩小</button> </template> </sketch-rule> </template> <script setup> import SketchRule from 'vue3-sketch-ruler' import { simplePanzoom } from 'simple-panzoom' // 需移除 </script> ``` **3.x 代码:** ```vue <template> <SketchRuler ref="sketchRef" v-model:scale="state.scale" v-model:offset="state.offset" :zoom-mode="'pointer'" :enable-animation="true" animation-mode="ease-out" :palette="{ guideLineStyle: 'dashed', guideLineColor: '#51d6a9' }" @update:lines="handleLinesChange" @zoomchange="handleZoomChange" > <template #default>...</template> <template #toolbar="{ tools }"> <button @click="tools.reset">还原</button> <button @click="tools.zoomIn">放大</button> <button @click="tools.zoomOut">缩小</button> <button @click="tools.zoomToPreset(1)">100%</button> <span>{{ (tools.state.scale * 100).toFixed(0) }}%</span> </template> </SketchRuler> </template> <script setup> import { SketchRuler } from 'vue3-sketch-ruler' </script> ``` ### 自动化迁移脚本 项目提供了官方迁移脚本,可自动处理大部分替换: ```bash npx vue3-sketch-ruler-migrate <path> ``` 脚本会自动处理: - 组件名 `SketchRule``SketchRuler` - 插槽 `#btn``#toolbar` - 事件 `zoomStart``update:scale``handleLine``update:lines` - 检测 `simple-panzoom``useLine` 等需手动移除的依赖并发出警告 > ⚠️ 脚本仅为辅助工具,执行后请务必 review 变更并运行测试。 ### 新增能力速览 - **Minimap 缩略图**:独立组件,支持拖拽视口与点击跳转 - **插件系统**:通过 `plugins` 属性注入生命周期钩子 - **多画布管理器**`CanvasManager` + `BUILTIN_TEMPLATES` - **吸附引擎**`snapThreshold` 配置参考线吸附阈值 - **动画引擎**`enableAnimation` + `animationMode` 实现平滑缩放/平移 - **纯原生零依赖**:核心引擎 `@sketch-ruler/core` 纯原生实现,无需 panzoom 等第三方库 --- ## 变更记录 - **v3.x** 内置 TransformEngine 替代外部 panzoom,新增 Minimap、插件系统、多画布管理器、吸附引擎、动画系统 - **v2.4.x** 多实例支持 - **v2.3.x** 引用简化版 simple-panzoom,提升性能,更新全部依赖 ## 🌈 Who is using this? [avue大屏可视化工具](https://data.avuejs.com/build/1) ![image](https://github.com/kakajun/vue3-sketch-ruler/blob/1x/example/v2/assets/dp.png) [GoView 高效拖拽式低代码数据可视化开发平台](https://vue.mtruning.club/#/project/items) > open a PR to add your library ;) ### QQ 技术交流群: <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=oqnBX-qn7gkWsdfYQdvNCzYbkeNknuOc&jump_from=webapi&authKey=4YXd2jvmWYU0cN8zUky5DoCD6kz+fjUyWv782GLUjDEIHctXYviSXD/pbqxm/ZDD"><img border="0" src="https://github.com/kakajun/vue3-sketch-ruler/blob/master/packages/docs/src/assets/group.png" alt="vue3-sketch-ruler" title="点击这里加入QQ群640166628"></a> <div align=center> <img src="https://github.com/kakajun/vue3-sketch-ruler/blob/master/packages/docs/src/assets/qq.png" width="243" height="287"> </div> ## 贡献者 <a href="https://github.com/kakajun/vue3-sketch-ruler/graphs/contributors"> <img src="https://contrib.rocks/image?repo=kakajun/vue3-sketch-ruler" /> </a> ## 最后 这是个开源业余做的功能,欢迎加强该插件的小伙伴加入。如果 `vue3-sketch-ruler` 对您有帮助,请给个 star,您的鼓励是我最大的动力。 <a href='https://gitee.com/majun2232/vue3-sketch-Ruler'><img src='https://gitee.com/majun2232/vue3-sketch-Ruler/widgets/widget_4.svg' alt='Fork me on Gitee'></img></a> ## 引用 vue标尺组件 [vue-sketch-ruler](https://github.com/chuxiaoguo/vue-sketch-ruler.git)