npm package: @lhy-meta-web/ruler
Description: > 基于vue3实现的标尺工具，支持拖拽、缩放
Latest version: 1.2.12

# @lhy-meta-web/ruler

> 基于vue3实现的标尺工具，支持拖拽、缩放

> 基于标尺工具实现的类似磨刀的标尺设计器

<br />

## 快速开始

安装

```typescript
  npm install -g @lhy-meta-web/ruler

  // 或者
  yarn install -g @lhy-meta-web/ruler

  // 或者
  pnpm install -g @lhy-meta-web/ruler
```

## 标尺工具

### 使用

```typescript
import { Ruler, type RulerExpose } from '@lhy-meta-web/ruler'
import '@lhy-meta-web/ruler/dist/style.css'

// 支持全局/局部使用

```

<br />

### 配置

`RulerProps`

| 属性            | 类型                                     | 描述                                                       |
| --------------- | ---------------------------------------- | ---------------------------------------------------------- |
| `direction`     | `horizontal \| vertical`                 | 方向，默认：horizontal                                     |
| `textPosition`  | `auto \| top \| bottom \| left \| right` | 文本相对于刻度的位置，默认：auto                           |
| `size`          | `number`                                 | 标尺尺寸，默认：18                                         |
| `zeroOrigin`    | `number`                                 | 原点坐标，基于scale=1，默认：0                             |
| `scale`         | `number`                                 | 用户缩放值，默认：1                                        |
| `scaleOrigin`   | `number`                                 | 缩放中心点，相对于zeroOrigin的偏移量，通常用于鼠标滚轮缩放 |
| `minScale`      | `number`                                 | 最小缩放值，默认：0.1                                      |
| `maxScale`      | `number`                                 | 最大缩放值，默认：10                                       |
| `ratio`         | `number`                                 | 画布的缩放比例，默认：1                                    |
| `selectedRange` | `[number, number]`                       | 选中的区间坐标值，高亮显示                                 |
| `calcGridSize`  | `(scaleValue: number) => number`         | 标尺中每小格代表的宽度，默认参照下表                       |
| `color`         | `RulerColor`                             | 颜色                                                       |

<br />

`RulerProps['calcGridSize']`

| scaleValue           | calcGridSize |
| -------------------- | ------------ |
| `scaleValue <= 0.25` | 40           |
| `scaleValue <= 0.5`  | 20           |
| `scaleValue <= 1`    | 10           |
| `scaleValue <= 2`    | 5            |
| `scaleValue <= 4`    | 2            |
| 其他                 | 1            |

<br />

`RulerColor`

| 属性              | 类型            | 描述                                   |
| ----------------- | --------------- | -------------------------------------- |
| `lineColor`       | `string(color)` | 线条颜色，默认：#888                   |
| `mmLineColor`     | `string(color)` | 小格线条颜色，默认：线条颜色 * 0.7     |
| `cmLineColor`     | `string(color)` | 大格线条颜色，默认：线条颜色           |
| `textColor`       | `string(color)` | 文本颜色，默认：#666                   |
| `bgColor`         | `string(color)` | 背景颜色，默认：#ccc                   |
| `selectedBgColor` | `string(color)` | 选中区域背景颜色，默认：背景颜色 * 1.1 |

<br />

### 实例方法

```typescript
export type RulerExpose = {
  /**
   * 平移
   *
   * @param offset 偏移量
   */
  translate(offset: number): void
  /**
   * 平移至
   *
   * @param value
   */
  translateTo(value: number): void
  /**
   * 渲染
   */
  render(): void
  // 画布Ref
  canvasRef: Ref<HTMLCanvasElement | undefined>
}
```

<br />

### Demo

```typescript
<template>
  <div
    class="canvas-wrapper"
    @wheel="onWheel"
    @mousedown="onMousedown"
    @mousemove="onMousemove"
    @mouseup="onMouseup">
    <div class="canvas-ruler ruler-h">
      <Ruler
        :scale="scale"
        :selectedRange="[120, 344]"
        :scaleOrigin="x"
        ref="hRuler" />
    </div>

    <div class="canvas-ruler ruler-v">
      <Ruler
        direction="vertical"
        :scale="scale"
        :selectedRange="[120, 344]"
        :scaleOrigin="y"
        ref="vRuler" />
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Ruler，type RulerExpose } from '@lhy-meta-web/ruler'

const hRuler = ref<RulerExpose>()
const vRuler = ref<RulerExpose>()
const scale = ref(1)
const x = ref(0)
const y = ref(0)
const onWheel = (e: WheelEvent) => {
  x.value = e.offsetX
  y.value = e.offsetY

  if (e.deltaY < 0) {
    scale.value = Math.min(scale.value + 0.1, 10)
  } else {
    scale.value = Math.max(scale.value - 0.1, 0.1)
  }

  e.stopPropagation()
  e.preventDefault()
}

const mousePos = {
  x: 0,
  y: 0,
  enabled: false,
}
const onMousedown = (e: MouseEvent) => {
  mousePos.x = e.x
  mousePos.y = e.y
  mousePos.enabled = true
}
const onMousemove = (e: MouseEvent) => {
  if (mousePos.enabled) {
    hRuler.value?.translate(e.x - mousePos.x)
    vRuler.value?.translate(e.y - mousePos.y)

    mousePos.x = e.x
    mousePos.y = e.y
  }
}
const onMouseup = () => {
  if (mousePos.enabled) {
    mousePos.enabled = false
    mousePos.x = 0
    mousePos.y = 0
  }
}
</script>
<style lang="scss" scoped>
.canvas-wrapper {
  position: relative;
  width: 1000px;
  height: 600px;
  padding: 40px;
  background-color: gray;
}

.canvas-ruler {
  position: absolute;
  left: 0;
  top: 0;
  background-color: #ccc;

  &.ruler-h {
    width: 100%;
    height: 18px;
  }

  &.ruler-v {
    width: 18px;
    height: 100%;
  }
}
</style>

```

<br />

### 刻度和文本

- 刻度通过`ctx.lineDash`方法和`ctx.lineDashOffset`实现，没有复杂的坐标计算
- 文本通过视口的起始->截止的有效范围遍历，每次间隔大刻度尺寸宽度，只需计算出起始位置即可

<br />

### 缩放

通过设置`scaleOrigin`即可实现以指定坐标点为中心进行缩放操作，该配置请参考以上配置表

<br />

### 平移

平移通过实例方法`RulerExpose.translate(offset: number)`/`RulerExpose.translateTo(value: number)`实现

<br />


## 标尺设计器

### 使用

```typescript
import { RulerDesigner, type RulerDesignerExpose } from '@lhy-meta-web/ruler'
import '@lhy-meta-web/ruler/dist/style.css'

// 支持全局/局部使用

```

<br />

### 配置

`RulerDesignerProps`

| 属性                      | 类型               | 描述                                       |
| ------------------------- | ------------------ | ------------------------------------------ |
| `rulerSize`               | `number`           | 标尺尺寸，默认：18                         |
| `rulerColor`              | `RulerColor`       | 标尺颜色                                   |
| `hRulerSelectedRange`     | `[number, number]` | 横向标尺选中区间                           |
| `vRulerSelectedRange`     | `[number, number]` | 纵向标尺选中区间                           |
| `initialScale`            | `number`           | 初始缩放值，默认：1                        |
| `minScale`                | `number`           | 最小缩放值，默认：0.1                      |
| `maxScale`                | `number`           | 最大缩放值，默认：10                       |
| `scaleSpeed`              | `number`           | 缩放速度                                   |
| `width`                   | `number`           | 操作视图宽度，默认视口宽度 * 0.75          |
| `height`                  | `number`           | 操作视图高度，默认视口高度 * 0.75          |
| `indicator`               | `boolean`          | 是否显示鼠标指示器                         |
| `referLine`               | `boolean`          | 开启参考线                                 |
| `referLineColor`          | `ReferLineColor`   | 参考线颜色                                 |
| `referLineRemoveBoundary` | `number`           | 参考线移动到边界xx范围时移除，默认：20     |
| `referLineLockable`       | `boolean`          | 参考线开启锁定功能，默认：true             |
| `referLockBtnPosition`    | `string`           | 参考线锁定按钮距离顶部/左侧距离，默认：90% |
| `panZoomOptions`          | `PanZoomOptions`   | 自定义PanZoom配置项                        |



<br />


### 实例方法

```typescript
export type RulerExpose = {
  // 横向标尺组件实例
  hRulerRef: Ref<RulerExpose | undefined>
  // 竖向标尺组件实例
  vRulerRef: Ref<RulerExpose | undefined>
  // 参考线组件实例
  referLineRef: Ref<DesignerReferLineExpose | undefined>
   /**
   * 获取横向标尺组件实例
   */
  getHRulerExpose(): RulerExpose | undefined
  /**
   * 获取纵向标尺组件实例
   */
  getVRulerExpose(): RulerExpose | undefined
  /**
   * 获取参考线组件实例
   */
  getReferLine(): DesignerReferLineExpose | undefined
  /**
   * 获取panZoom实例
   */
  getPanZoom(): PanZoom | undefined
  /**
   * 获取panZoom实例
   */
  getPanZoom(): PanZoom | undefined
  /**
   * 获取viewpoet元素
   */
  getViewportEl(): HTMLElement | undefined
  /**
   * 获取body元素
   */
  getBodyEl(): HTMLElement | undefined
  /**
   * 获取view元素
   */
  getViewEl(): HTMLElement | undefined
  /**
   * 缩放
   *
   * @param scaleValue
   * @param scaleOptions 默认是中心点
   */
  scale(scaleValue: number, scaleOptions?: { x?: number; y?: number; smooth?: boolean }): void
  /**
   * 平移
   *
   * @param offset
   * @param smooth
   */
  translate(offset: { x: number; y: number }, smooth?: boolean): void
  /**
   * 平移至指定坐标点
   *
   * @param point
   * @param smooth
   */
  translateTo(point: { x: number; y: number }, smooth?: boolean): void
  /**
   * 定位至初始中心
   */
  locateCenter(): void
  /**
   * 获取transform数据
   */
  getTransform(): Transform
  /**
   * 重新渲染
   */
  render(): void
}
```

<br />

### 事件

```typescript
export type RulerEmits = {
   /**
   * 组件就绪
   *
   * @returns
   */
  ready: () => true,
  /**
   * 缩放
   *
   * @param scaleValue 当前缩放值
   * @param origin 缩放中心点
   * @param lastScaleValue 上一次的缩放值
   * @returns
   */
  scale: (scaleValue: number, origin: { x: number; y: number }, lastScaleValue: number) => true,
  /**
   * 平移
   *
   * @param point
   * @returns
   */
  translate: (point: { x: number; y: number }) => true,
}
```

<br />

### 插槽

```typescript
export type RulerDesignerSlots = SlotsType<{
  // 视图内容
  default?: {}
  // 与视图同级元素，通常用于扩展
  body?: {}
}>
```

<br />

### 样式

请通过css样式复写

### 参考线

参考线由`DesignerReferLine`组件提供能力和管理，点击设计器左侧/顶部的标尺工具可拖拽出参考线

<br />

### Demo

```typescript
<template>
  <div class="canvas-wrapper">
    <RulerDesigner
      referLine
      ref="designerRef" />

    <button @click="locateCenter()">中心</button>
    <button @click="scale()">缩放至0.5</button>
    <button @click="translate()">移动至[200, 100]</button>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { RulerDesigner, type RulerDesignerExpose } from '@lhy-meta-web/ruler'
import '@lhy-meta-web/ruler/dist/style.css'

const designerRef = ref<RulerDesignerExpose>()

const locateCenter = () => designerRef.value?.locateCenter()
const scale = () => designerRef.value?.scale(0.5, { smooth: true })
const translate = () => designerRef.value?.translateTo({ x: 200, y: 100 }, true)
</script>
<style lang="scss" scoped>
.canvas-wrapper {
  position: relative;
  width: 1000px;
  height: 600px;
}
</style>

```

<br />


## 参考线

### 使用

```typescript
import { DesignerReferLine, type DesignerReferLineExpose } from '@lhy-meta-web/ruler'
import '@lhy-meta-web/ruler/dist/style.css'

// 支持全局/局部使用

```

<br />

### 配置

`DesignerReferLineProps`

| 属性             | 类型                      | 描述                                  |
| ---------------- | ------------------------- | ------------------------------------- |
| `viewport`       | `() => HTMLElement`       | 视口元素，默认：父元素                |
| `referLineProps` | `Partial<ReferLineProps>` | 参考线props                           |
| `xZeroOrigin`    | `number`                  | x原点坐标，基于scale=1，默认：0       |
| `yZeroOrigin`    | `number`                  | y原点坐标，基于scale=1，默认：0       |
| `scale`          | `number`                  | 用户缩放值，必须大于0，默认：1        |
| `xScaleOrigin`   | `number`                  | x缩放中心点，相对于zeroOrigin的偏移量 |
| `yScaleOrigin`   | `number`                  | y缩放中心点，相对于zeroOrigin的偏移量 |
| `removeBoundary` | `number`                  | 删除边界值，默认：20                  |

<br />

`ReferLineProps`

| 属性              | 类型                         | 描述                                                   |
| ----------------- | ---------------------------- | ------------------------------------------------------ |
| `left`            | `number`                     | left坐标值，direction=vertical时有效，默认：0          |
| `top`             | `number`                     | top坐标值，direction=horizontal时有效，默认：0         |
| `direction`       | `'horizontal' \| 'vertical'` | 方向，默认：horizontal                                 |
| `hover`           | `boolean`                    | 是否hover，css中已经包含:hover效果，该属性用于强制启用 |
| `selected`        | `boolean`                    | 是否选中                                               |
| `willRemove`      | `boolean`                    | 是否将要删除                                           |
| `color`           | `ReferLineColor`             | 参考线颜色                                             |
| `lockable`        | `boolean`                    | 是否开启锁定功能                                       |
| `locked`          | `boolean`                    | 是否锁定                                               |
| `lockBtnPosition` | `boolean`                    | 锁定按钮距离顶部/左侧位置，默认：90%                   |

<br />

`ReferLineColor`

| 属性              | 类型            | 描述                          |
| ----------------- | --------------- | ----------------------------- |
| `color`           | `string(Color)` | 参考线颜色，默认：#ccc        |
| `hoverColor`      | `string(Color)` | 参考线hover颜色，默认：#666   |
| `selectedColor`   | `string(Color)` | 参考线选中颜色，默认：#2681ff |
| `willRemoveColor` | `string(Color)` | 将要删除的颜色，默认：#f05537 |
| `lockedColor`     | `string(Color)` | 锁定颜色，默认：#ffaa32       |

<br />


### 实例方法

```typescript
export type DesignerReferLineExpose = {
  /**
   * 添加横向参考线
   *
   * @param top
   * @param emit
   * @returns
   */
  addHorizontalLine(top?: number, emit?: boolean): ReferLine
  /**
   * 添加竖向参考线
   *
   * @param left
   * @param emit
   * @returns
   */
  addVerticalLine(left?: number, emit?: boolean): ReferLine
  /**
   * 获取横向参考线
   */
  getHorizontalLines(): ReferLine[]
  /**
   * 获取竖向参考线
   */
  getVerticalLines(): ReferLine[]
  /**
   * 获取参考线
   */
  getLines(): ReferLine[]
  /**
   * 删除参考线
   *
   * @param index
   * @param emit
   */
  removeLine(index: number | ReferLine, emit?: boolean): void
  /**
   * 清空参考线
   */
  clearLines(): void
  /**
   * 坐标系平移
   *
   * @param offset
   */
  translate(offset: { x: number; y: number }): void
  /**
   * 坐标系平移至
   *
   * @param point
   */
  translateTo(point: { x: number; y: number }): void
  /**
   * 移动参考线
   *
   * @param offset
   * @param lines
   */
  move(offset: { x: number; y: number }, lines?: ReferLine[]): void
  /**
   * 移动参考线至
   *
   * @param value
   * @param lines
   */
  moveTo(value: { x: number; y: number }, lines?: ReferLine[]): void
  /**
   * 重置
   */
  reset(): void
  /**
   * 切换锁定
   *
   * @param lines
   * @param locked
   */
  toggleLocked(lines: ReferLine[] | ReferLine, locked?: boolean): void
}
```

<br />

### 事件

```typescript
export type DesignerReferLineEmits = {
  /**
   * 参考线mousedown事件
   *
   * @param e
   * @param line
   * @returns
   */
  referLineMousedown: (e: MouseEvent, line: ReferLine) => true,
  /**
   * 添加参考线
   *
   * @param line
   * @returns
   */
  addReferLine: (line: ReferLine) => true,
  /**
   * 删除草靠先
   *
   * @param line
   * @returns
   */
  removeReferLine: (line: ReferLine) => true,
}
```

<br />


## 意见或建议

可发送邮件至邮箱`810422646@qq.com`，标题请明确包含`@lhy-meta-web/ruler`字样