Canvas与SVG

区别概括

  • Canvas
    通过 js 在画布上绘制像素图形(位图),放大会失真。
    图象的变动需要重新绘制,但因为不涉及dom操作,性能极高,适合开发游戏、图表等。

  • SVG
    可伸缩矢量图形 (Scalable Vector Graphics),矢量意味着图像放大不会损失图形质量,适合地图、简单特效等。
    通过 XML 格式直接定义,每一部分都是一个实际的DOM元素,可以方便地绑定事件。且其中的文字独立于图像,文字可保留,可编辑和可搜索。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>

以下重点介绍Canvas

html部分

<canvas width=400 height=400 id='mycanvas'>
    您的浏览器不支持canvas
</canvas>

script部分

自定义形状

每次stroke其实都是将从上一次beginPath到现在所有的路径进行绘制。

var canvas=document.getElementById('mycanvas');
var cxt=canvas.getContext('2d');
cxt.beginPath();//隔离.stroke()和.fill()对之上内容的影响
cxt.moveTo(0,0);//设置起点,无起点则由第一个lineTo代替
cxt.lineTo(100,100);
cxt.lineTo(200,100);
cxt.closePath();//自动闭合当前内容到起点(并不意味着路线结束,和beginPath其实无关)
cxt.strokeStyle='red';//设置描边颜色
cxt.lineWidth=10;//设置描边粗,仅对各种stroke有影响
cxt.stroke();//描边
cxt.fillStyle='blue';//设置填充颜色
cxt.fill();//填充
矩形
cxt.beginPath();
cxt.rect(100,100,150,50)//依次为左上角的x,y坐标,x轴边长,y轴边长
cxt.stroke();

更直接的还有

cxt.beginPath();
cxt.strokeRect(100,100,150,50)//依次为左上角的x,y坐标,x轴边长,y轴边长

cxt.beginPath();
cxt.fillRect(100,100,150,50);//依次为左上角的x,y坐标,x轴边长,y轴边长

此外有清除指定矩形范围

cxt.clearRect(100,100,150,50);//依次为左上角的x,y坐标,x轴边长,y轴边长
圆弧
cxt.beginPath();
cxt.arc(100,100,150,0,Math.PI/3,false);//依次为圆心的x,y坐标,半径,起止角度(0为三点钟方向,均需用弧度表示),顺逆时针(默认为false,顺时针)
cxt.stroke();

复杂路径填充

  • 非0环绕原则:区域中任意方向作射线,若相交的顺逆方向路径数量相等则视为不在区域中,不填充

内容

文字方法

  • strokeText(text, x, y) 描边写字
    • 受到strokeStyle,以及lineWidth的影响
  • fillText(text, x, y) 填充写字
    • 受到fillStyle的影响,不受lineWidth影响
  • 以上两者中,x,y为定位,受到textAlign和textBaseline影响
  • measureText(text) 返回对象文本的宽度
  • font 属性 设置 大小、字体 如 cxt.font="100px MicrosoftYaHei";
  • textAlign 属性 水平对齐方式 start(默认)/end/center/left/right
  • textBaseline 属性 垂直对齐方式 alphabetic(默认)/top/bottom/middle/hanging/ideographic

绘制图片(插入图片)

插入图片

drawImage(img, x, y, width, height)

  • img image的dom元素
    • 利用var img=document.createElement('img')和img.src=''
    • 且应在img.onload触发后执行
  • x,y 插入到画布的坐标(默认0)
  • width,height默认为图片自身宽高

插入裁剪后的图片

drawImage(img, sx,sy,swidth,sheight, x, y, width, height)

  • 先在原图中根据 sx,sy,swidth,sheight裁剪出一部分,然后根据 x, y, width, height放入画布中
  • sx/sy: 图片上开始裁剪的位置
  • swidth/sheight : 裁剪图片的大小

阴影(少用,性能差)

  • 阴影的大小粗细和原型相等,不能改变
  • shadowColor 阴影颜色
  • shadowBlur 阴影的模糊值
  • shadowOffsetX 阴影的左偏移量
  • shadowOffsetY 阴影的右偏移量

渐变

线性渐变

  • var grd = cxt.createLinearGradien(x, y, x1, y1);
    • x,y为起点,x1,y1为终点
    • 一经设置,等同于隐藏在画布下,所有.fillStyle或.strokeStyle为grd的目标会采用该渐变
  • grd.addColorStop(位置, color)
    • 位置范围为0~1
    • 可设置多个

径向渐变

  • createRadiaGradient(x1, y1, r1, x2, y2, r2)//第一个圆和第二个圆
  • addColorStop()

把背景图片作为填充(同渐变,生成的图片相对于画布固定)

  • var bg=createPattern(imgDom, repeate)
  • 第二个参数 repeate/ repeat-x / repeat-y / no-repeat

变换(每次变换会在上一次的基础上进行)

缩放

  • sacle(x, y)

位移(重新布置原点)

  • translate(x, y)

旋转(弧度,围绕当前原点)

  • rotate(angle)

环境的保存和恢复(包括变换,透明,限定区等)

  • save()
  • restore()//释放内存,不再能restore()

设置透明

  • globalAlpha = number 设置不透明度
  • 全局设置是对整个画布(绘图环境) 进行设置

限定绘图区域(跟随之前的闭合路径)

  • clip()

输出base64编码

  • canvas.toDataURL(type, encoder)
  • type为mime类型 image/jpeg image/gif image/png image/webp
  • encoder为0~1表示图片质量,1为无损,仅能jpeg和webp

画布渲染画布

把一个画布以图片的形式用 drawImage() 插入到另一个画布
这是一种canvas的优化手段

设置线条

  • lineCap 属性 设置线条两端的形状 butt/round/square
  • lineJoin 属性 设置线条夹角 miter/bevel/round
  • miterLimit 属性 设置夹角斜角的最大长度 一般默认 10

贝塞尔曲线

创建梁切线的弧

判断点是否在路径(填充区)中

  • cxt.isPointInPath(x,y)

使用canvas制作图片并分享的案例

    <canvas id="cvs" style="width:74%;position:absolute;height:104vw;top:17vw;left:13%;">
        当前浏览器不支持canvas
        <!-- 如果浏览器支持canvas,则canvas标签里的内容不会显示出来 -->
    </canvas>

    <script>
        var wWidth =  $(window).width()*2;//canvas属性宽高设置为css的两倍,这样在多倍屏下显示更清晰
        var wHeight = $(window).height()*2;

        //获取canvas元素
        var cvs = document.getElementById("cvs");
        cvs.width = wWidth*0.74;
        cvs.height = wWidth*1.04;
        var ctx = cvs.getContext('2d');

        //创建image对象
        var imgBG = new Image();
        imgBG.src='images/public/poster.jpg';
        imgBG.onload = function(){//背景图
            ctx.drawImage(this, 0, 0,wWidth*0.74,wWidth*1.04);//this即是imgObj
            var imgObj = new Image();//二维码
            imgObj.src = $scope.qrcodeImageUrl;
            imgObj.onload = function(){
                ctx.drawImage(this, wWidth*0.07, wWidth*0.82,wWidth*0.15,wWidth*0.15);
            }

            var imgHead = new Image();//头像
            imgHead.setAttribute('crossOrigin', 'anonymous');//解决跨域问题
            imgHead.src=$scope.userInfo.headImageUrl;
            imgHead.onload = function(){//使用clip进行圆形头像的裁剪
                ctx.arc(wWidth*0.37, wWidth*0.175, 0.095*wWidth, 0, 2 * Math.PI);
                ctx.clip();
                ctx.drawImage(this, wWidth*0.275, wWidth*0.075,wWidth*0.19,wWidth*0.19);
                ctx.restore();
            }

            ctx.font = "6.6vw 'PingFangSC-Regular', '微软雅黑', Helvetica, STheiti, 'Microsoft YaHei'";
            ctx.fillStyle = '#333';
            ctx.textBaseline = "top";
            ctx.fillText('保险经纪人:', wWidth*0.23, wWidth*0.82);
            ctx.fillText($scope.userInfo.mobile, wWidth*0.23, wWidth*0.91);

            ctx.font = "7.6vw 'PingFangSC-Regular', '微软雅黑', Helvetica, STheiti, 'Microsoft YaHei'";
            ctx.fillText($scope.userInfo.nickName, wWidth*0.23, wWidth*0.865);
        }
            
        $scope.canvasDrawImage = function(ID){//微信分享和本地保存
            var canvasBase64 = cvs.toDataURL().replace('data:image/png;base64,', '');//传给原生时需要去掉图片类型字段
            
            if (ID === '3') {
                nativeBridge.invoke('saveImage', { shareType: ID, imgData: canvasBase64 });
            } else {
                nativeBridge.invoke('pandaAppImgShare', { shareType: ID, imgData: canvasBase64 });
            }
        
        }
    <script>

canvas第三方库使用

  • Konva 全能
  • echarts 专用于画图表
  • egret 白鹭时代 游戏引擎
  • threeJS 3D
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,945评论 4 60
  • 我想和老师同学嘻嘻哈哈的打成一片 但我天生性格内向 我想一出生就可以 享受到荣华富贵 可谁又能选择自己的出生 我想...
    poiqwe阅读 196评论 0 0
  • 三观不合是啥概念,其实只不过是一种借口而已,开始时表演那么如此动情,说的那么冠冕堂皇,实际上内心的东西最真实! 不...
    那年春天呢喃阅读 261评论 0 0
  • 清水无香LY阅读 585评论 1 3