canvas实现刻度尺

 

html 

<template>
  <canvas ref="widthways" :style="getRuleStyle" style="flex: none"></canvas>
</template>

js逻辑 

import { onMounted, ref, computed, watch } from 'vue'
import type { CSSProperties } from 'vue'

const widthways = ref<HTMLCanvasElement>()
const props = defineProps<{
  options: {
    offsetX: number
    offsetY: number
    scale: number
  }
  mode: 'horizontal' | 'vertical'
}>()
const getRuleStyle = computed<CSSProperties>(() => {
  return {
    width: props.mode === 'horizontal' ? '100%' : '30px',
    height: props.mode === 'horizontal' ? '30px' : '100%',
    backgroundColor: 'white',
    zIndex: 996,
    display: 'block',
    cursor: props.mode === 'horizontal' ? 'row-resize' : 'col-resize'
  }
})

function getFixed(sparsity: number) {
  const pointIdx = String(sparsity).indexOf('.')
  const len = String(sparsity).length
  return pointIdx < 0 ? 0 : len - pointIdx - 1
}

function isCloseToInteger(num: number) {
  return Math.abs(num - Math.round(num)) < 0.0000001
}

// 获取间隔
function getSparsity(scale: number) {
  if (scale <= 1) {
    return 100
  } else if (scale <= 3) {
    return 50
  } else if (scale <= 4) {
    return 20
  } else if (scale <= 5) {
    return 10
  }
  return 5
}
watch(() => props.options, renderWidthWays, { deep: true })

function renderWidthWays() {
  const canvas = widthways.value
  if (!canvas) {
    return
  }
  const { width, height } = canvas.getBoundingClientRect()
  const dpi = 2
  canvas.width = width * dpi
  canvas.height = height * dpi
  canvas.style.width = width + 'px'
  canvas.style.height = height + 'px'
  let { width: w, height: h } = canvas
  w /= dpi
  h /= dpi
  const ctx = canvas.getContext('2d')!
  ctx.scale(dpi, dpi)
  ctx.clearRect(0, 0, w, h)
  ctx.save()
  ctx.lineWidth = 1
  ctx.strokeStyle = '#d9d9d9'
  ctx.fillStyle = '#232323'
  ctx.font = '12px serif'
  ctx.beginPath()
  const { offsetX, offsetY, scale } = props.options
  const offset = props.mode === 'horizontal' ? offsetX : offsetY
  // 间隔
  const sparsity = getSparsity(scale)
  // 间隔内有多少条线
  const part = 10
  const pixelPerUnit = scale * sparsity
  const gap = pixelPerUnit / part
  const fixed = getFixed(sparsity)
  let index = offset % gap > 0 ? gap - (offset % gap) : -offset % gap
  if (props.mode === 'horizontal') {
    ctx.translate(29.5, 0)
    do {
      const num = ((offset + index) / pixelPerUnit) * sparsity
      if (isCloseToInteger(num / sparsity)) {
        ctx.moveTo(index, h * 0.5)
        ctx.lineTo(index, h)
        const text = num.toFixed(fixed)
        const textWidth = ctx.measureText(text).width
        ctx.fillText(text, index - textWidth / 2, 10)
      } else {
        ctx.moveTo(index, h * 0.7)
        ctx.lineTo(index, h)
      }
      index += gap
    } while (index < w)
  } else {
    ctx.translate(0, -0.5)
    do {
      const num = ((offset + index) / pixelPerUnit) * sparsity
      if (isCloseToInteger(num / sparsity)) {
        ctx.moveTo(w * 0.5, index)
        ctx.lineTo(w, index)
        const text = num.toFixed(fixed)
        ctx.save()
        ctx.rotate((-90 * Math.PI) / 180)
        const textWidth = ctx.measureText(text).width
        ctx.fillText(text, -(index + textWidth / 2), 12)
        ctx.rotate((0 * Math.PI) / 180)
        ctx.restore()
      } else {
        ctx.moveTo(w * 0.7, index)
        ctx.lineTo(w, index)
      }
      index += gap
    } while (index < h)
  }
  ctx.closePath()
  ctx.stroke()
  ctx.restore()
}
onMounted(renderWidthWays)

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值