/** * 刻度尺绘制 * * @param {*} canvas - canvas元素 * @param {*} canvasStyleWidth - canvasStyleWidth宽度 * @param {*} canvasStyleHeight - canvasStyleHeight高度 * @param {*} direcotion - 标尺方向 * @param {*} scale - 缩放比例 * @param {*} scrollX - 滚动x * @param {*} scrollY - 滚动y * @param {*} originX - 原点x * @param {*} originY - 原点y * */ export function drawScaleplate({ canvas, canvasStyleWidth, canvasStyleHeight, direcotion, scale, scrollX, scrollY, originX, originY, }: { canvas: HTMLCanvasElement; direcotion: "horizontal" | "vertical"; canvasStyleWidth: number; canvasStyleHeight: number; scale: number; scrollX: number; scrollY: number; originX: number; originY: number; }) { const ctx = canvas.getContext("2d"); if (!ctx) return; ctx.clearRect(0, 0, canvas.width, canvas.height); // 计算出清晰canvas的原始宽度 = 样式宽度 * 屏幕倍率 const drp = window.devicePixelRatio || 1; const width = (canvas.width = canvasStyleWidth * drp); const height = (canvas.height = canvasStyleHeight * drp); // 起始位置 const hStartNum = (scrollX - originX) / scale; const vStartNum = (scrollY - originY) / scale; // 计算大刻度, 判断跟20 50 100 250 500 1000谁更接近用谁 const tickSpacingOptions = [20, 50, 100, 250, 500, 1000]; const maxTickNum = tickSpacingOptions.reduce((prev, curr) => { return Math.abs(curr - 100 / scale) < Math.abs(prev - 100 / scale) ? curr : prev; }); // 小刻度数 const minTickNum = maxTickNum / 10; // 计算最小刻度的距离 const minTickSpacing = (maxTickNum / 10) * scale * drp; const maxLength = direcotion === "horizontal" ? width : height; // 记录起始刻度值 let startNum = Math.round( direcotion === "horizontal" ? hStartNum : vStartNum ); // 计算起始刻度偏移量 let startTickOffset = 0; if (startNum % minTickNum !== 0) { startTickOffset += Math.abs((startNum % minTickNum)) * scale * drp; startNum -= startNum % minTickNum; } // 每间隔小刻度数就绘制一个刻度 for ( let tickSpacing = startTickOffset; tickSpacing < maxLength; tickSpacing += minTickSpacing ) { // 如果当前为大刻度 需要展示数字 if(startNum % maxTickNum === 0) { drawMaxTick( ctx, direcotion === "horizontal" ? tickSpacing : 0, direcotion === "horizontal" ? 0 : tickSpacing, startNum, direcotion ); } else if(startNum % minTickNum === 0) { // 如果当前为小刻度 drawMinTick( ctx, direcotion === "horizontal" ? tickSpacing : 0, direcotion === "horizontal" ? 0 : tickSpacing, direcotion ); } startNum += minTickNum; } } // 绘制大刻度 function drawMaxTick( ctx: CanvasRenderingContext2D, x: number, y: number, num: number, direcotion: "horizontal" | "vertical" ) { const drp = window.devicePixelRatio || 1; ctx.beginPath(); if (direcotion === "horizontal") { ctx.moveTo(x + 1, 2); ctx.lineTo(x + 1, y + 20 * drp); } else { ctx.moveTo(x + 1, y); ctx.lineTo(x + 20 * drp, y); } ctx.strokeStyle = "#666"; ctx.lineWidth = 1 * drp; ctx.stroke(); ctx.fillStyle = "#666"; ctx.font = "16px Arial"; if (direcotion === "horizontal") { ctx.fillText(num.toString(), x + 5, 10 * drp); } else { ctx.save(); if(num / 10 >= 100) { // >=1000 ctx.translate(8, y + 25 * drp); } else if(num / 10 >= 10) { // >=100 ctx.translate(8, y + 20 * drp); } else if(num / 10 >= 1) { // >=10 ctx.translate(8, y + 20 * drp); } else if(num / 10 < 0) { ctx.translate(8, y + 25 * drp); } else { ctx.translate(8, y + 10 * drp); } ctx.rotate(-Math.PI / 2); ctx.fillText(num.toString(), 0, 10); ctx.restore(); } } // 绘制小刻度 function drawMinTick( ctx: CanvasRenderingContext2D, x: number, y: number, direcotion: "horizontal" | "vertical" ) { const drp = window.devicePixelRatio || 1; ctx.beginPath(); if (direcotion === "horizontal") { ctx.moveTo(x + 1, 12 * drp); ctx.lineTo(x + 1, y + 20 * drp); } else { ctx.moveTo(12 * drp, y); ctx.lineTo(x + 20 * drp, y); } ctx.strokeStyle = "#666"; ctx.lineWidth = 1 * drp; ctx.stroke(); }