根据 MDN 的教学
一开始canvas为空白,程序码脚本需要先存取渲染环境,在上面绘图,然後才会显现影像。 素有一个方法(method)叫getContext(),透过此方法可以取得渲染环境及其绘图函数(function);getContext()输入参数只有渲染环境类型一项,像本教学所讨论的2D绘图,就是输入”2d”。
所以当我们要在画布上操作时,要将画布改写成方法,使用 getContext(),像是这样
const ctx = canvasRef.current.getContext("2d");
再来按照画笔的操作,行为如下:
开始画画(onMouseDown)-> 滑鼠按着移动绘制 (mousemove)-> 绘制完成(onMouseUp)
所以当滑鼠下压时,我们应该给予一个 isDrawing = true;
,告诉下一个步骤,当前是在绘制状态,同理,在绘制完成时 isDrawing = false;
这是本段的重点,当每个点在移动时进行绘制。
/**
* 移动时处理每一个点
* @param {Object} e 移动事件
*/
const handleMouseMove = (e: MouseEvent) => {
if (isDrawing) {
const point = { x: e.offsetX, y: e.offsetY };
handleDrawCanvas(point);
}
};
绘制
const handleDrawCanvas = (point: { x: number; y: number }) => {
const ctx = canvasRef.current.getContext("2d");
if (tool === "pencil") {
ctx.strokeStyle = activeColor;
ctx.lineWidth = 1;
// ctx.globalAlpha = opacity;
ctx.lineCap = "round"; // 头尾圆弧的线条
ctx.lineJoin = "round"; // 交会时圆角
ctx.beginPath();
ctx.moveTo(lastPoint?.x, lastPoint?.y); // 下笔位置
ctx.lineTo(point?.x, point?.y);
ctx.stroke();
lastPoint = { x: point?.x, y: point?.y }; // 记录最後停止位置
ctx.closePath();
}
};
每当一个点到下一个点时要记录最後停止的位置,然後就可以点接着点连成线~
画笔参数
在这边学习几个参数,可以依照喜好给予内容
ctx.strokeStyle = "#000"; // 画笔颜色
ctx.lineWidth = 1; // 画笔宽度
ctx.lineCap = "round"; // 头尾圆弧的线条
ctx.lineJoin = "round"; // 交会时圆角
补上 MDN link
颜色:strokeStyle
画笔粗细:lineWidth
头尾处:lineCap
交界处:lineJoin
前面的准备就绪後,就可以开始用画笔画画啦!来看看目前完成的程序码
CanvasBox/index.tsx
/**
* 画布区块
*/
import { useEffect, useState, useRef, useCallback } from "react";
import { Wrapper, MainCanvas } from "./style";
import { useRecoilValue } from "recoil";
import { activeColorState, toolState } from "../../data/atom";
let lastPoint: { x?: number; y?: number } | null = {}; // 滑鼠移动的上一个点
const CanvasBox = () => {
const activeColor = useRecoilValue(activeColorState);
const tool = useRecoilValue(toolState);
const canvasRef = useRef<any>(null);
const [isDrawing, setIsDrawing] = useState<boolean>(false);
useEffect(() => {
const handleDrawCanvas = (point: { x: number; y: number }) => {
const ctx = canvasRef.current.getContext("2d");
if (tool === "pencil") {
ctx.strokeStyle = activeColor;
ctx.lineWidth = 1;
// ctx.globalAlpha = opacity;
ctx.lineCap = "round"; // 头尾圆弧的线条
ctx.lineJoin = "round"; // 交会时圆角
ctx.beginPath();
ctx.moveTo(lastPoint?.x, lastPoint?.y); // 下笔位置
ctx.lineTo(point?.x, point?.y);
ctx.stroke();
lastPoint = { x: point?.x, y: point?.y };
}
ctx.closePath();
};
/**
* 移动时处理每一个点
* @param {Object} e 移动事件
*/
const handleMouseMove = (e: MouseEvent) => {
if (isDrawing) {
const point = { x: e.offsetX, y: e.offsetY };
handleDrawCanvas(point);
}
};
if (canvasRef && canvasRef.current) {
canvasRef.current.addEventListener("mousemove", handleMouseMove);
}
return () => {
canvasRef.current.removeEventListener("mousemove", handleMouseMove);
};
}, [isDrawing, canvasRef, activeColor, tool]);
/**
* 滑鼠点下画布後开始画画 or 填满
*/
const handleMouseDown = () => {
setIsDrawing(true);
};
/**
* 提起画笔
*/
const handleMouseUp = () => {
if (isDrawing) {
setIsDrawing(false);
lastPoint = null;
}
};
return (
<Wrapper>
<MainCanvas
ref={canvasRef}
height={500}
width={500}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onMouseOver={handleMouseUp}
></MainCanvas>
</Wrapper>
);
};
export default CanvasBox;
https://i.imgur.com/Iu3HlCQ.gif
>>: [第四天]从0开始的UnityAR手机游戏开发-介绍Unity介面和常用快捷键
前言 成长的过程中,有高峰有低潮,会有峰回路转的此起彼落,但也有柳暗花明的落泪感动。曾经我们也是那懵...
写了好几天的事前准备、我想大家应该都腻了。终於、准备到了一定程度、可以进入本文了。这篇文章主要的目的...
是的,如题 因为网路上找到的范例,几乎都是具备密码学知识基础才看得懂的 … 我完全无法使用 pyth...
在64位元系统指标是64/8 = 8bytes,而double也是8bytes若指标指向更小的型态如...
今天要介绍 TypeScript 的基本型别,TypeScript 跟 JavaScript 一样拥...