刻度尺组件,可支持横向、纵向,同时支持通过缩放比调节缩放比例。在一些可视化设计组件中使用。
截图
横向刻度尺
纵向刻度尺
参数说明
-
layout?: ‘horizontal’ | ‘vertical’,标尺方向,默认为:horizontal;
-
scale: number,缩放比;
-
rulerColor?: string,标尺颜色默认为:#000000;
-
labelColor?: string,标尺刻度数字颜色默认为:#000000
-
mousemove(position: number): void,鼠标移动时触发;
-
click(position: number): void,鼠标点击时触发;
组件源码
<!--
* @Description: 刻度尺组件
* @Author: wang keju
* @Email: git config user.email
* @Date: 2025-03-04 07:12:35
* @LastEditTime: 2025-03-04 07:35:06
* @LastEditors: wang keju
-->
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue'
type Props = {
layout?: 'horizontal' | 'vertical';
scale: number;
rulerColor?: string;
labelColor?: string;
}
const props = withDefaults(defineProps<Props>(), {
layout: 'horizontal',
rulerColor: '#000000',
labelColor: '#000000',
})
const emits = defineEmits<{
(event: 'mousemove', position: number): void
(event: 'click', position: number): void
}>()
const canvasRef = ref<HTMLCanvasElement>()
onMounted(draw)
watch(props, draw)
/**
* @description: 根据布局方向,绘制标尺
* @return {*}
*/
function draw () {
drawSketchRuler()
}
/**
* @description: 绘制刻度
* @return {void}
*/
function drawSketchRuler() {
const canvas = canvasRef.value
if (!canvas) return
const containerRect = canvas.getBoundingClientRect()
canvas.width = containerRect.width
canvas.height = containerRect.height
const ctx = canvas.getContext('2d')
if (!ctx) return
// 清空画布
ctx.clearRect(0, 0, containerRect.width, containerRect.height)
// 设置线条样式
ctx.strokeStyle = props.rulerColor
ctx.lineWidth = 1
// 绘制标尺刻度数字
ctx.font = '12px Arial'
ctx.textAlign = 'center'
ctx.textBaseline = 'top'
ctx.fillStyle = props.labelColor
const scale = props.scale
const rulerConfig = [
{ min: 8, max: 10, minSketch: 0.5, middleSketch: 2.5, maxSketch: 5 },
{ min: 4, max: 8, minSketch: 1, middleSketch: 5, maxSketch: 10 },
{ min: 2, max: 4, minSketch: 2, middleSketch: 10, maxSketch: 20 },
{ min: 1, max: 2, minSketch: 5, middleSketch: 25, maxSketch: 50 },
{ min: 0.5, max: 1, minSketch: 10, middleSketch: 500, maxSketch: 100 },
{ min: 0.3, max: 0.5, minSketch: 20, middleSketch: 100, maxSketch: 200 },
{ min: 0.1, max: 0.3, minSketch: 50, middleSketch: 250, maxSketch: 500 },
{ min: 0.01, max: 0.1, minSketch: 100, middleSketch: 500, maxSketch: 1000 },
]
let info = scale >= 10 ? rulerConfig[0] : rulerConfig.find((item) => item.min <= scale && scale < item.max)
if (!info) return
const { minSketch, middleSketch, maxSketch } = info
if (props.layout === 'horizontal') {
for (let i = 0; i <= containerRect.width / scale; i += 1) {
const point = i * props.scale
if (i % maxSketch === 0) {
ctx.beginPath()
ctx.moveTo(point, 0)
ctx.lineTo(point, 14)
ctx.stroke()
i !== 0 && ctx.fillText(String(i), point, 16);
} else if (i % middleSketch === 0) {
ctx.beginPath()
ctx.moveTo(point, 0)
ctx.lineTo(point, 10)
ctx.stroke()
} else if (i % minSketch === 0) {
ctx.beginPath();
ctx.moveTo(point, 0)
ctx.lineTo(point, 6)
ctx.stroke()
}
}
} else {
for (let i = 0; i <= containerRect.height / scale; i += minSketch) {
const point = i * props.scale
if (i % maxSketch === 0) {
ctx.beginPath()
ctx.moveTo(0, point)
ctx.lineTo(14, point)
ctx.stroke()
} else if (i % middleSketch === 0) {
ctx.beginPath()
ctx.moveTo(0, point)
ctx.lineTo(10, point)
ctx.stroke()
} else if (i % minSketch === 0) {
ctx.beginPath()
ctx.moveTo(6, point)
ctx.lineTo(0, point)
ctx.stroke()
}
}
// 纵向标尺,绘制纵向文本
ctx.rotate(-Math.PI / 2);
for (let i = 0; i <= containerRect.height / Math.min(scale, 1); i += minSketch) {
const point = i * props.scale
if (i % maxSketch === 0) {
if (i !== 0) {
ctx.fillText(String(i), -point, 16)
}
}
}
ctx.restore()
}
}
/**
* @description: 点击标尺触发
* @param {MouseEvent} e
* @return {void}
*/
const onClick = (e: MouseEvent) => {
const position = props.layout === 'horizontal'
? (e.offsetX) / props.scale
: (e.offsetY) / props.scale
emits('click', Math.ceil(position * 10) / 10)
}
/**
* @description:
* @param {MouseEvent} e
* @return {void}
*/
const onMousemove = (e: MouseEvent) => {
const current = props.layout === 'horizontal' ? e.layerX / props.scale : e.layerY / props.scale
emits('mousemove', Math.ceil(current * 10) / 10)
}
</script>
<template>
<canvas style="width: 100%; height: 100%;" ref="canvasRef" @click="onClick" @mousemove="onMousemove" />
</template>