canvas的笔记分享

221 阅读7分钟

developer.mozilla.org/zh-CN/docs/…

手机上的定时器能设置时间间隔到16(性能原因),更流畅,而电脑上一般是30;

  1. IE8及以下不支持canvas,可以不用带单位px,画的都是一个个的像素点,是位图

  2. beginPath closePath中间只需要包含路径的信息,不用包含strokeStyle fillStyle lineWidth等信息。

  3. closePath的作用,如果路径不是封闭的,使用后就会封闭路径,而且会对接头处进行处理。

  4. canvas是内嵌块元素。 是基于状态的绘制,状态分为路径和属性,line arc等是路径, strokeStyle等是属性

  5. beginPath和closePath不一定要成对出现,beginPath表示要重新规划一段状态,属性没改的话使用之前的属性,路径使用新路径,closePath表示要结束一段路径, fill也不必须closePath.使用beginPath后的第一个lineTo相当于moveTo。

  6. fill 填充 可以不必是封闭的图形。

  7. cxt.save(); cxt.restore(); 【注意:一直是上下文环境在save restore,而不是cavas标签本身在旋转等等】 在中间可以任意变形,之后恢复原来的状态,不会影响其他的绘图。

    #canvas
    ctx.save()      // 清除状态(颜色、旋转、缩放)
    ctx.beginPath() // 清除路径
    ...
    ctx.closePath() // 闭合-封闭
    ctx.restore()
    
    ctx.strokeRect() // 线框
    ctx.fillRect()   // 填充
    ctx.clearRect()  // 清除
    

关于当前路径和子路径,下面文档有对beginPath 和 closePath 有比较清晰的解释。 juejin.cn/post/684490… 填充路径的“非零环绕规则” 部分,示意了在fill的时候,因为当前 path 的 子路径的方向不同而 fill 出了空心的效果。】

image.png

image.png

ctx.beginPath();
ctx.strokeStyle = "pink";
ctx.fillStyle = "blue";
ctx.lineWidth = 5;

ctx.moveTo(30, 10);
ctx.lineTo(30, 200);//绘制子路径
ctx.lineTo(230, 200);
ctx.closePath();

// 这个地方比较重要,标识是否清除旧的子路径并开始新的当前路径,可以打开关闭试试看
// ctx.beginPath();
ctx.lineTo(40, 40);
ctx.lineTo(180, 180);
ctx.lineTo(40, 180);
ctx.lineTo(40,40);

// 注意fill与stroke的顺序,如果fill()在后,会把stroke()后的部分描边覆盖掉
// 这个是因为 stoke 是从中间往两边画的
ctx.stroke();
ctx.fill();
  1. scale的副作用: 影响x,y lineWidth等
  2. transform和setTransform 图形变换矩阵
  3. 渐变 createLinearGradient
  4. createPattern 参数image是给 new Image()的对象(不是cxt上下文) 或者一个canvas对象document.createElement('canvas');或者video
  5. globalAlpha全局透明度
  6. globalCompositeOperation遮挡关系
  7. clip 剪辑区域范围的内容才被画出来
// 在使用 Path2D 的方式去clip的时候,要把 Path2D 实例作为参数传入 clip 函数,否则就是clip掉了整个 canvas。如下:
let svgpath = "M30.3,46.5a37.3,37.3,0,0,1,45-26.36c41.08,10.37,99.31,36,51.18,93.73-70,84-105,61-106,5C20,91.41,25,65.64,30.3,46.5Z"
let p = new Path2D(svgpath);
ctx.closePath();
ctx.stroke(p);
ctx.clip(p);
// 而通过正常画 path 的方式画路径,之后 clip 的话,ctx.clip() 即可
ctx.beginPath();

ctx.moveTo(50, 150);
ctx.bezierCurveTo(130,  130,  110,  60,  260,  50);
ctx.arcTo(230, 160, 20, 220, 70);
ctx.closePath();
ctx.stroke();

ctx.clip();
  1. canvas默认的宽高是 300*150, canvas没有z-index的概念,它的优先级是通过画的顺序确定的,后画的图案在上面显示。

    canvas给width和height与在style里面给width height的区别:不在style里面的是真是的绘制的像素,在style里面的是在绘制好以后压缩或拉伸整个cavas到这个宽高(而且这个要带单位px)。与vml不同,canvas和svg都不用带style里面的样式。

  2. 画布旋转,移动,变形等都是以画布左上角为中心的。所以想要方框沿着自己的中心旋转,要先把画布的中心与方框的中心重合。

  3. strokeRect不是路径操作,在他后面的操作不需要beginPath

  4. 弧的度数为顺时针从0到2π,逆时针从0到-2π,度数位置是固定的,跟画弧的时候是顺时针画还是逆时针画没有关系。只是从0到90度画的时候如果是顺时针是小弧,如果是逆时针的话是大弧。

image.png

image.png

image.png 19. canvas没有事件,只能通过模拟:计算位置关系判断是否点击或飘过等。 从这点来说,cavas不适合做交互多的应用,如图表等。cavas性能高,适合做游戏,游戏的交互不如图表那么复杂,点击居多,用圆和方框的模拟差不多够用。 判断是否在方框内比判断是否在圆内还麻烦些,要判断4个边,判断圆只需要判断与圆心的距离和半径的关系即可,所以一般用圆来模拟的更多,比如游戏中全是拿圆来模拟的。一个大物体可以用很多圆拼出边缘。

image.png

  1. 文字 fillText和strokeText y值要不小于字体的高度,否则会被截掉头部

image.png

  1. canvas的内容输出 oC.toDataURL() 【注意:是canvas的方法,不是上下文gd的方法】【注意下面代码说的透明背景,不要混淆于:采用父级的颜色遮住的是蒙版】

image.png

image.png 把图片作为 canvas 的css 样式 style 中的background 中的背景图,在使用 canvas.toDataUrl() 生成图片的时候,该图片就不会在最后生成的图片中。

  1. canvas绘制图片 gd.drawImage 【简单用法和完整用法】

    i.笔记 【图片预加载的方法:图片预加载】

image.png

  ii. 可以作为img传入的都有:     【注意:不能是url路径,得是对象】
  

image.png

  1. 像素级操作 getImageData putImageData 【createImageData】

    i. 控制每一个像素的信息 *极其慢

    ii. 浏览器,不允许读取本地文件(ajax、getImageData),需要放在服务器上,为了安全,否则坏人可以通过这种方法获取本地文件再传给他自己。

    iii. 800*600的区域有 48万个像素点, 每个像素点分为rgba四个参数。这个a与css不同,取值范围为0到255 【rgb三个值相等是灰色】

    iv. getImageData获取的结果是包含像素点数据的一维数组。[r0,g0,b0,a0,r1,g1,b1,a1,r2,g2,b2,a2.......] 那么每个像素点实际包含这个数组的4个元素。

    v. 像素级操作的时候如果使得数值超过了0到255的范围,取最值。不报错。

    vi. 如何获取某个像素点:

image.png

vii.使用方法

image.png

viii.createImageData的使用方法

image.png

ix.对象的封装 canvas主要用于游戏,其中有大量的重复使用的对象,封装起来。

  1. canvas在Android微信浏览器,画饼图不能正常显示 这段代码在手机普通浏览器都正常显示,在微信Android浏览器不能显示,随着微信版本的更新也许本bug不复存在,需要常常测试

image.png

25.canvas里面,框是往两边扩

gd.lineWidth=30;
gd.strokeRect(100, 100, 400, 300);

最终的宽度=430
最终的高度=330

26.关于颜色

Cc.graphics 是如何处理 strokeColor的

Canvas 要beginPath 后 新的 strokeStyle 才会只画新的路径,否则会话上次 beginpath 之后的所有线,是覆盖性的,即旧的画的颜色会留在下面被叠加。

/Users/bjhl/Documents/festudy/html5-node笔记-练习加批注版/playhtml/50110/canvas/4.html cc.graphics 不确定机制,隔一段时间就可以不会覆盖。 而且用的是 strokeColor

难道是根据 moveTo 判断用新的?

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="bb" />
<meta name="copyright" content="bb" />
<title>bb</title>
<style>
body {background:black; text-align:center;}
#c1 {background:white;}
</style>
<script>
window.onload=function ()
{
 var oC=document.getElementById('c1');
 var gd=oC.getContext('2d');
 
 //不清空路径,会一直保留
 
 //第一条
 gd.moveTo(100,100);
 gd.lineTo(300,300);
 
 gd.strokeStyle='red';
 gd.stroke();
 
 //清空前面的路径 试试注释掉
 gd.beginPath();
 
 //第二条
 gd.moveTo(200, 100);
 gd.lineTo(400, 300);
 
 gd.strokeStyle='green';
 gd.stroke();
    //清空前面的路径 试试注释掉
  gd.beginPath();

  gd.moveTo(500, 600);
  gd.lineTo(400, 300);

  gd.strokeStyle='yellow';
  gd.stroke();
};
</script>
</head>

<body>
<canvas id="c1" width="800" height="600"></canvas>
</body>
</html>

27.关于 path

不重新beginpath的话,所有path是是同一个path下面的subpath,在fill的时候会默认遵循非零原则。不用new 一个 Path2D 对象

juejin.cn/post/684490…

developer.mozilla.org/zh-CN/docs/…

28.关于 isPointInPath

检查某点是否在当前的路径内(及内部)。默认使用 非零环绕规则

developer.mozilla.org/zh-CN/docs/…

因为常常需要用 beginPath 来开始新的路径去绘制新的样色等,之后想看是否在某个之前指定的path上的话,可以传入那个 path 参数。

console.log('is in path', ctx.isPointInStroke(this.clipPath, x, y))

ctx.rect(10, 10, 100, 100);
ctx.stroke();
console.log(ctx.isPointInPath(10, 10)); // true
console.log(ctx.isPointInPath(50, 50)); // true

29.关于 isPointInStroke

用于检测一个点是否在路径的描边线上。

developer.mozilla.org/zh-CN/docs/…

ctx.rect(10, 10, 100, 100);
ctx.stroke();
console.log(ctx.isPointInStroke(10, 10)); // true
console.log(ctx.isPointInStroke(10, 20)); // true
console.log(ctx.isPointInStroke(50, 50)); // false

30.关于 drawImage 及 img 标签的 naturalWidth naturalHeight

drawImage()方法在绘制时使用源元素的CSS大小。

developer.mozilla.org/zh-CN/docs/…

在文档中搜 naturalWidth

图片的 naturalWidth naturalHeight 表示图片本身的宽高,width height 表示图片的css宽高

31.使用SVG path data来初始化canvas上的路径

developer.mozilla.org/zh-CN/docs/…

32.圆头去毛刺

ctx.save();
ctx.clip(pd);
ctx.lineTo(x, y);
ctx.lineJoin = ctx.lineCap = 'round';
// 加阴影能放置重复画同一个地方的时候跳尖刺
ctx.shadowBlur = 5;
ctx.shadowColor = ctx.strokeStyle;
ctx.lineWidth = mode === 1 ? 40 : 20;
ctx.stroke();
ctx.restore();

33.笔触参考

juejin.cn/post/684490…

34.每当画布的高度或宽度被重设时,画布内容就会被清空

canvas.width 不是 canvas.style.width

juejin.cn/post/684490…