canvas理解及本周感受

本周我讲课,一开始不知道讲什么,觉得canvas听不错的就讲canvas,为了这次讲讲个canvas,我特意学了基本满三天的canvas;
一般网页如果做炫酷粒子动画的话,那肯定很花费资源,而canvas能大大减少这中资源消耗,当然,如果canvas动画写的太多的话那肯定也会花费大量资源消耗,但是绝对要比利用盒子做粒子动画要节省资源很多

canvas基本介绍

历史上,canvas最早是由Apple Inc. 提出的,在Mac OS Xwebkit中创建控制板组件使用,而在canvas称为HTML草案及标准之前,我们是通过一些替代方式去绘图的,比如为人所诟病的Flash,以及非常强大的SVG(ScalableVector Graphics,可伸缩的矢量标记图),还有只能在IE(IE 5.0以上的版本)中使用的VML(Vector Markup Language,矢量可标记图)。甚至于有些前端可以使用div+css来完成绘图。

总的来说,没有canvas的时候,在浏览器绘制图形是比较复杂的,而在canvas出现之后,绘制2D图形相对变得容易了。NOTE: 用div绘制一些简单的图形,如矩形,圆形,三角形,梯形,倒也算是没那么复杂。 但canvas也有缺点。因为canvas本质上是一个与 分辨率相关 的 位图画布,也就注定了在不同分辨率下,canvas绘制的内容显示的时候会有所不同。此外,canvas绘制的内容 不属于任何DOM元素 ,在浏览器的元素查看器中也找不到,那自然无法检测鼠标点击了canvas中的哪个内容,很显然,这两方面,canvas都是不如SVG的

举个例子:如果使用CSS设置canvas元素的尺寸,那可能会导致绘制出来的图形变得扭曲,如长方形变正方形,圆形变椭圆等,这是因为画布尺寸和元素尺寸是不一样的,画布会自动适应元素的尺寸,如果二者是成比例的,那么画布就会等比例缩放,不会出现扭曲。
这么说来,canvas有这么明显的缺点,那直接使用SVG岂不是更好? No,听过一句话吗?没有完美的方案,只有适不适合. SVG是基于XML的,那么就说明,SVG里面的元素都可以认为是 DOM元素 ,可以启用DOM操作,同时,SVG中每个绘制的图像均被视为对象,若SVG对象属性变化,浏览器会自动重现图形.
以上是SVG的优势,但通过这个优势,我们也能发现一些问题:

通常,过度使用DOM的应用都会变得很慢,所以,复杂的SVG会导致渲染速度变慢。但是像地图这类的应用,首选是SVG。
浏览器的重排发生在浏览器窗口发生变化,元素尺寸位置变化,字体变化等等。
即使可以启用DOM操作,但DOM操作的代价还是比较昂贵的(DOM和JS的实现是分开的)。 回到主题。 canvas是通过JavaScript进行2D图形的绘制,而 canvas签本身是没有任何绘制能力的,它仅仅是一个容器。在绘制时,canvas是逐像素的进行渲染的,一旦图形绘制完成,该元素就不再被浏览器所关注(脚本执行结束,绘制的图形也不属于DOM)。

值得注意的是,在HTML标准(whatwg标准)中明确的指出: Authors should not use the canvas element in a document when a more suitable element is available. 所以,不要滥用元素。

canvas目前几乎被所有的浏览器支持,但是IE 9.0 之前的版本不支持 canvas元素

canvsa基本API

  • 主要分为颜色、样式、阴影
  • 线条样式
  • 矩形
  • 路径
  • 转换
  • 文本
  • 图像绘制
  • 像素操作
  • 合成
  • 其他

我主要讲矩形,路径,线条,文本这几种,本周目前就学了这点,但也可做出酷炫动画了

基本样式,颜色

填充颜色

fillStyle

描边颜色

strokeStyle()

画笔大小

lineWidth

lineCap

可选’butt | round | square’
效果:线段尽头的样式

线段连接处的样式

lineCap可选‘butt | round | square’

线性渐变

let gradient = ctx.createLinearGradient(0,0,1300,900);
    gradient.addColorStop(0, 'red');
    gradient.addColorStop(0.5, 'blue');
    gradient.addColorStop(1, 'white');
    ctx.fillStyle = gradient;

矩形

1.绘制一个填充矩形

fillRect(x, y, width, height)
填充一个矩形,默认式黑色填充

2.绘制一个矩形边框

strokeRect(x, y, width, height)
画一个描边矩形,默认式黑色

3.清除指定矩形区域

fillRect(x, y, width, height)
清除指定矩形区间的所有动画效果,

路径

1.beginPath()

新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。

2.closePath():

闭合路径之后图形绘制命令又重新指向到上下文中

3.stroke():

通过线条来绘制图形轮廓

4.fill():

通过填充路径的内容区域生成实心的图形。

5.moveTo(x,y)

将画笔“抬起来”移到某个位置

6.lineTo(x,y)

将画笔在画布上滑倒某个位置

注意一条路径一定要有 beginPath() 开始,由closePath()结束,如果不这样写的话他会分不清哪个是哪个路径,画动画的时候会产生意想不到的错误效果

圆形

arc(x,y,半径,开始角度,结束角度,方向默认顺时针)

画一个以(x,y)为圆心的以半径的圆弧,从开始 开始到结束,按照 给定的方向(默认为顺时针)来生成

arcTo(x1,y1,x2,y2,radiu)

根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点

二次贝塞尔曲线及三次贝塞尔曲线

quadraticCurveTo(cp1x, cp1y, x, y)

绘制二次贝塞尔曲线,cp1x,cp1y 为一个控制点,x,y 为结束点。
在这里插入图片描述

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
在这里插入图片描述

  • 关于这个单说的话比较难理解,建议看看动态视频,自己试试,一般可以将折线编成有弧度的线

文字

文字默认是左下角对齐

绘制实心

fillText(text,x,y,maxWidth);

绘制空心文字

strokeText(text, x, y, maxWidth);

文字纵向基准

textBaseline=‘top | hanging | middle | alphabetic | ideographic | bottom’

文字横向基准

textAlign=‘start | left | center | right |end’

canvas注意事项

  1. canvas通过width,height或js修改画布像素大小,不加px,用px只是将其横向或是纵向放大,会造成canvas模糊.不要用css设置canvas宽高,这只是对长度和宽度的放大缩小,图像会发生变形
  2. 通过canvas.getContext判断浏览器是否支持canvas
  3. 在画画是如果更改canvas的宽高canvas内容会被清除
  4. 受到屏幕分辨率影响
  5. canvas 的默认宽度是300px,默认高度是150px。
  6. 暂时只有 IE 9 以上才支持 canvas
    附上一份自己写的代码,可以粘贴复制看看什么效果
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    * {
        margin: 0 !important;
    }

    #canvas {
        position: fixed;
        background-color: black;
    }
</style>

<body>
    <canvas id="canvas"></canvas>
</body>
<script>
    let canavs = document.getElementById('canvas')
    let ctx = canavs.getContext('2d');
    console.log(ctx)
    function init() {
        canavs.width = window.innerWidth * devicePixelRatio / 2;
        canavs.height = window.innerHeight * devicePixelRatio / 2;
    }
    function getRandom(begin, end) {
        return Math.floor(Math.random() * (end - begin) + begin);
    }
    class Point {
        constructor() {
            this.r = 3;
            this.x = getRandom(this.r, canavs.width - this.r);
            this.y = getRandom(this.r, canavs.height - this.r);
            this.speedx = getRandom(-10, 10) / 10;
            this.speedy = getRandom(-10, 10) / 10;
        }
        draw() {
            this.x += this.speedx;
            this.y += this.speedy;
            if (this.x > canavs.width || this.x < 0) {
                this.speedx = -this.speedx;
            }
            if (this.y > canavs.height || this.y < 0) {
                this.speedy = -this.speedy;
            }
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true);
            ctx.fillStyle = 'red';
            ctx.fill();
            ctx.closePath()
        }
    }
    class Linner {
        constructor(num = 10, maxdis = 800) {
            this.points = new Array(num).fill(0).map(() => new Point());
            this.maxdis = maxdis;
        }
        draw() {
            requestAnimationFrame(() => {
                this.draw();
            })
            ctx.fillStyle = 'rgba(0,0,0,0.01)'
            ctx.fillRect(0, 0, canavs.width, canavs.height);
           // ctx.clearRect(0, 0,canvas.width, canavs.height);
            
            for (let i = 0; i < this.points.length; i++) {
                const pi = this.points[i];
                for (let j = i + 1; j < this.points.length; j++) {
                    const pj = this.points[j];
                    const d = Math.sqrt((pi.x - pj.x) ** 2 + (pi.y - pj.y) ** 2);
                    const dXY = Math.sqrt((pi.x - x) ** 2 + (y - pj.y) ** 2);
                    if (d > this.maxdis) {
                        continue;
                    }
                    ctx.beginPath();
                    ctx.moveTo(pi.x, pi.y);
                    ctx.lineTo(pj.x, pj.y);
                    if (dXY< this.maxdis) {
                        ctx.moveTo(pi.x, pi.y);
                        ctx.lineTo(x, y);
                    }
                    ctx.closePath();
                    ctx.strokeStyle = 'red';
                    ctx.stroke();
                }
                pi.draw()
            }
        }
    }
    init()
    let x, y;
    window.onmousemove = e => { x = e.clientX; y = e.clientY }
    let linner = new Linner(100, 150);
    linner.draw()
</script>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值