Canvas绘图环境中有些属于立即绘制图形方法,有些绘图方法是基于路径的。

立即绘制图形方法仅有两个strokeRect(),fillRect(),虽然strokezText(),fillText()方法也是立即绘制的,但是文本不算是图形。

基于路径的绘制系统
大多数绘制系统,如:SVG(Scalable Verctor Graphics, 可缩放的矢量图形),Adobe Illustrator等,都是基于路径的,

使用这些绘制系统时,你需要先定义一个路径,然后再对其进行描边或填充,也可以描边加填充这样图形才能显示出来。

Canvas中的三种绘制方式:

绘制一条线段

Canvas绘图环境中,线段也是基于路径绘制的,称为线性路径,创建线性路径的方法:moveTO()与lineTo(),在创建路径之后调用stroke()方法,才能在Canvas中画出线段出来。

这就是前面我们所说的基于路径的绘制方法,必须对其进行描边或者填充;

通常两点连一线因此绘制线段非常简单,通过moveTO()指定线的起点,通过lineTo()移动到另一个点。

function drawLine(){
cxt.moveTo(50, 50);
cxt.lineTo(100, 100);
}

然而这样我们在画布中是看不见线段的,前面我们说到基于路径的绘制方法,必须要描边或者填充。所以要想看到结果,我们必须还要使用stroke()方法。

因此我们把方法修改成下面这样就会绘制出一条线段

function drawLine(){
cxt.moveTo(50, 50);
cxt.lineTo(200, 200);
cxt.stroke();
}

我们只使用lineTo()也是能在画布中绘制出线段的,我们把上面的代码改成如下面所示,效果也是一样的

function drawLine(){
cxt.lineTo(50, 50);
cxt.lineTo(200, 200);
cxt.stroke();
}

总结下moveTo()与lineTo()的用法

  • moveTo(x,y): 将笔触移动到指定的坐标x以及y上,向当前路径中增加一条子路径,该方法不会清除当前路径中的任何子路径。
  • lineTo(x,y): 绘制一条从当前位置到指定x以及y位置的直线,如果当前路径中没有子路径,那么这个方法的行为与moveTo()一样。如果当前路径中存在子路径,此方法会将你所指定的这个点加入子路径中。

改变线段的样式

改变线段的宽度

function= 14;
cxt.lineTo(50, 50);
cxt.lineTo(200, 200);
cxt.stroke();
}

改变线段的颜色

function drawLine(){
cxt.lineWidth = 14;
cxt.strokeStyle = 'green';
cxt.lineTo(50, 50);
cxt.lineTo(200, 200);
cxt.stroke();
}

我们还可以利用CanvasGradient对象或者CanvasPattern对象给线段添加渐变色或图案

function drawLine(){
cxt.lineWidth = 14;
var gradient = cxt.createLinearGradient(0, 0, canvas.width/2, canvas.height/2);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'purple');
gradient.addColorStop(1, 'yellow');
cxt.strokeStyle = gradient;
cxt.lineTo(50, 50);
cxt.lineTo(200, 200);
cxt.stroke();
}

beginPath()与closePath()

从上面canvas中的三种绘制方式中我们可以看出,第二行的弧形路径是开放路径,最后一行的弧形是封闭路径。那么封闭的路径是怎么实现的呢?

下面我们来看看canvas中路径绘制中两个比较重要的方法

  • beginPath(): 清除当前所有子路径,以此来重置当前路径,重新规划一条路径。
  • closePath(): 用于封闭某段开放路径。不是必需的,如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。

先绘制出一条折线

function drawLine(){
cxt.strokeStyle = 'green';
cxt.lineWidth = 2;
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.lineTo(150, 150);
cxt.stroke();
}

修改上面例子中的代码在代码中添加beginPath()与closePath()方法

function drawLine(){
//描边三角形
cxt.strokeStyle = 'green';
cxt.lineWidth = 2;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.stroke();
cxt.beginPath();
cxt.lineTo(150, 150);
cxt.lineTo(150, 250);
cxt.stroke();
  cxt.closePath();
}

可以看出我们在画布中绘制了两条路径

注意:调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo()。所以我们在绘制图形的时候一定要先使用beginPath()。

我们继续修改我们的代码

function drawLine(){
//描边三角形
cxt.strokeStyle = 'green';
cxt.lineWidth = 2;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.lineTo(150, 150);
cxt.closePath();
cxt.stroke();
//折线
cxt.translate(150, 0);
cxt.strokeStyle = 'red';
cxt.lineWidth = 2;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.lineTo(150, 150);
cxt.stroke();
cxt.closePath();
//绿色填充三角形
cxt.translate(150, 0);
cxt.fillStyle = 'green';
cxt.lineWidth = 2;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.lineTo(150, 150);
cxt.fill();
cxt.closePath();
//红色填充三角形
cxt.translate(150, 0);
cxt.fillStyle = 'red';
cxt.lineWidth = 2;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(50, 150);
cxt.lineTo(150, 150);
cxt.closePath();
cxt.fill();
}

从上面的例子我们可以看出closePath()的位置不同,也会影响我们的图形

注意:当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以此时closePath()函数不是必须的。

但是调用stroke():如果你在stroke()方法之前只用closePath()会形成闭合路径,如果在stroke()方法之后调用closePath()方法,此时图形已经绘制完成,当前的绘制路径已经关闭,所以closePath()方法不起作用。

线段与像素边界

先来看一个例子

function drawLine(){

    cxt.lineWidth = 1;
cxt.beginPath();
cxt.moveTo(50, 50);
cxt.lineTo(450, 50);
cxt.stroke();
cxt.beginPath();
cxt.moveTo(50.5, 150.5);
cxt.lineTo(450.5, 150.5);
cxt.stroke();
}

从图中我们可以看出,我们将两条线段的lineWidth都是设置为1像素,但是上面的线段画出的却是两像素。

如果你在某2个像素的边界处绘制一条1像素宽的线段,那么该线段实际会占据2个像素的宽度;

因为当你在像素边界处绘制一条1像素宽度的垂直线段时,canvas的绘图环境对象会试着将半个像素画在边界中线的右边,将另外半个像素画在边界中线的左边。

然而,在一个整像素的范围内绘制半个像素宽的线段是不可能的,所以在左右两个方向上的半个像素都被扩展为1个像素。

另外一方面,绘制在两个像素之间,这样的话,中线左右两端的那半个像素就不会延伸,它们结合起来恰好占据1个像素的宽度。所以说,如果要绘制一条真正1像素宽度的线段,你必须将该线段绘制在某两个像素之间

网格的绘制

既然我们已经明白了如何绘制真正的1像素的线段,那我们就开始绘制网格

function drawLine(stepx, stepy){
cxt.lineWidth = 0.5;
cxt.strokeStyle = 'green';
//绘制竖线
for(var i= stepx + 0.5; i< cxt.canvas.width; i+= stepx){
cxt.beginPath();
cxt.moveTo(i, 0);
cxt.lineTo(i, cxt.canvas.height);
cxt.stroke();
}
//绘制横线
for(var i= stepy + 0.5; i< cxt.canvas.height; i+= stepy){
cxt.beginPath();
cxt.moveTo(0, i);
cxt.lineTo(cxt.canvas.width, i);
cxt.stroke();
}
}
drawLine(10, 10);

上面例子中我们将线段绘制在两个像素之间的像素上,而且绘制出来的线段仅有0.5像素宽,

虽说canvas规范没有明文规定,不过所有浏览器的Canvas实现都使用了“抗锯齿”技术,以便创建出“亚像素”线段的绘制效果来

 

总结

本节内容主要讲解canvas中路径中线性路径的绘制方法,主要是利用 moveTo()定义起点,lineTo()定义终点,stroke()描绘当前路径。这三个方法绘制线段

canvas中绘制路径有两个重要的方法,beginPath()与closePath()。绘制图形之前先调用beginPath()是绘制多个图形必要的步骤。

closePath()在使用fill()时是可以省略的,而且还要注意closePath()方法的调用位置。

绘制线段时我们可以使用 lineWidth改变线段的宽度,strokeStyle改变线段的颜色。

弄清楚线段的像素边界,这样我们才能绘制出真正的1像素线宽的线段。

canvas学习总结三:绘制路径-线段的更多相关文章

  1. 【canvas学习笔记三】样式和颜色

    上一节我们学习了如何用路径绘制各种形状,但我们只能用默认的颜色和线条.这节就来学习设置不同的颜色和线条样式. 颜色 设置颜色主要有两个属性: fillStyle = color 设置填充颜色 stro ...

  2. canvas学习(三):文字渲染

    一.绘制基本的文字: var canvas = document.getElementById("myCanvas") var ctx = canvas.getContext('2 ...

  3. OpenGL入门学习 课程 (三) 绘制几何图形的一些细节问题

    http://oulehui.blog.163.com/blog/static/79614698201191832753312/ 先回顾一下我们都学习了些什么: 第一课,编写第一个OpenGL程序第二 ...

  4. canvas学习总结三:绘制虚线

    上一章节我们说到,线性路径的绘制,主要利用movoTo(),lineTo()等方法,当然 Canvas 2D API 也提供了虚线的绘制方法,CanvasRenderingContext2D.setL ...

  5. canvas学习总结六:绘制矩形

    在第三章中(canvas学习总结三:绘制路径-线段)我们提高Canvas绘图环境中有些属于立即绘制图形方法,有些绘图方法是基于路径的. 立即绘制图形方法仅有两个strokeRect(),fillRec ...

  6. Javascript高级编程学习笔记(87)—— Canvas(4)绘制路径

    绘制路径 2D上下文支持许多在画布上绘制路径的方法 通过路径可以创造出复杂的形状和线条,要绘制路径首先必须调用beginPath()方法,表示开始绘制路径 然后再通过下列的方法绘制路径: arc(x, ...

  7. 【canvas学习笔记二】绘制图形

    上一篇我们已经讲述了canvas的基本用法,学会了构建canvas环境.现在我们就来学习绘制一些基本图形. 坐标 canvas的坐标原点在左上角,从左到右X轴坐标增加,从上到下Y轴坐标增加.坐标的一个 ...

  8. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  9. canvas学习笔记(上篇)-- canvas入门教程 -- canvas标签/方块/描边/路径/圆形/曲线

    [上篇] -- 建议学习时间4小时  课程共(上中下)三篇 此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例, ...

随机推荐

  1. Laravel 5.2 教程 - 迁移

    一.简介 迁移(Migrations)是一种数据库的版本控制.可以让团队在修改数据库结构的同时,保持彼此的进度一致.迁移通常会和 结构生成器 一起使用,可以简单的管理数据库结构. 下面以创建学生表的迁 ...

  2. windows下安装Redis并部署成服务

    windows下安装Redis并部署成服务 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 一:下载 下载地址: windows版本: http ...

  3. 一条sql语句引发mysql不停创建临时表的问题解决..coping to tmp table on desk

    (不懂临时表的先看 MySQL临时表 ) 首先,临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间.因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表.     ...

  4. Yeelink初步体验

    环境 Qemu: 2.8.0 开发板:vexpress-ca9   概述     前面的博文已经使我们的虚拟开发板具备了访问外网的目的,离物联网越来越近了.要玩物联网,Yeelink不得不说,它提供了 ...

  5. hdu1420 Prepared for New Acmer 简单数学

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1420 简单数学题 第一次wa在可能和会出现取模后值为负数的情况. 只要会一个数论上的简单公式(a*b) ...

  6. 一分钟应对勒索病毒WannaCry

    一.WannaCry 勒索病毒 勒索病毒WannaCry肆虐全球,利用Windows操作系统漏洞,因链式反应迅猛自动传播,校园电脑.个人电脑.政府机关都是重灾区.中毒电脑所有文档被加密,将被勒索高达3 ...

  7. Spring事务处理

    事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 数据库向用户提供保存当前程序状态的方法,叫事务提交(commit): ...

  8. 【JAVAWEB学习笔记】18_el&jstl&javaee的开发模式

    一.EL技术 1.EL 表达式概述 EL(Express Lanuage)表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL 出现的目的是要替代jsp页面中脚本的编写. 2.EL从域中取出数据 ...

  9. 用kotlin方式打开《第一行代码:Android》

    参考:<第一行代码:Android>第2版--郭霖 注1:本文为原创,例子可参考郭前辈著作:<第一行代码:Android> 注2:本文不赘述android开发的基本理论,不介绍 ...

  10. 在Linux下的找不同-打补丁

    Q:为什么要找不同,为什么要打补丁? A: 在Linux应用中,作为DBA,我们知道MySQL跑在Linux系统之上,数据库最重要的追求就是性能,"稳"是重中之重,所以不能动不动就 ...