美文网首页程序员
前端canvas妙用

前端canvas妙用

作者: 我是云小梦 | 来源:发表于2020-07-04 16:21 被阅读0次

    要创建一个canvas,其实只要在HTML中添加标签:<canvas></canvas> 就行了。
    若是考虑浏览器的兼容问题,只需在标签中加上一行文字:

    <canvas>
        您的浏览器不支持canvas
    </canvas>
    

    即可达到「 友好提示用户 」的效果。

    如果要“画东西”,也就是所谓的“操纵canvas元素”,则必要借助于DOM事件:

    //获取canvas
    var canvas=document.querySelector('canvas标签中的id/class名');
    //获取“上下文对象“
    var ctx=canvas.getContext("2d");
    

    其中“上下文对象”你可以理解为是“绘图的环境(参数)”,而“2d”代表“要绘制2d(平面)图形” —— 同样的,“3d”表示“绘制3d(立体)图形”。

    canvas坑一:
    若要改变canvas“画布”的大小,最好在canvas标签的style属性中或在JS中动态进行。若通过class/id-style中修改(执行),会造成“整体缩放”——包括后面说到的lineTo线条也是这样。

    //style
    .canvas{
        border: 1px solid red;
        width: 200px;
        height: 200px;
    }
    //html
    <canvas class="canvas">
        您的浏览器不支持canvas
    </canvas>
    //JS
    var canvas=document.querySelector('.canvas');
    var ctx=canvas.getContext("2d");
    console.log(canvas.width,canvas.height);  //canvas中可以直接操作canvas所用到属性的各个CSS,这个后面还会提到
    //下面三行先不必管
    ctx.moveTo(0,0);
    ctx.lineTo(200,200);
    ctx.stroke()
    
    left

    JS操控canvas

    上面说了,通过JS操作canvas元素前要先

    1. 得到元素
    2. 获取环境(参数)

    下面的一些demo就省去这两行代码了。。。

    首先,你要画比如一条线/一个图的话,假如canvas现在是你手中的一杆画笔,那你就要先“提笔” —— 从哪开始画:

    ctx.moveTo(0,0);   //移动到【画布的】(0,0)坐标处“落笔”
    

    moveTo的两个参数分别是:起始坐标X、Y。
    然后
    若是画直线,可以调用lineTo - API:

    ctx.lineTo(100,100);   //从画布的(0,0)处“画”到(100,100)处
    

    然后其实可以继续lineTo()...

    ctx.lineTo(100,200);   //从画布的(100,100)处“画”到(100,200)处
    

    这时,这些线条还只是在【内存】中,要其真正显示到页面上,则需调用stroke():

    ctx.stroke();
    

    ctx坑二:
    若要再画一条线,不少初学者可能会将以上“绘制”部分代码再CV一遍,改变坐标即“大功告成”,但是真是这样的吗?
    经检验,第一条线要“深色”一些:这是因为整段代码有两个stroke() —— 即第一条线被“画”了两次。

    其实若要画多个图形,只要先把moveTo、lineTo...全部完成,再调用一次 ctx.stroke(); 即可。
    但这样一来又有一个问题:若是就想让两条线颜色不一样怎么办?
    canvas API提供了下面的函数:

    ctx.beginPath();   //开启一条“新的”内存路径
    

    只要把这个函数加到“第二条绘制线”的moveTo函数前即可。

    canvas画图形

    上面是画线,那么诸如圆、长方形...这些图形怎么画?

    圆形:ctx.arc(参数1,参2,参3,起始弧度,终止弧度,顺时针/逆时针画);

    • 参1:圆心坐标X
    • 参2:圆心坐标Y
    • 参3:半径r
    • 最后一个参数:true代表“逆时针”,false为“顺时针”
    ctx.arc(300,300,50,0,2*Math.PI,true);
    ctx.stroke();
    

    矩形:ctx.strokeRect(左上角X,左上角Y,宽,高);
    (因为是strokeRect这种stroke前缀的函数其实都是经过stroke()封装过的,所以可以直接显示在屏幕上)

    其实,矩形还有两种画法:

    • 通过lineTo画四条线,最后一条的终点坐标和第一条的起点坐标相同
    • 通过lineTo画三条线,最后通过“闭合函数”:ctx.closePath() 将图形路径闭合

    曾经看到好多“图片+JS雪花掉落效果”,其实这个用canvas也可以实现:

    var circles = [];
    setInterval(function() {
      // 擦出画布
      animCtx.clearRect(0, 0, animCtx.canvas.width, animCtx.canvas.height);   //animCtx是canvas元素上下文对象
      // 绘制下落的圆形
      for(var i=0; i<=10; i++) {
        if(!circles[i]) {   //保证每片“雪花”垂直下落
          circles[i] = {};
          circles[i].radius = Math.floor(Math.random() * 5) + 1;
          circles[i].y = - circles[i].radius - Math.floor(Math.random() * 10);
          circles[i].x = i * 60 + Math.floor(Math.random() * 10) - 5;
          circles[i].vy = Math.floor(Math.random() * 5) + 1;
        }
        animCtx.beginPath();
        animCtx.arc(circles[i].x, circles[i].y, circles[i].radius, 0, Math.PI * 2);
        animCtx.fillStyle = "rgba(255, 255, 255, 0.5)";
        animCtx.fill();
        circles[i].y = circles[i].y + circles[i].vy;
        if(circles[i].y > animCtx.canvas.height + circles[i].radius * 2) {
          circles[i] = undefined;
        }
      }
    }, 100);
    

    JS填充canvas与canvas描边

    上面的图形画着是挺爽的,就是颜色未免太单一了一些:
    我们可以通过 ctx.fill() 填充函数填充整个图形(内部)为“黑色”(默认颜色)(视觉上看“自动闭合了路径”)emmmmmmm,这样全部都变成黑色了,不过我可以在前面用 ctx.fillStyle="颜色值" 来改变整个图形的颜色。

    若是要只改变图形边框的颜色呢?其实上面说的一个函数本身就有“描边”的功能:ctx.stroke()
    你当然可以理解为“只有为图形边框添加了颜色,才能显示出来”,毫无疑问,它默认也是黑色的。不过我们也可以用API:ctx.strokeStyle="颜色值" 来改变图形边框的颜色。
    我们还可以通过 ctx.lineWidth=数字值; 来改变边框的宽度。

    canvas中允许“边框设置”和“填充设置”同时出现。

    JS图形变换(平移、旋转、缩放)

    如上面“画线”所说:

    ctx.moveTo(0,0);
    ctx.lineTo(100,100);
    ctx.stroke();
    

    平移:ctx.translate(X方向,Y方向);
    大家可以试下分别将translate函数放在moveTo前、lineTo前、最后,分别有什么效果!

    旋转:ctx.rotate(旋转角度); —— 以弧度为单位:

    //旋转45°
    ctx.rotate(Math.PI / 4);
    

    缩放:ctx.scale(X轴缩放,Y轴缩放);

    //X轴不缩放,Y轴变为原来的1/2
    ctx.scale(1,0.5);
    

    图形变换的效果也会“自上而下叠加”!

    如果觉得叠加效果并不是想要的,可以将某个变换片段代码放到 ctx.save() 【保存环境函数】和 ctx.restore() 【恢复环境函数】(恢复到save()函数之前的环境)的“包裹”中。

    canvas文字

    var str="hello world";
    

    我们怎么把展示到canvas画布中呢?

    ctx.fillText(str,0,100);   //参数:文字,X坐标,Y坐标
    //或
    ctx.strokeText(str,0,200);   //若有颜色,则上面的为填充,这里为描边(字体呈镂空效果)
    

    填充:


    tc

    能不能改变他的样式?
    (开头说了一句“canvas里能直接改变元素CSS样式值”不知道大家还记得不记得)

    ctx.font="50px sans-serif";   //改变字体大小
    

    并且加上strokeText函数:


    ys

    也可以改变文字的位置,如:

    ctx.textAlign="center";   //文字居中(水平)
    
    ctx.textBaseline="middle";   //文字垂直居中
    

    既然能控制大小和位置,肯定也能获取一些自身信息:

    let width=ctx.measureText(str).width;   //获取文本宽度
    

    这样,我们就能做一些有意义的事,比如文本X/Y坐标是多少时设置Align才能让水平居中、比如根据一个元素的width(文字字数)控制另一个元素的位置。。。这些都在末尾demo中有用到。

    很遗憾的是,canvas并不支持获取文本的“高度”

    在canvas中展示图片

    canvas作为一个“特殊的结构”,其图片的展示方式肯定也不同寻常:

    //加载图片对象
    let img=new Image();
    //设置src属性
    img.src="xxx.xx";
    //展示
    ctx.drawImage(img,0,0);   //ctx.drawImage(img对象,左上角X坐标,左上角Y坐标);
    

    然后我们“自信满满地”打开图片,发现...没有东西!!!

    这是因为Image()的加载需要一定时间,而我们直接插入了src:切记!一定要在load中完成img的“展示”。(和H5的File()加载展示一样的道理)

    img.onload=function(){
        ctx.drawImage(img,0,0);
    }
    

    这样完成是完成了,但图片样式是固定的,不好看啊。
    没关系,我们有“第二种展示方法”,可以将其进行缩放:

    ctx.drawImage(img对象,左上角X坐标,左上角Y坐标,宽,高);
    

    然后我们又发现缩放后图片中图标是挺好看的,但文字太模糊了,难受的一批,于是我们想:怎么把图标单独显示出来呢?
    没关系,我们还有“第三种展示方法”:

    ctx.drawImage(img对象,截取起点X坐标,截取起点Y坐标,截取终点X坐标,截取终点Y坐标,绘制位置X坐标,绘制位置Y坐标,宽,高);
    

    其实“图片”的展示还有一种方式 —— 图形画刷 ,它可以将图片为背景填充展示到canvas区域:

    var pattern=ctx.createPattern(img对象,"模式");
    ctx.fillStyle=pattern;
    

    其中,“模式”和CSS中【背景图片】的展示也很类似:

    • no-repeat
    • repeat
    • repeat-x
    • repeat-y

    canvas阴影设置

    • X轴偏移:ctx.shadowOffsetX=数字值; (数字值相对于图形)
    • Y轴偏移:ctx.shadowOffsetY=数字值; (数字值相对与图形)
    • 阴影颜色:ctx.shadowColor='颜色值如:rgba(0,0,0,0.2)';
    • 模糊半径:ctx.shadowBlur=数字值;

    阴影会作用于其下所有设置的canvas上(文本、图形、图片...)

    离屏canvas

    这个在大加载量、频繁JS动画 and DOM重绘量巨大的场景下应用极广。它基于这样的原理:把涉及大量DOM重绘、频繁加载的元素(比如小球运动场景下的背景格的样式改变)单独拿出来放在某位置地方(display:none;)自己加载,在触发操作后,通过:

    真实canvas元素上下文对象.drawImage(离屏canvas元素, 起始位置X, 起始位置Y, 真实canvas元素宽, 真实canvas元素高,起始位置X, 起始位置Y, 离屏canvas元素宽,离屏canvas元素高);
    

    将元素的“样子”刻画到主要显示的canvas上!

    要记得“适当地”擦干画布:canvas元素上下文对象.clearRect()


    canvas名片生成程序代码

    代码较多,已打包到百度网盘,可直接免费下载:

    链接 提取码
    https://pan.baidu.com/s/1EIJp0MNAD4gvTsBRwkglLg xqwk
    canvas生成的图形可以作为图片保存

    本文首发于@csdn:https://yunxiaomeng.blog.csdn.net/article/details/107123585

    相关文章

      网友评论

        本文标题:前端canvas妙用

        本文链接:https://www.haomeiwen.com/subject/axbuqktx.html