create-a-drawing-app-using-javascript-and-canvas-2an1

原始地址:https://dev.to/javascriptacademy/create-a-drawing-app-using-javascript-and-canvas-2an1

在本教程中,我们将在浏览器中创建一个简单的绘图应用程序。为此,我们将使用原生JS和Canvas API。
完成本教程后,您将对canvas API和JavaScript中的事件处理有很好的概述。

视频教程
如果您希望观看详细的逐步视频,可以查看我在我的YouTube频道上制作的覆盖此项目的视频:

HTML标记
我们将首先将整个应用程序包装到一个带有class为container的部分中。这将用于对齐工具栏和绘图板。
在其中,我们创建一个div,用于容纳我们的工具栏。我还为此设置了一个id为toolbar,这样在JavaScript中处理它将更容易。
在工具栏中,我们将添加一个标题h1。在此之下,我们将添加两个输入字段:一个用于颜色,一个用于线条宽度。对于颜色输入,我添加了id为stroke,因为它将定义描边的颜色,对于数字输入,我将添加id为lineWidth。不要忘记为这些输入字段添加相应的标签。最后,我将添加一个id为clear的按钮,用于清除绘图板。
接下来我们需要添加的是实际的绘图板。它将是一个 canvas 元素,但为了布局目的,我们将其包装在一个div中。
最后,我们需要在body底部添加脚本标签以引入我们的脚本。

绘制。

清除
## 用CSS添加样式 我将首先移除浏览器定义的任何内边距和外边距。还将body的高度设置为100%,并使用overflow: hidden来去除滚动条。 body { margin: 0; padding: 0; height: 100%; overflow: hidden; color: white; } 对于标题,我将添加渐变文本颜色。 h1 { background: #7F7FD5; background: -webkit-linear-gradient(to right, #91EAE4, #86A8E7, #7F7FD5); background: linear-gradient(to right, #91EAE4, #86A8E7, #7F7FD5); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; } 我们还将使容器的高度为100%,将显示设置为flex。 .container { height: 100%; display: flex; } 对于工具栏,我们将使用具有列方向的flexbox。工具栏的宽度将固定为70px。我们添加一些间距,即5px的padding,并为其设置一个深色背景。 对于工具栏元素,我应用了一些基本样式。随意复制这些样式👇 #toolbar { display: flex; flex-direction: column; padding: 5px; width: 70px; background-color: #202020; } #toolbar * { margin-bottom: 6px; } #toolbar label { font-size: 12px; } #toolbar input { width: 100%; } #toolbar button { background-color: #1565c0; border: none; border-radius: 4px; color:white; padding: 2px; } ## 实施javascript部分。 首先,我们将保存工具栏和绘图板(canvas)的引用。 const canvas = document.getElementById('drawing-board'); const toolbar = document.getElementById('toolbar'); 接下来,我们需要获取画布的上下文。我们将使用这个上下文在画布上进行绘制。我们可以通过调用画布的getContext方法来实现这一点。我们要进行2D绘制,因此我们需要将其作为参数提供。 const ctx = canvas.getContext('2d'); 在下一步中,我们将收集偏移量(画布边缘与视口边缘之间的距离)并保存它们。在这种情况下,顶部偏移量为0px,因为画布占据了整个视口的高度,左侧偏移量为70px,因为我们在左侧有一个固定宽度的边栏。接下来,我们将通过用视口的宽度和高度减去偏移量来计算和设置画布的高度和宽度。 const canvasOffsetX = canvas.offsetLeft; const canvasOffsetY = canvas.offsetTop; canvas.width = window.innerWidth - canvasOffsetX; canvas.height = window.innerHeight - canvasOffsetY; 现在,我们将设置一些全局变量。isPainting变量将反映我们当前是否正在绘制。我们将设置基本线宽为5 px。最后,我们将声明两个变量(startX和startY),它们将保存我们开始绘制的点的坐标。 let isPainting = false; let lineWidth = 5; let startX; let startY; 现在我们开始添加事件监听器。首先,我们将向工具栏添加click事件监听器。如果e.target.id是clear(即单击了清除按钮),我们将调用clearRect函数,并为其提供画布的宽度和高度。这个方法的作用是在提供的宽度和高度值内将画布的每个像素设置为白色(即整个画布)。 toolbar.addEventListener('click', e => { if (e.target.id === 'clear') { ctx.clearRect(0, 0, canvas.width, canvas.height); } }); 接下来,我们将处理线条宽度和绘制颜色的输入更改。在这种情况下,我们将使用事件委托。因此,我们只需为父元素添加一个事件监听器,并从那里处理事件。我们可以通过检查e.target的值来区分更改了哪个输入字段。如果更改了颜色,我们将设置画布上下文的strokeStyle,如果更改了lineWidth,则使用新值更新全局变量lineWidth的值。 toolbar.addEventListener('change', e => { if(e.target.id === 'stroke') { ctx.strokeStyle = e.target.value; } if(e.target.id === 'lineWidth') { lineWidth = e.target.value; } }); 接下来,我们将实现绘图控制。当发生mousedown事件(用户单击并按住鼠标按钮)时,我们将将isPainting变量设置为true,并将当前鼠标位置的坐标设置为startX和startY。 如果用户释放鼠标按钮,那么我们将把isPainting设置为false,并调用上下文的stroke方法对已经绘制的路径上色。我们还必须调用beginPath方法来关闭迄今为止用户绘制的路径。我们这样做是因为如果用户想绘制另一条线条,它会从这个位置开始,而这并不是我们想要的。 最后,我们将为mousemove事件添加一个事件监听器。当用户移动鼠标时,我们将调用下一个将要实现的draw函数。 canvas.addEventListener('mousedown', (e) => { isPainting = true; startX = e.clientX; startY = e.clientY; }); canvas.addEventListener('mouseup', e => { isPainting = false; ctx.stroke(); ctx.beginPath(); }); canvas.addEventListener('mousemove', draw); 在draw函数中,我们首先检查isPainting变量的值,如果为false,则表示我们没有在绘制,所以只需简单地返回。 接下来,我们将设置线宽以使用全局变量的值,并设置lineCap为round。之后,我们将通过使用当前鼠标位置的坐标调用lineTo方法绘制一条线段。有一件事需要注意,那就是从X坐标中减去偏移量,否则绘制的线段将与边栏的宽度(70px)偏移。最后,我们只需调用stroke方法为线条指定我们选择的颜色。 const draw = (e) => { if(!isPainting) { return; } ctx.lineWidth = lineWidth; ctx.lineCap = 'round'; ctx.lineTo(e.clientX - canvasOffsetX, e.clientY); ctx.stroke(); } 现在,您已经拥有了一个工作的绘图应用程序! 如果您在任何时候卡住了,可以观看视频,或查看在Codepen上的[源代码。](https://codepen.io/javascriptacademy-stash/pen/porpeoJ) ## 从我这里可以学到更多什么? 我在多个平台上制作涵盖Web开发的教育内容,欢迎 👀 查看这些内容。 我还创建了一个专栏,分享我创建的近一周或两周的教育内容。没有废话,只有教育内容。 🔗 链接: - 🍺 支持免费教育和 [给我买杯啤酒](https://ko-fi.com/adamnagy) - 💬 加入我们的 [Discord社区](https://discord.gg/GuxmcEgAjB) - 📧 订阅简报 [在这里订阅](https://www.getrevue.co/profile/dev_adamnagy) - 🎥 YouTube [Javascript Academy](https://www.youtube.com/channel/UCicOwFWkuMX0ddFaKCc_E5Q) - 🐦 Twitter: [@dev_adamnagy](https://twitter.com/dev_adamnagy) - 📷 Instagram [@javascriptacademy](https://www.instagram.com/javascriptacademy/)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值