You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

106 lines
3.3 KiB

import { useCallback, useEffect, useRef } from "react";
const primaryLineColor = "rgb(203,213,245)";
const subLineColor = "rgb(226,231,232)";
export default function GridLayer(props: {
width: number;
height: number;
leftPadding: number;
rightPadding: number;
topPadding: number;
bottomPadding: number;
columns: number;
rows: number;
colCellNum: number;
rowCellNum: number;
visibility: 'hidden' | 'visible';
}) {
const xStartPx = props.leftPadding;
const xEndPx = props.width - props.rightPadding;
const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns;
const xUnitPx = xStepPx / props.colCellNum;
const yStartPx = props.topPadding;
const yEndPx = props.height - props.bottomPadding;
const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows;
const yUnitPx = yStepPx / props.rowCellNum;
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const drawGrid = useCallback(
(ctx: CanvasRenderingContext2D) => {
ctx.resetTransform();
ctx.clearRect(0, 0, props.width, props.height);
ctx.beginPath();
ctx.strokeStyle = subLineColor;
for (let i = 1; i < props.columns * props.colCellNum; ++i) {
if (i % props.colCellNum === 0) continue;
ctx.moveTo(xStartPx + xUnitPx * i, yStartPx);
ctx.lineTo(xStartPx + xUnitPx * i, yEndPx);
}
for (let j = 1; j < props.rows * props.rowCellNum; ++j) {
if (j % props.rowCellNum === 0) continue;
ctx.moveTo(xStartPx, yStartPx + yUnitPx * j);
ctx.lineTo(xEndPx, yStartPx + yUnitPx * j);
}
ctx.stroke()
ctx.beginPath();
ctx.strokeStyle = primaryLineColor;
for (let i = 0; i <= props.columns; ++i) {
ctx.moveTo(xStartPx + xStepPx * i, yStartPx);
ctx.lineTo(xStartPx + xStepPx * i, yEndPx);
}
for (let j = 0; j <= props.rows; ++j) {
ctx.moveTo(xStartPx, yStartPx + yStepPx * j);
ctx.lineTo(xEndPx, yStartPx + yStepPx * j);
}
ctx.stroke()
ctx.beginPath();
ctx.strokeStyle = "#999";
// 偏移原点
const xOffset = (xEndPx - xStartPx) / 2;
const yOffset = yStepPx * 2;
const yMax = yEndPx - yStartPx - yOffset;
ctx.translate(xStartPx + xOffset, yStartPx + yOffset);
// 绘制原点交叉线
ctx.moveTo(-xOffset, 0);
ctx.lineTo(xOffset, 0);
ctx.moveTo(0, -yOffset);
ctx.lineTo(0, yMax);
ctx.stroke()
// 绘制x轴y轴 单位数值
ctx.beginPath();
ctx.fillStyle = "#333333";
ctx.textAlign = "center";
ctx.font = "normal 14px system";
for (let index = -4; index < 5; index++) {
ctx.fillText((index * 10).toString(), xStepPx * index, yMax + 20);
}
for (let index = -1; index < 5; index++) {
ctx.fillText((index * 10).toString(), -xOffset - (index > 0 ? 18 : 14), yStepPx * index + 4);
}
},
[props.colCellNum, props.columns, props.height, props.rowCellNum, props.rows, props.width, xEndPx, xStartPx, xStepPx, xUnitPx, yEndPx, yStartPx, yStepPx, yUnitPx]
);
useEffect(() => {
// 获取canvas的2D绘图上下文
const canvas = canvasRef.current;
if (!canvas) return;
const context = canvas.getContext("2d");
if (!context) return;
// 使用context对象进行绘图
drawGrid(context);
}, [drawGrid]);
return (
<div style={{visibility: props.visibility}}>
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas>
</div>
);
}