当前位置: 首页 > news >正文

基于vue3的刻度尺组件

刻度尺组件,可支持横向、纵向,同时支持通过缩放比调节缩放比例。在一些可视化设计组件中使用。

截图

横向刻度尺

在这里插入图片描述

纵向刻度尺

在这里插入图片描述

参数说明

  • 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>

相关文章:

  • 什么是全栈?
  • 【人工智能技术发展路径:从符号学习到深度学习的演进】
  • 大模型FunctionCall-知识整理
  • 利率债、信用债、可转债区别与优势
  • STM32L051系列单片机低功耗应用
  • AcWing 蓝桥杯集训·每日一题2025·5526. 平衡细菌
  • 以实例解析汇编语言和高级语言
  • RCE漏洞
  • OpenWrt如何配置WireGuard互联?
  • MyBatis @Param 注解详解:多参数传递与正确使用方式
  • Oracle19c进入EM Express(Oracle企业管理器)详细步骤
  • Map<String,Object>转换为XML报文的方法
  • 网络安全wireshark题目
  • Ubuntu20.04本地配置IsaacGym Preview 4的G1训练环境(一)
  • Linux - 进程通信
  • 11、vue3生命周期?
  • 湖仓一体化及冷、热、实时三级存储
  • Django 5实用指南(十二)异步处理与Celery集成
  • 【YOLOv12改进trick】多尺度大核注意力机制MLKA模块引入YOLOv12,实现多尺度目标检测涨点,含创新点Python代码,方便发论文
  • GCC RISCV 后端 -- GCC Passes 注释
  • 做网站打广告图片素材/营销的四种方式
  • 做网站 php java/做百度推广的网络公司
  • 手机网站 cms/产品推广软文200字
  • 天津建站服务/免费获客软件
  • 网站搜索功能怎样做/找代写文章写手
  • html5网站开发方案/海外销售平台有哪些