전체 텍스트에서는 삼각형, 원 및 기타 관련 그래픽을 그리는 방법에 대해 설명합니다. 익숙하지 않은 학생들은 나가서 오른쪽으로 가서 이전 텍스트를 먼저 읽은 다음 그래픽인 곡선을 계속 읽을 수 있습니다.
수학을 공부했거나 js에 비교적 익숙한 학생들은 모두 베지어 곡선을 알고 있습니다. 물론 수학에서는 이것은 js에서 베지어 곡선이 실제로 다른 곳에 반영되는 데 일반적으로 사용되는 심오한 지식입니다. Photoshop의 펜 도구, CorelDraw의 Bezier 도구 등 캔버스에도 반영됩니다
물론 단순히 곡선을 그리는 경우 이전 방법을 사용할 수도 있습니다. 🎜>
아아아아
곡선을 그리려면 어려울텐데, 그래야만 다음과 같은 주인공이 등장한다.
quadraticCurveTo(cpx,cpy,x,y) 2차 베지어 곡선
매개변수: cpx, cpy는 첫 번째 제어점을 나타내고, x, y는 끝점을 나타냅니다.
더하기 이는 3개의 점이 곡선을 제어한다는 의미입니다. 실제로 이는 arcTo의 사용법과 유사합니다. 차이점은 arcTo는 2개의 선 사이에 있기 때문에 호의 반경을 지정해야 한다는 것입니다. 원과 직선의 접선. 이 이차 베지어 곡선을 그리는 원리는 무엇입니까? 함께 그림을 그려 봅시다:
2차 베지어 곡선의 일반 법칙: 시작점에서 시작하여 곡선이 제어점에 가까울수록 곡선의 경사가 가파르게 됩니다 , 그리고 천천히 제어점에서 멀어지면 곡선은 끝점까지 점점 더 매끄러워지며 이 곡선은 시작점과 끝점에 접하게 됩니다
이 제어점은 약간 비슷합니까? 이 곡선을 끄는 자석? 스포츠, 듣는 것이 보는 것보다 나쁘다, 한번 해보자:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.arc(100,100,100,0,90*Math.PI/180,false); ctx.stroke(); ctx.beginPath(); ctx.moveTo(103,103); ctx.arcTo(183,83,162,182,40); ctx.stroke();
봐요, 곡선의 곡률에 대한 공식이 있지만, 우리는 신경 쓸 필요가 없습니다. 곡선이 제어점에 가까워질수록 곡선은 더 가파르고, 제어점에서 멀어질수록 곡선은 더 평평해집니다.
다시 한번 상기시켜 주세요. 이제 arcTo와quadraticCurveTo의 차이점을 이해하셨나요?
이제 3차 베지어 곡선을 소개하겠습니다.
bezierCurveTo(cpx1,cpy1,cpx2,cpy2,x,y) 3차 베지어 곡선
매개변수: cpx1, cpy1은 첫 번째 제어점 cpx2, cpy2는 두 번째 제어점 x를 나타내고 y는 시작점을 포함한 끝점
을 나타내며 4개의 점을 모아 곡선을 결정하는데 이는 2차 베지어와 유사합니다. 곡선의 원리 제어점이 하나 더 있으면 동일합니다. 곡선이 제어점에 가까울수록 곡선이 더 가파르고 곡선이 제어점에서 멀어질수록 곡선이 더 평평해집니다. 🎜>
간단한 예부터 시작해 보겠습니다(U자 모양 만들기):
ctx.moveTo(50,50); ctx.lineTo(70,120); ctx.lineTo(200,80); ctx.stroke(); ctx.beginPath(); ctx.moveTo(50,50); ctx.quadraticCurveTo(70,120,200,80); ctx.stroke();
위 그림과 같이 첫 번째는 렌더링이고 두 번째는 개략도입니다. 곡선은 시작점에서 시작되며 아래에는 곡선이 가파르게 변하는 제어점이 있습니다. , 두 번째 제어점과 곡선 사이의 접선 위치는 두 제어점의 영향을 받기 때문에 영향을 받으므로 두 제어점이 대칭이므로 곡선이 점차 평평해지기 시작합니다. , 곡선은 수평이 되고 두 제어점의 영향을 계속받으며 두 번째 제어점의 효과는 점점 더 커집니다. 첫 번째 제어점과 곡선 사이의 접점 위치가 달라집니다. 두 번째 제어점의 영향을 계속 받아 반대 방향으로 힘을 받습니다. 끝점에 도달하면 음, 이해가 안 돼요, 이해하지 못한다면 그냥 이해하지 마세요. 그 결론 문장을 기억하세요. 할 것이다!
전형적인 예는 정현파 다이어그램입니다(2개의 베지어 곡선, 하나의 양의 U와 하나의 역 U 사용).
ctx.moveTo(20,20); ctx.bezierCurveTo(20,100,200,100,200,20); ctx.stroke();
물론 3차 베지어 곡선이 U자형 그래프를 그릴 수 있는지는 모르겠지만, 그릴 수 없는 한 어떤 곡선이라도 그릴 수 있다. 생각해보면 못 그리는 건 없잖아요, 하하, 상상력을 키워보자!
그림을 그리는 사람은 항상 수묵화를 하면 안된다고 하네요. 화려한 색을 좋아하는데, 캔버스도 CSS3처럼 그라데이션을 설정할 수 있으니 먼저. 무엇보다 무지개는 멀지 않네요 ㅎㅎ
먼저 CSS3의 그라데이션 설정 방법을 살펴보고 캔버스의 그라데이션을 비교해 보겠습니다. 그래디언트를 하나씩 비교해 보겠습니다.
선형 그래디언트:
.box1{ width:500px; height:50px; background: -webkit-linear-gradient(left, red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%); }
css3可以指定颜色,支持各种颜色格式,且可以指定颜色所在位置,不仅如此,css3还可以指定渐变的方向:
.box1{ width:500px; height:50px; background: -webkit-linear-gradient(45deg , red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%); }
方向可以用角度来定义,45度角是从左下到右上进行渐变
径向渐变:
.box2{ width:300px; height:200px; background:-webkit-radial-gradient(red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%); }
渐变原点为中心,渐变颜色为百分百之间的颜色渐变
可以看出,径向渐变是以中心为原点,一圈一圈向外扩散,同样支持自定义颜色,支持各种颜色格式,支持指定位置,也是可以设置原点和渐变方式(圆形,椭圆):
.box2{ width:300px; height:200px; background:-webkit-radial-gradient(bottom left, ellipse,red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%); }
原点左下,渐变形状为椭圆
.box2{ width:300px; height:200px; background:-webkit-radial-gradient(bottom left, circle,red 0%, #0F0 20%,rgb(51,102,255) 50%, rgba(204,255,0,0.8) 100%); }
原点左下,渐变形状为圆形
以上只是简单列举一下css3的渐变样式,当然css3的渐变肯定不止这些,这里主要是想对比一下canvas的渐变样式,顺便科普一下!
canvas的渐变相对要简单一些,没有那么多的花花肠子:
createLinearGradient(x1,y1,x2,y2) 创建线性渐变
参数:x1,y1 表示渐变起始点 x2,y2 表示渐变结束点
createRadialGradient(x1,y1,r1,x2,y2,r2) 创建径向渐变
参数:x1,y1 表示渐变开始圆心坐标,r1表示渐变开始圆的半径 x2,y2 表示渐变结束圆心坐标,r2表示渐变结束圆的半径
gradient.addColorStop(stop,color) 规定gradient 对象中的颜色和位置
参数: stop 取值0-1之间,表示渐变中开始与结束之间的位置 color表示渐变颜色
注意,这里添加渐变颜色的对象并不是context,而是gradient
怎么用呢?看线性渐变一个小例子:
这个科普一个误区:
ctx.fillRect(50,50,200,50); var line = ctx.createLinearGradient(50,50,200,50); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)');
这样是错误的,什么都出不来!
照理说,应该是先创建一个图像,然后给这个图形加渐变色,一般的规律都如此,比如画画,比如css,但是canvas不一样,重点来了:canvas凡是设置样式的,必须放在绘图前面 ,怎么理解这句话?
绘图的方法: fill() , fillRect() , stroke() , strokeRect() , rect()
那设置:比如文字类字体,字体大小,字体颜色,字体阴影,渐变色 路径类如线条,矩形,圆形,背景,渐变等等
所以正确的格式是:
var line = ctx.createLinearGradient(50,50,200,50); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,50);
可以看到canvas一样可以自定义颜色,支持各种颜色格式,支持指定位置(用0-1的数,跟百分比类似),相比css3之下,我觉得canvas的渐变颜色区域更加准确!
好了,既然canvas能像css3一样设置渐变样式,那可不可以设置方向呢?怎么设?以上面的代码为例,我们画一张图:
图可能画的有点蒙啊,解释一下,第一张图表示我们上面的代码显示的效果,渐变方向是(50,50)——> (200,50),是一条水平线,表示方向是从左到右渐变,要是我将坐标方向设为(50,50)——> (200,100),如第二张图,那么渐变是否是从左上角到右下角呢?我们试一下:
var line = ctx.createLinearGradient(50,50,200,100); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,50);
可以看出角度是正确的,createLinearGradient的2个坐标就是为了指明渐变方向的,那么canvas的径向渐变会不会跟css3相同呢?我们写一个小例子:
var line = ctx.createRadialGradient(150,150,0,150,150,200); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,150);
可以看到,如果图形即使不是一个正方形,径向渐变的圆依然是正圆,与css3的渐变机制有点不一样(css3是椭圆,看上面的css3图),并且渐变区域是根据两个圆来决定的,我们改一下这2个圆的区域看看:
var line = ctx.createRadialGradient(150,150,50,150,150,100); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,150);
比对上面的图可以看出,下图在50-100的区间里是有渐变的,其他地方则是首尾的颜色填充,那么圆心在边角上呢?
var line = ctx.createRadialGradient(50,50,0,50,50,200); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,150);
效果跟css3的样式一样,颜色更加准确,如果2圆的圆心不一样,会有什么反应?
var line = ctx.createRadialGradient(50,50,0,150,150,200); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillRect(50,50,200,150);
一个圆心在左上角,一个圆心在中间
咦,什么鬼,算了,如果想要正常的径向渐变,还是同圆心吧,不同圆心太诡异,hold 不住啊!
那径向渐变能像css3一样可以设置椭圆吗?咳咳,我只能借用一句台词:臣妾做不到啊!
我们来一个炫酷的渐变应用:
ctx.font = "40px 微软雅黑"; var line = ctx.createLinearGradient(10,100,200,100); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.fillText("狂拽炫酷吊炸天",10,100);
下面我们介绍另外一个与颜色有关的属性——透明!
globalAlpha = num 参数:num取值0-1之间 设置或返回绘图的当前透明值
有同学会问,按这个词的意思是全局透明,那么它是全局的吗?我也想问,那我们试一下:
ctx.fillStyle = "red"; ctx.fillRect(50,50,100,100); ctx.globalAlpha = 0.5; ctx.fillStyle = "green"; ctx.fillRect(100,100,100,100); ctx.fillStyle = "blue"; ctx.fillRect(150,150,100,100);
可以看到,第一个没有变透明,后面2个变透明了,那么如果我将路径闭合,是否还会出现这样的效果:
ctx.beginPath(); ctx.fillStyle = "red"; ctx.fillRect(50,50,100,100); ctx.closePath(); ctx.globalAlpha = 0.5; ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(100,100,100,100); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.fillRect(150,150,100,100); ctx.closePath();
结果是一样的,说明它是”人“如其名啊,果然是全局的,那么将它放入闭合路径中,会污染其他的路径吗?
ctx.beginPath(); ctx.globalAlpha = 0.5; ctx.fillStyle = "red"; ctx.fillRect(50,50,100,100); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(100,100,100,100); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.fillRect(150,150,100,100); ctx.closePath();
马蛋,简直是严重的核污染啊,穿透力如此之强?如果我只想让第一个透明,后面的不透明?我要怎么弄呢?
为了解决这个问题,我们需要引入2个方法,同样是一对活宝啊:
context.save() 保存当前环境的状态
context.restore() 返回之前保存过的路径状态和属性
怎么理解这对活宝呢?
可以这么理解:当设置了save()方法,就相当于将后面的绘图放在一个堆栈中,与世隔绝,知道看到restore(),就返回到原来的位置,举个例子哈,就像是一堆糖果,save()就是将一部分糖果装进盒子,restore()就是封闭盒子,继续捡糖果,但是盒子里的糖果就不会与其他糖果混合了,恩,可以这么理解,特别注意的是,restore()方法必须要有save()才起作用,你想啊,都没有盒子装糖果,怎么能封闭盒子呢
那咱们来看看他们的神奇技能:
ctx.save(); ctx.beginPath(); ctx.globalAlpha = 0.5; ctx.fillStyle = "red"; ctx.fillRect(50,50,100,100); ctx.closePath(); ctx.restore(); ctx.beginPath(); ctx.fillStyle = "green"; ctx.fillRect(100,100,100,100); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "blue"; ctx.fillRect(150,150,100,100); ctx.closePath();
哎呀,瞬间觉得整个世界都完美了!在面对凶悍的全局变量,属性或方法时,我们可以用上面的这对活宝来避免它们对我们需要的部分的侵害(这里为什么要说侵害,会让人想污的),确实是好技能!
回到globalAlpha,它的用处还是有很多的,路径,图形,文字都可以设置透明,那我们来一个文字透明看看:
ctx.font = "40px 微软雅黑"; var line = ctx.createLinearGradient(10,100,200,100); line.addColorStop(0,'red'); line.addColorStop(0.2 ,'#0F0'); line.addColorStop(0.5 ,'rgb(51,102,255)'); line.addColorStop(1 ,'rgba(204,255,0,0.8)'); ctx.fillStyle = line; ctx.globalAlpha = 0.3; ctx.fillText("狂拽炫酷吊炸天",10,100);
恩,今天就介绍到这里吧,后面的内容比较复杂,需要认真的准备,就这样吧!
以上就是canvas API ,通俗的canvas基础知识(三) 的内容,更多相关内容请关注PHP中文网(www.php.cn)!
相关文章:
canvas API 介绍,常见的canvas基础知识(一)