上次我们一起学习了canvas对于颜色与透明的调整,今天我们来学习一下线型、渐变、图案与阴影的相关知识。

首先是线型,在canvas对象中我们可以用一系列的属性来控制线的样式。

lineWidth = value

lineCap = type

lineJoin = type

miterLimit = value

我觉得用例子来讲解要比单纯的介绍好得多,这也是我一贯的风格。让我们先上代码:

function draw() {

var ctx = document.getElementById('canvas').getContext('2d');

for (var i = 0; i < 10; i++){

ctx.lineWidth = 1+i;

ctx.beginPath();

ctx.moveTo(5+i*14,5);

ctx.lineTo(5+i*14,140);

ctx.stroke();

}

}

这个例子绘制了十条粗细不一的线,那么就让我们来熟悉一下这个属性:lineWidth。

lineWidth设置当前绘线的粗细,属性值必须为正数,默认为1.0.

线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半。因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。

例子中最左边的以及所有宽度为奇数的线并不能精确呈现,这就是因为路径的定位问题。

想要获得精确的线条,必须对线条是如何描绘出来的有所理解。见下图,用网格来代表canvas的坐标格,每一格对应屏幕上一个像素点。在第一个图中,填充了(2,1)至(5,5)的矩形,整个区域的边界刚好落在像素边缘上,这样就可以得到的矩形有着清晰的边缘。原谅我从教学网站上当的图片吧,我也不想的,要是我自己画打死你们也学不会了。。。

如果你想要绘制一条从(3,1)到(3,5),宽度是1.0的线条,你会得到像第二幅图一样的结果。实际填充区域(深蓝色部分)仅仅延伸至路径两旁各一半像素。而这半个像素又会以近似的方式进行渲染,这意味着那些像素只是部分着色,结果就是以实际笔触颜色一半色调的颜色来填充整个区域(浅蓝和深蓝的部分)。这就是上例中为何宽度为1.0的线并不准确的原因。

要解决这个问题,你必须对路径施以更加精确的控制。已知粗1.0的线条会在路径两边各延伸半像素,那么像第三幅图那样绘制从(3.5,1)到(3.5,5)的线条,其边缘正好落在像素边界,填充出来就是准确的宽为1.0的线条。

对于那些宽度为偶数的线条,每一边的像素数都是整数,那么你想要其路径是落在像素点之间 (如那从(3,1)到(3,5)) 而不是在像素点的中间。同样,注意到那个例子的垂直线条,其Y 坐标刚好落在网格线上,如果不是的话,端点上同样会出现半渲染的像素点。

虽然开始处理可缩放的2D图形时会有点小痛苦,但是及早注意到像素网格与路径位置之间的关系,可以确保图形在经过缩放或者其它任何变形后都可以保持看上去蛮好:线宽为1.0的垂线在放大2倍后,会变成清晰的线宽为2.0,并且出现在它应该出现的位置上。

好了,我们弄明白直线的着色问题后,继续学习下一个属性:lineCap。

属性lineCap的指决定了线段端点显示的样子。它可以为下面的三种的其中之一:butt,round 和square。默认是butt。

无例子,无学习。来,让我们上代码:

function draw() {

var ctx = document.getElementById('canvas').getContext('2d');

var lineCap = ['butt','round','square'];

// Draw guides

ctx.strokeStyle = '#09f';

ctx.beginPath();

ctx.moveTo(10,10);

ctx.lineTo(140,10);

ctx.moveTo(10,140);

ctx.lineTo(140,140);

ctx.stroke();

// Draw lines

ctx.strokeStyle = 'black';

for (var i=0;i<lineCap.length;i++){

ctx.lineWidth = 15;

ctx.lineCap = lineCap[i];

ctx.beginPath();

ctx.moveTo(25+i*50,10);

ctx.lineTo(25+i*50,140);

ctx.stroke();

}

}

来,我们分析一下代码。前半段绘制了两条辅助线,目的是让大家看清楚这个属性赋不同值的区别。然后后半段用循环来遍历了lineCap的所有参数项并一一赋值。三条线的起点和重点都落在辅助线之中。

最左边的线用了默认的butt。可以注意到它是与辅助线齐平的。中间的是round的效果,端点处加上了半径为一半线宽的半圆。右边的是square的效果,端点出加上了等宽且高度为一半线宽的方块。

现在对于直线我们掌握的差不多了,但是新的问题又出来了。我们怎么去绘制两条线段连接的地方呢?是圆角弧还是直角?还是别的什么?用路径方法去描边填充?当然不是。让我们来学习这个新的属性:lineJoin

先来一段代码吧,大量代码是知识的基础嘛:

function draw() {

var ctx = document.getElementById('canvas').getContext('2d');

var lineJoin = ['round','bevel','miter'];

ctx.lineWidth = 10;

for (var i=0;i<lineJoin.length;i++){

ctx.lineJoin = lineJoin[i];

ctx.beginPath();

ctx.moveTo(-5,5+i*40);

ctx.lineTo(35,45+i*40);

ctx.lineTo(75,5+i*40);

ctx.lineTo(115,45+i*40);

ctx.lineTo(155,5+i*40);

ctx.stroke();

}

}

lineJoin的属性值决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round,bevel和miter。默认是miter。

在这个例子中,我们定义了三个连接方式,分别设置了不同的lineJoin值。第一次是round的效果,角被磨成了圆角弧。第二次是bevel效果,角变成了平的。第三次是miter的效果,线段延伸直到交于一点,延伸效果受到下面将要介绍的miterLimit属性的制约。

miterLimit又是干啥的呢?就像刚才看到的milter的效果,线段向外延伸交汇在一起。这俩线段之间的夹角至关重要,要是角度较大,好的,出去没多远俩就能遇上。但是要是角度比较小的话,那就麻烦咯,延长的长度将承指数级上升。。。

miterLimit属性就是用来设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了bevel。

老规矩,来代码吧:

function draw() {

var ctx = document.getElementById('canvas').getContext('2d');

// Clear canvas

ctx.clearRect(0,0,150,150);

// Draw guides

ctx.strokeStyle = '#09f';

ctx.lineWidth   = 2;

ctx.strokeRect(-5,50,160,50);

// Set line styles

ctx.strokeStyle = '#000';

ctx.lineWidth = 10;

//Set miterLimit value

ctx.miterLimit = 10;

// Draw lines

ctx.beginPath();

ctx.moveTo(0,100);

for (i=0;i<24;i++){

var dy = i%2==0 ? 25 : -25 ;

ctx.lineTo(Math.pow(i,1.5)*2,75+dy);

}

ctx.stroke();

return false;

}

这个例子我做了点小小的改动,原例是由input标签输入miterLimit属性,我这里为了方便大家学习,直接写死了,望谅解。

大家可以更改这个数值,自己看一下变化,相信就会对这个简单的属性有一个直接的认识了。

今天我们的学习就先到这里吧,下次我们将进行渐变的学习,我们下次见~

转载于:https://www.cnblogs.com/xiao-yao/archive/2012/04/13/2445965.html

canvas元素简易教程(7)(大部分转自火狐,自己只写了简单的代码分析)相关推荐

  1. canvas元素简易教程(3)(大部分转自火狐,自己只写了简单的代码分析)

    记得我们上次学了什么么?矩形.路径.填充.回忆一下以前的东西,我们有什么用到却没有学过的呢?对了,那一个大笑脸不是都是圆弧么,它咋做到的呢? 别急别急,咱们慢慢来~ 我们用arc方法来绘制弧线或圆.标 ...

  2. WebGL简易教程(十一):纹理

    文章目录 1. 概述 2. 实例 2.1. 准备纹理 2.2. 配置纹理 2.3. 使用纹理 3. 结果 4. 参考 1. 概述 在之前的之前的教程<WebGL简易教程(九):综合实例:地形的绘 ...

  3. WebGL简易教程(十):光照

    目录 1. 概述 2. 原理 2.1. 光源类型 2.2. 反射类型 2.2.1. 环境反射(enviroment/ambient reflection) 2.2.2. 漫反射(diffuse ref ...

  4. 文件上传利器SWFUpload入门简易教程

    凡做过网站开发的都应该知道表单file的确鸡肋. Ajax解决了不刷新页面提交表单,但是却没有解决文件上传不刷新页面,当然也有其它技术让不刷新页面而提交文件,该技术主要是利用隐藏的iFrame, 较A ...

  5. Ocelot简易教程(五)之集成IdentityServer认证以及授权

    最近比较懒(编者注:作者不是真懒,而是在憋大招,他最近实现了把Ocelot的配置使用数据库存储),所以隔了N天才来继续更新第五篇Ocelot简易教程,本篇教程会先简单介绍下官方文档记录的内容然后在前几 ...

  6. Ocelot简易教程(三)之主要特性及路由详解

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9664977.html 上篇<Ocelot简易教程(二)之快速开始2>教大家如何快速跑起来一个 ...

  7. python绘制曲线y=2x+5_Python Matplotlib 简易教程

    原标题:Python Matplotlib 简易教程 简单演示 import matplotlib.pyplot as plt import numpy as np # 从[-1,1]中等距去50个数 ...

  8. Paypal国际版网站集成简易教程

    转自:http://www.chenchen.org/article/paypal/4.htm Paypal国际版网站集成简易教程(一):序言 前段时间接到一个外贸网站的项目,集成paypal支付接口 ...

  9. WebGL简易教程(十五):加载gltf模型

    文章目录 1. 概述 2. 实例 2.1. 数据 2.2. 程序 2.2.1. 文件读取 2.2.2. glTF格式解析 2.2.2.1. 场景节点 2.2.2.2. 网格 2.2.2.3. 缓冲,缓 ...

最新文章

  1. vmware 8 精简 安装版_被困免安装版下载
  2. 初中计算机课教什么时候,初中计算机教学课程教学方法探讨
  3. java泛型中的E,K,V,T,U,S
  4. python前n项和存为一个数组_在Python中存储多个数组
  5. 简单几步,教你在mac电脑上轻松启用悬停文本!
  6. linux 日志报告生成器,Linux报告生成器工具awk
  7. windows-7:系统利用终端cmd命令关机
  8. 为什么数据科学家需要承担开发运维的工作?
  9. centos7yum安装VirtualBox
  10. Python基础应用-摄氏温度换算
  11. python format是什么意思_python的format什么意思
  12. java私聊_java Socket实现多人群聊与私聊功能
  13. java获取date的时分秒_java Date简单的 获得时分秒代码
  14. java技术--报警通知及实现方式
  15. 使用opentelemetry-go操作Jaeger
  16. iOS UITextView调整行间距
  17. 2016全球大数据战略版图剖析(6):应用篇下
  18. 操作系统——放置策略
  19. 南加大计算机硕士学制,南加州大学研究生学制几年
  20. 理解图像中的高频、低频分量

热门文章

  1. javaweb实训第五天上午——Spring基础
  2. Http Body 的四种格式
  3. 水桶平分 java_关于java:桶排序算法代码问题
  4. swift 引用其他类_浅谈swift中闭包修饰符 weak?unowned? 或什么都不用
  5. python接管已经打开的浏览器_Python Webdriver 从新使用已经打开的浏览器实例
  6. 计算机系统的输入与输出接口是,计算机输入输出系统与接口技术
  7. java四种内部类区别_浅谈Java中的四种内部类
  8. React中StrictMode严格模式
  9. vue多个根节点上的属性继承
  10. 什么是虚拟DOM(React16源码分析)