【中篇】 -- 建议学习时间4小时  课程共(上中下)三篇

此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例,建议大家学习10~15个小时,里面的案例请挨个敲一遍,这样才能转化为自己的知识。

技术要求:有html/css/js基础。

颜色


为canvas添加颜色我们使用 fillStyle 和 strokeStyle,在上一篇中我们已经简单的使用过

fillStyle = color
设置图形的填充颜色。
strokeStyle = color
设置图形轮廓的颜色。

其中的 color可以是   颜色名/颜色值/rgba等等

例子:绘制多彩方块

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); for(var i=0; i<6; i++){
for(var j=0; j<6; j++){
ctx.fillStyle = 'rgb('+Math.floor(255-42.5*i)+','+Math.floor(255-42.5*j)+',0)';
ctx.fillRect(150+j*25,50+i*25,25,25);
}
}

例子:绘制多彩圆圈

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); for(var i=0; i<6; i++){
for(var j=0; j<6; j++){
ctx.strokeStyle = 'rgb(0,'+Math.floor(255-42.5*i)+','+Math.floor(255-42.5*j)+')';
ctx.beginPath();
ctx.arc(150+j*25,50+i*25,10,0,Math.PI*2,true);
ctx.stroke();
}
}

透明度


全局透明度:

ctx.globalAlpha = transparencyValue
这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。

下面代码设置全局透明度为 0.3,后续绘制的所有图像,都会是0.3的透明度。

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.globalAlpha = 0.3;//设置全局透明度
ctx.fillStyle = "red"; //设置颜色
ctx.fillRect(50,50, 100, 100); //绘制方块

例子:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.fillStyle = "#fd0";
ctx.fillRect(0,0,75,75);
ctx.fillStyle = "#6c0";
ctx.fillRect(75,0,75,75);
ctx.fillStyle = "#09f";
ctx.fillRect(0,75,75,75);
ctx.fillStyle = "#f30";
ctx.fillRect(75,75,75,75);
ctx.fillStyle = "#fff"; //设置透明值
ctx.globalAlpha = 0.2;
for(var i=0; i<7; i++){
ctx.beginPath();
ctx.arc(75, 75, 10+10*i, 0, Math.PI*2, true);
ctx.fill();
}

这种设置全局透明度的方式不好控制,我们通常通过设置 rgba 颜色值的透明度来设置透明

例子:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.fillStyle = "#fd0";
ctx.fillRect(0,0,150,37.5);
ctx.fillStyle = "#6c0";
ctx.fillRect(0,37,150,37.5);
ctx.fillStyle = "#09f";
ctx.fillRect(0,75,150,37.5);
ctx.fillStyle = "#f30";
ctx.fillRect(0,112,150,37.5);
ctx.fillStyle = "#fff";
for(var i=0; i<10; i++){
ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
for(var j=0; j<4; j++){
ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
}
}

渐变色


线性渐变  createLinearGradient(x1, y1, x2, y2)
createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。

径向渐变  createRadialGradient(x1, y1, r1, x2, y2, r2)
createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。

创建出 canvasGradient 对象后,我们就可以用 addColorStop 方法给它上色了。

gradient.addColorStop(position, color)
addColorStop 方法接受 2 个参数,position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。

线性渐变 示例:

代码如下:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线性渐变
var lineargradient = ctx.createLinearGradient(0,0,0,140);
lineargradient.addColorStop(0,'#00ABEB');
lineargradient.addColorStop(0.5, "#fff");
lineargradient.addColorStop(0.5, "green");
lineargradient.addColorStop(1,'#fff'); var lineargradient2 = ctx.createLinearGradient(0,50,0,95);
lineargradient2.addColorStop(0,'#000');
lineargradient2.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle = lineargradient;
ctx.strokeStyle = lineargradient2; ctx.fillRect(10,10,130,130);
ctx.strokeRect(50,50,50,50);

径向渐变 示例:

代码如下:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); /*径向渐变*/
var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);
radgrad.addColorStop(0, "#fff");
radgrad.addColorStop(0.9, "green");
radgrad.addColorStop(1, "rgba(255,255,255,0)"); //最后一个颜色最好写成透明的,这样圆圈以外部分会以这个颜色填充 var radgrad2 = ctx.createRadialGradient(112,120,0,112,120,50);
radgrad2.addColorStop(0, "#fff");
radgrad2.addColorStop(0.9, "#FF0188");
radgrad2.addColorStop(1, "rgba(255,1,136,0)"); var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);
radgrad3.addColorStop(0, '#00C9FF');
radgrad3.addColorStop(0.8, '#00B5E2');
radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); ctx.fillStyle = radgrad;
ctx.fillRect(0,0,150,150); ctx.fillStyle = radgrad2;
ctx.fillRect(0,0,200,200); ctx.fillStyle = radgrad3;
ctx.fillRect(0,0,200,200);

线宽


lineWidth = value

设置线条宽度。 直接给数值,不需要单位,默认单位为像素

例子:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线宽
for(var i=0; i<10; i++){
ctx.lineWidth = i+1;
ctx.beginPath();
var a = 5;
ctx.moveTo(a+i*14, 5);
ctx.lineTo(a+i*14, 140);
ctx.stroke();
}

大家会发现,我们绘制出的线条中,基数线条居然是模糊的

那这是什么原因呢!见下图,用网格来代表 canvas 的坐标格,每一格对应屏幕上一个像素点。在第一个图中,填充了 (2,1) 至 (5,5) 的矩形,整个区域的边界刚好落在像素边缘上,这样就可以得到的矩形有着清晰的边缘。

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

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

以此原理,我们只要将原来绘制过程中的基数线条 +0.5 像素即可

代码修改如下(修改地方在9/10行):

         var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线宽
for(var i=0; i<10; i++){
ctx.lineWidth = i+1;
ctx.beginPath();
var a = 5;
if(i%2 == 0){
a = 5.5; //基数像素避免模糊
}
ctx.moveTo(a+i*14, 5);
ctx.lineTo(a+i*14, 140);
ctx.stroke();
}

这样呈现的效果就不模糊了

线条样式


lineCap = type 设置线条末端样式。它可以为下面的三种的其中之一:butt,round 和 square。默认是 butt。

示例:

代码如下:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线条末尾样式
var lineCap = ['butt','round','aquare'];
ctx.strokeStyle = "#09f";
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(140,10);
ctx.moveTo(10,140);
ctx.lineTo(140,140);
ctx.stroke(); 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();
}

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

示例:

代码如下:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线条链接处样式
var lineJoin = ['round','bevel','miter'];
ctx.strokeStyle = "#09f";
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();
}

虚线


ctx.setLineDash([x1, x2]); //设置设置虚线的间隔 x1表示虚线自身长度 x2表示间隔长度  默认单位:px
ctx.lineDashOffset = offset; //设置偏移量
ctx.strokeRect(x,y, width, height); //绘制虚线边框

例子:跑马灯效果

代码如下:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //虚线
ctx.strokeStyle = "#09f";
ctx.lineWidth = 4;
var offset = 0; function draw(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.setLineDash([4,2]);
ctx.lineDashOffset = - offset;
ctx.strokeRect(100,100,100,100);
} function march(){
offset++;
if(offset > 16){
offset = 0;
}
draw();
setTimeout(march, 20)
}
march();

描绘文字


canvas 提供了两种方法来渲染文本:

fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.

strokeText(text, x, y [, maxWidth])
在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.

文本设置(可不掌握):

font = value
当前我们用来绘制文本的样式. 这个字符串使用和 CSS font 属性相同的语法. 默认的字体是 10px sans-serif。
textAlign = value
文本对齐选项. 可选的值包括:start, end, left, right or center. 默认值是 start。
textBaseline = value
基线对齐选项. 可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。
direction = value
文本方向。可能的值包括:ltr, rtl, inherit。默认值是 inherit。

另外可以使用 measureText 来测量文本长度 (单位px)

示例:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //线条链接处样式
ctx.strokeStyle = "#09f";
ctx.lineWidth = 1; ctx.font = "48px Arial";
ctx.fillText("Hellow World ! " , 50, 100); ctx.strokeText("Hellow World ! ", 50, 200);
/* 测量文本长度 */
var text = ctx.measureText("Hellow World ! ");
ctx.fillText(text.width , 50, 300);

绘制阴影


通过 ctx.shadow来设置

例子:

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); /* 阴影 */
ctx.shadowOffsetX = 2; //阴影x方向偏移量
ctx.shadowOffsetY = 2; //阴影y方向偏移量
ctx.shadowBlur = 5; //阴影模糊度
ctx.shadowColor = "rgba(0,0,0,0.5)"; //阴影颜色 ctx.font = "20px Times New Roman";
ctx.fillStyle = "black";
ctx.fillText("Sample String", 5, 30);

效果:

 绘制图片


使用 drawImage(image, x, y)

其中 image 是 Image对象 或者 canvas 对象,x 和 y 是其在目标 canvas 里的起始坐标。

示例(图片使用了网络图片,所以地址比较长):

        var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); var img = new Image(); //创建了一个Image对象
img.src = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507713846845&di=51e9f2958ed57789a0fa8e656a8c57c8&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimage%2Fc0%253Dshijue1%252C0%252C0%252C294%252C40%2Fsign%3D952c2aeb14178a82da3177e39e6a19f8%2Fb8014a90f603738dbe7ddc05b91bb051f819ece6.jpg";
img.onload = function(){
ctx.drawImage(img,50,50,300,190); //将图片绘制到canvas中
}

这里绘制图片也可以使用 从页面获取的 Img dom对象,如:  ctx.drawImage(document.getElementsByTagName("img")[0],100,100,300,190);

图片导出/下载图片


使用c.toDataURL()对canvas图片数据进行输出

示例:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{margin: 0;padding: 0}
body{
margin: 30px;
}
canvas{
border: 1px solid #a4e2f9;
float: left;
}
img{
float:left;
margin: 0 10px;
} </style>
</head>
<body>
<canvas height="300" width="300" id="myCanvas"></canvas>
<img id="showImg" src="" alt=""/>
<a id="downloadBtn" href="" download="testImg">下载</a>
<!-- a标签设置 download="图片名称" 来设置点击下载 --> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.fillStyle = "#fd0";
ctx.fillRect(0,0,150,37.5);
ctx.fillStyle = "#6c0";
ctx.fillRect(0,37,150,37.5);
ctx.fillStyle = "#09f";
ctx.fillRect(0,75,150,37.5);
ctx.fillStyle = "#f30";
ctx.fillRect(0,112,150,37.5);
ctx.fillStyle = "#fff";
for(var i=0; i<10; i++){
ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
for(var j=0; j<4; j++){
ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
}
} //将canvas生成的图像 链接到 img标签 和 a标签下载链接中
document.getElementById("showImg").setAttribute("src",c.toDataURL('png')); //输出为png格式
document.getElementById("downloadBtn").setAttribute("href",c.toDataURL('png')); </script>
</body>
</html>

获取和操作canvas像素信息


可以用getImageData()方法,获得一个包含画布场景像素数据的ImageData对像
var myImageData = ctx.getImageData(left, top, width, height);

你可以用putImageData()方法去对场景进行像素数据的写入。
ctx.putImageData(myImageData, dx, dy);
dx和dy参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标。

下面示例中,我们获取canvas已经绘制的图形信息,然后经过去色处理,然后再在旁边重新绘制去色的图形,具体解释在代码注释中

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
*{margin: 0;padding: 0}
body{
margin: 30px;
}
canvas{
border: 1px solid #a4e2f9;
}
</style>
</head>
<body>
<canvas height="300" width="600" id="myCanvas"></canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); ctx.fillStyle = "#fd0";
ctx.fillRect(0,0,150,37.5);
ctx.fillStyle = "#6c0";
ctx.fillRect(0,37,150,37.5);
ctx.fillStyle = "#09f";
ctx.fillRect(0,75,150,37.5);
ctx.fillStyle = "#f30";
ctx.fillRect(0,112,150,37.5);
ctx.fillStyle = "#fff";
for(var i=0; i<10; i++){
ctx.fillStyle = "rgba(255, 255, 255,"+ (i+1)/10 +")";
for(var j=0; j<4; j++){
ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5);
}
} //获取canvas的图片数据
var imageData = ctx.getImageData(0, 0, 150, 150); //获取canvas的绘制区域的像素信息
var idata = imageData.data; //真实的像素rgba信息在 data中
console.log(idata)
/*
idata中的数据是一个数组,每四个分别代表一个像素点的 r g b a 值 ,如下:
[159,159,159,255,159,159,159,255......]
R - 红色 (0-255)
G - 绿色 (0-255)
B - 蓝色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
*/ for(var i=0; i<idata.length; i+=4){
var avg = (idata[i]+idata[i+1]+idata[i+2])/3;
idata[i] = avg; // red
idata[i + 1] = avg; // green
idata[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 200, 0); </script>
</body>
</html>

今天就讲到这里,下节课我们讲解:canvas变换 / 路径保存 / 综合案例

关注公众号,博客更新即可收到推送

canvas学习笔记(中篇) -- canvas入门教程-- 颜色/透明度/渐变色/线宽/线条样式/虚线/文本/阴影/图片/像素处理的更多相关文章

  1. canvas学习笔记:canvas对图片的像素级处理--ImageData的应用

    学习了canvas的基本绘图功能后,惊喜的发现canvas对图片数据也有相当强大的处理功能,能够从像素级别操作位图,当然[lte ie8]不支持. 主要的函数有三个: ctx.createImageD ...

  2. canvas学习笔记、小函数整理

    http://bbs.csdn.net/topics/391493648 canvas实例分享 2016-3-16 http://bbs.csdn.net/topics/390582151 html5 ...

  3. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

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

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

  5. 学习笔记《简明python教程》

    学习笔记<简明python教程> 体会:言简意赅,很适合新手入门 2018年3月14日21:45:59 1.global 语句 在不使用 global 语句的情况下,不可能为一个定义于函数 ...

  6. iOS学习笔记-地图MapKit入门

    代码地址如下:http://www.demodashi.com/demo/11682.html 这篇文章还是翻译自raywenderlich,用Objective-C改写了代码.没有逐字翻译,如有错漏 ...

  7. Hadoop学习笔记(1) ——菜鸟入门

    Hadoop学习笔记(1) ——菜鸟入门 Hadoop是什么?先问一下百度吧: [百度百科]一个分布式系统基础架构,由Apache基金会所开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序. ...

  8. canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)

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

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

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

随机推荐

  1. Spring p名称空间配置属性

    1.p 名称空间介绍 从 2.0开始,Spring支持使用名称空间的可扩展配置格式.这些名称空间都是基于一种XML Schema定义.事实上,我们所看到的所有bean的配置格式都是基于一个 XML S ...

  2. 20172333 2017-2018-2 《Java程序设计》第5周学习总结

    20172333 2017-2018-2 <Java程序设计>第5周学习总结 教材学习内容 1.if语句.if-else语句.switch语句 都是通过对于布尔表达式的结果来进行是否执行下 ...

  3. 【Data URL】【RE】【bugku】逆向入门writeup

    在写wp之前先来了解一下Data URL是什么 Data URL 在浏览器向服务端发送请求来引用资源时,一般浏览器都有同一时间并发请求数不超过4个的限制.所以如果一个网页需要引用大量的服务端资源,就会 ...

  4. 洛谷 [AHOI2001]质数和分解

     题目描述 Description 任何大于 1 的自然数 n 都可以写成若干个大于等于 2 且小于等于 n 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式.例 ...

  5. BZOJ 4028: [HEOI2015]公约数数列 分块

    4028: [HEOI2015]公约数数列 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4028 Description 设计一个数据结 ...

  6. HDU 5626 Clarke and points 平面两点曼哈顿最远距离

    Clarke and points 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5626 Description Clarke is a patie ...

  7. 明尼苏达推荐系统导论(第一课 欢迎来到RS)

    一.RS介绍 1.显示评分:直接从用户来 隐式评分:从用户活动推测得到的 2.预测是偏好的估计,是预测缺失值,推荐是从其他用户推荐项目,是推荐感兴趣的项目. 3.协同表示利用其它用户的数据 二.欢迎来 ...

  8. Objective-C字面量语法总结

    通常情况下,创建数组,字典的时候需要写一些很长的方法名,今天就总结一下如何使用字面量语法代替这些方法. 1.数值的创建 NSNumber *number1 = [NSNumber numberWith ...

  9. 开源轻量级即时通讯技术 MobileIMSDK 的常见问题解答

    本帖最后由 茜茜asa 于 2015-12-14 17:50 编辑 申明:MobileIMSDK 目前为个人原创开源工程且已发布,现整理了一些有关MobileIMSDK的常见的问题,希望对需要的人有用 ...

  10. python部署工具fabric

    两台机器:10.1.6.186.10.1.6.159.fabric部署在10.1.6.186上面 1  执行和1相同的任务,不过排除掉10.1.6.159这台机器 1 #!/usr/bin/pytho ...