前言
本节我们通过简单的矩形绘制学习如何实现无限画布
准备工作
在绘制前,我们需要矫正 canvas 的分辨率,使用 appState 保存 canvas 相关的信息。新建一个 index.jsx 文件,初始化代码如下:
const appState = {offsetLeft: 0,offsetTop: 0,
};
const Canvas = memo(() => {const canvasRef = useRef(null);const canvasContainer = useRef(null);useEffect(() => {const canvas = canvasRef.current;const context = canvas.getContext("2d");const { offsetWidth, offsetHeight, offsetLeft, offsetTop } = canvas;canvas.width = offsetWidth * window.devicePixelRatio;canvas.height = offsetHeight * window.devicePixelRatio;context.scale(window.devicePixelRatio, window.devicePixelRatio);appState.offsetLeft = offsetLeft;appState.offsetTop = offsetTop;}, []);return (<div ref={canvasContainer}><canvas ref={canvasRef} className="canvas">绘制canvas</canvas></div>);
});
绘制坐标轴
为方便观察,首先在 canvas 上绘制一个坐标轴。新建一个 renderScene.js 文件,实现 drawAxis 方法:
const drawAxis = (ctx) => {ctx.save();const rectH = 100; // 纵轴刻度间距const rectW = 100; // 横轴刻度间距const tickLength = 8; // 刻度线长度const canvas = ctx.canvas;ctx.translate(0, 0);ctx.strokeStyle = "red";ctx.fillStyle = "red";// 绘制横轴和纵轴ctx.save();ctx.beginPath();ctx.setLineDash([10, 10]);ctx.moveTo(0, 0);ctx.lineTo(0, canvas.height);ctx.moveTo(0, 0);ctx.lineTo(canvas.width, 0);ctx.stroke();ctx.restore();// 绘制横轴和纵轴刻度ctx.beginPath();ctx.lineWidth = 2;ctx.textBaseline = "middle";for (let i = 0; i < canvas.height / rectH; i++) {// 绘制纵轴刻度ctx.moveTo(0, i * rectH);ctx.lineTo(tickLength, i * rectH);ctx.font = "20px Arial";ctx.fillText(i, -25, i * rectH);}for (let i = 1; i < canvas.width / rectW; i++) {// 绘制横轴刻度ctx.moveTo(i * rectW, 0);ctx.lineTo(i * rectW, tickLength);ctx.font = "20px Arial";ctx.fillText(i, i * rectW - 5, -15);}ctx.stroke();ctx.restore();
};
const renderScene = (canvas) => {const context = canvas.getContext("2d");drawAxis(context);
};
export default renderScene;
然后在 index.jsx 中引入 renderScene
useEffect(() => {//...renderScene(canvas);
}, []);
效果如下:
绘制矩形
屏幕坐标系转 canvas 坐标系
在开始绘制矩形之前,我们先来看下屏幕坐标系如何转换成 canvas 坐