内容简介:现在,我们终于有了画布,继续定义画布的最基本属性。线我们已经完成了所有这些工作,让我们看看如何在画布上绘图。
在最近的 JavaScript 30天挑战中,我有机会了解 HTML 内置 canvas的特性。相对适宜的等级和学习曲线,使我写下整个过程。
HTML canvas 用最简单的方式,使web 开发者能够通过JavaScript在网页上绘制图形。这样,HTML 元素变得更加有趣。
<canvas>
元素只是个容器,你总是需要使用 JavaScript 来准确绘制图形。有人可能会说,我们总是可以添加这些点,也可以添加SVG,但这又会多么有趣?
回到 <canvas>
元素:canvas 在 HTML 页面上是一个矩形。canvas 是默认没有边框和内容的。
写法像这样:
<canvas id="canvas" width="200" height="100"></canvas>复制代码
开始
已经做了那么多介绍,让我们专注于使用简单的原生 JavaScript(不是很旧——ES6)做些有趣的东西。首先,我们看下初始的文件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>HTML5 Canvas</title> <link rel="stylesheeet" href="style.css" /> </head> <body> <canvas id="canvas" width="800" height="800"></canvas> <script src="app.js"></script> </body> </html>复制代码
让我们慢慢讲。我们有个叫 style.css 的样式层叠表。然后我们定义一个宽800和高800的 canvas 。最后,我们在 script
标签里引用了 app.js
,所有魔法都在这里。我们开始使用 app.js
做一些事情。
const canvas = document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innnerWidth; canvas.height = window.innerHeight; ctx.strokeStyle = "#BADA55" ctx.lineWidth = 1; ctx.lineJoin = 'round'; ctx.lineCap = 'round';复制代码
canvas
现在,我们终于有了画布,继续定义画布的最基本属性。
-
ctx.strokeStyle
设置或返回用于描绘的颜色,渐变色或图案。是的,你理解的对:默认颜色是#BADASS
。 -
ctx.lineWidth
设置或返回 当前线条的宽度。我们把它设置为1
,稍后我们会讲到这个。 -
ctx.lineJoin
设置或返回 两条线相汇时所创建的边角的类型。我们设置当两条线交汇时的边角为圆角。 -
ctx.lineCap
设置或返回线的端点的样式。我们将它设置为圆形,这样当我们不遇到其他线时,我们仍然会得到相同的整齐的圆形,具体取决于之前定义的线的宽度。
线我们已经完成了所有这些工作,让我们看看如何在画布上绘图。
首先,我们需要为画布上的鼠标移动添加事件侦听器,然后触发一个绘制内容的函数。我们来看看 app.js
文件中可能添加的内容。
let isDrawing = fasle; function draw(e){ if(!isDrawing) return; console.log(e) } canvas.addEventListener('mousemove',draw); canvas.addEventListener('mousedown', () => isDrawing = true); canvas.addEventListener('mouseup', () => isDrawing = fasle); canvas.addEventListener('mousedown', () => isDrawing = fasle);复制代码
我们来讲解下:
- 我们开始定义一个叫
isDrawing
的变量,来判断用户是否要在画布上画图。我们会在后面再讲到这个。 - 现在,我们有一个叫
draw
的函数,它会被触发,并负责完成整个绘制动作。 - 最后,我们增加一个约束条件,确保我们捕获正确的事件,并且只在需要的时候执行
draw
函数。
通过声明 isDrawing
变量,并将其值设置为 false
,我们在 canvas
元素被加载后设置 canvas
的初始状态,但还不绘制。然后在每个后续事件侦听器中,我们使用内嵌函数,并每次根据触发的事件类型更改 变量 isDrawing
变量的值。
在 draw
函数 的开头,如果 isDrawing
的值为 false
,函数会执行 return
语句。如果 isDrawing
的值为 true
, 会执行draw 函数。
绘制函数
我们来扩展下 draw 函数:
let isDrawing = false; let lastX = 0; let lastY = 0; function draw(e){ if(!isDrawing) return; console.log(e); ctx.beginPath(); ctx.moveTo(lastX,lastY); ctx.lineTO(e.offsetX,e.offsetY); ctx.stroke(); }复制代码
- 我们在开头定义两个全局变量:
lastX
,lastY
,并设置他们的初始值为0
. - 如果你现在进入浏览器的控制台,你会发现你已经记录了所有鼠标移动。这个
MouseEvent
对象有一些非常重要和有用的属性:
鼠标事件对象
我们只关注对象里的 offsetX
和 offsetY
属性。
- 每次执行
ctx.beginPath
,我们新建一个路径,或者重置当前的路径。每次事件被触发,我们希都会执行这个动作。 -
ctx.moveTo
移动路径到画布指定的点上,但还没绘制线。在例子中,在函数外面的全局环境里定义lastX
和lastY
。 -
ctx.lineTo
增加新的点,并从上一个点到新的点之间绘制一条线。 -
ctx.stroke()
真正绘制你已经定义的路径 —— 辛苦了,伙计们!
在 ctx.lineTo
里,我们利用事件的属性 offsetX
和 offsetY
获得 在画布上的最新点的 X
和 Y
,只用 ctx.lineTo
绘制一条线。
我们几乎所有的东西都准备好了。在页面上的每个鼠标事件都会在画布上绘制一条线——但还有些问题,没有太多酷的东西。所以,让我们加点酷的东西。
酷!
现在,所有线都是从画布中的 (0,0)
点绘制的。 我们将其设置为加载画布或执行 draw
函数时开始绘制的初始点。
让我们解决这个问题,以获得更好的实时体验。 如果考虑一下,答案非常简单:每次执行draw函数时,我们都希望初始点始终是 MouseEvent
对象的 offsetX
和 offsetY
属性。
通过使用 ES6 的数组解构,我们可以将变量 lastX
和 lastY
分别重置为 鼠标事件对象的属性 offsetX
和 offsetY
,我们在 draw
函数的最后执行。我们来看看加了新东西后的 app.js
。
function draw(e){ if(!isDrawing) return; console.log(e); ctx.beginPath(); ctx.moveTo(lastX,lastY); ctx.lineTo(e.offsetX,e.offsetY); ctx.stroke(); [lastX,lastY] = [e.offsetX,e.offsetY]; } canvas.addEventListener('mousemove',draw); canvas.addEventListener('mousedown',(e) => { isDrawing = true; [lastX,lastY] = [e.offsetX,e.offsetY]; }; canvas.addEventListener('mouseup',()=> isDrawing = false); canvas.addEventListener('mousemove',()=> isDrawing = false);复制代码
- 当
mousemove
事件发生时,我们会执行draw
函数。然后继续执行,在draw
函数里使用 ES6 解构 设置 变量lastX
和lastY
。 - 当
mousedown
事件发生时,首先我们执行嵌套函数,如你所见,我们再一次将 变量lastX
和lastY
设置为当前事件的偏移属性。这是为了确保当我们在画布上从一个点移动到另一个点时,我们可以在画布上看到这条线。
让它变得丰富多彩,并在笔画中添加一些动态元素。
let hue = 0; let direction = true; function draw(e){ if(!isDrawing) return; console.log(e); ctx.strokeStyle = `hsl(${hue},100%,50%)`; ctx.beginPath(); ctx.moveTo(lastX,lastY); ctx.lineTo(e.offsetX,e.offsetY); ctx.stroke(); [lastX,lastY] = [e.offsetX,e.offsetY]; hue++; if(hue>=360){ hue = 0; } if(ctx.lineWidth >= 75 || ctx.lineWidth <= 1){ direction = !direction; } if(direction){ ctx.lineWidth++; } else { ctx.lineWidth = 1; } } canvas.addEventListener('mousemove',draw); canvas.addEventListener('mousedown',(e) => { isDrawing = true; [lastX,lastY] = [e.offsetX,e.offsetY]; }; canvas.addEventListener('mouseup',()=> isDrawing = false); canvas.addEventListener('mousemove',()=> isDrawing = false);复制代码
神圣时刻!!
这还有很多事要处理,我们一一分解:
- 我定义一个新的变量
hue
,并设置其值为0
。 - 如果你还不知道色调,为什么会很棒,那就去谷歌试试吧,或者只需点击这里就可以了。
在其最简单的形式, hsl
让我们在从0到360范围里使用相同的彩虹的颜色。 每个数字都有一个亮度和透明度。 定义 hsl 看起来像这样: hsl(173,99%,50%)
。 此处 173
表示颜色 , 99%
是亮度, 50%
是透明度。
同样,通过使用 ES6 的模板字符串,来修改 hsl
的值,像这样:
ctx.strokeStyle = `hsl( ${hue}, 100%, 50%)`
接下来,我们增加 hue
变量的值,该变量在每个 mousemove
事件中更改笔触的颜色。 一旦色调值增加到360,我们将在上述要点的第14行上将 hue
的值重置为0。 但即使我们不这样做,我们仍然会有同样的结果。 即便如此,我们还是做正确的事吧
if(hue > 360){ hue = 0 }复制代码
下一步,我们加点动态的东西,使笔画的宽度实时变化,像这样:
if(ctx.linewidth >= 75 || ctx.lineWidth <= 1){ direction = ! direction; } if(direction){ ctx.lineWidth++ }else { ctx.lineWidth = 0 }复制代码
这里我们所做的就是首先检查当前的线宽是大于75还是小于1。 如果是,则将初始值为 true
的变量 direction
取反。
接下来,我们检查变量 direction
的值是否为 true
。 如果是,则将 lineWidth
的值增加 1
,否则将 lineWidth
重置为 0
。
没有很多JavaScript。 如果你正确跟着做,你应该有个漂亮的画布了。
让我们快速地看一下最终的文件结构是什么样子的。 因为我们只更改了 app.js
文件,所以我将只向你展示这一点,因为index.html从一开始就几乎没有变化。
canvas.width = window.innerWidth;canvas.height = window.innerHeight;ctx.strokeStyle = '#BADA55';ctx.lineWidth = 1;ctx.lineJoin = 'round';ctx.lineCap = 'round';let isDrawing = false;let lastX = 0;let lastY = 0;let hue = 0;let direction = true;function draw(e) { if(!isDrawing) { return; // 鼠标没有按下时不执行. } console.log(e); ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`; ctx.beginPath(); ctx.moveTo(lastX, lastY); ctx.lineTo(e.offsetX, e.offsetY); ctx.stroke(); [lastX, lastY] = [e.offsetX, e.offsetY]; hue++; if(hue>=360){ hue = 0; } if(ctx.lineWidth >= 75 || ctx.lineWidth <= 1) { direction = !direction; } if(direction){ ctx.lineWidth++; } else { ctx.lineWidth = 1; }}canvas.addEventListener('mousemove', draw);canvas.addEventListener('mousedown', (e) => { isDrawing = true; [lastX, lastY] = [e.offsetX, e.offsetY];});canvas.addEventListener('mouseup', ()=> isDrawing = false);canvas.addEventListener('mouseout', () => isDrawing = false);复制代码
在 canvas 和 JavaScript 的结合中,介绍的只是冰山一角。 我会鼓励你做更多的研究,使画布看起来更好。 也许添加几个按钮来清除屏幕,或者选择一种特定的颜色在画布上绘制。 有很多选择!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- TiDB入门(四):从入门到“跑路”
- MyBatis从入门到精通(一):MyBatis入门
- MyBatis从入门到精通(一):MyBatis入门
- Docker入门(一)用hello world入门docker
- 赵童鞋带你入门PHP(六) ThinkPHP框架入门
- 初学者入门 Golang 的学习型项目,go入门项目
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++ API设计
[美] Martin Reddy / 刘晓娜、臧秀涛、林健 / 人民邮电出版社 / 2013-8 / 89.00
现代软件开发中的一大难题就是如何编写优质的API。API负责为某个组件提供逻辑接口并隐藏该模块的内部细节。多数程序员依靠的是经验和冒险,从而很难达到健壮、高效、稳定、可扩展性强的要求。Martin Reddy博士在自己多年经验基础之上,对于不同API风格与模式,总结出了API设计的种种最佳策略,着重针对大规模长期开发项目,辅以翔实的代码范例,从而有助于设计决策的成功实施,以及软件项目的健壮性及稳定......一起来看看 《C++ API设计》 这本书的介绍吧!
图片转BASE64编码
在线图片转Base64编码工具
html转js在线工具
html转js在线工具