如何优雅的使用canvas:通过li-canvas轻松实现绘制单图、多图、圆角图,绘制单行、多行、竖向文字,保存图片,下载图片等

蛰伏已久 蛰伏已久 2018-11-29

Html5新增的canvas是个强大的功能, 估计大家平时都会用到,只是频率不高,偶尔用它合成图片,但是如果不进行封装的话,代码会很乱,所以对canvas常用的画图、绘制文字、保存功能进行了封装,目前还比较满意,能够快速完成canvas绘图任务,从容应对需求变更,只需进行简单配置更改即可。

先看一个简单的案例,假如要合成这张图片,其中背景图是一部分,有个标题,还有个简介,合成之后下载为图片

下载.png


实现代码如下

...

<script src="../dist/li-canvas.js"></script>   //引入封装后的js文件
...
<canvas id="test" width="1563" height="1180"></canvas>
...

<script>
 
 var canvas=new LiCanvas('test')

 //添加绘制图片任务
 canvas.addDrawImageTask({
     src:"http://www.***.com/bg.png",//图片的url地址
     x:0,//绘制起始位置左上角的x坐标
     y:0,//绘制起始位置左上角的y坐标
     width:1563,//图片绘制宽度
     height:1180,//图片绘制高度
     borderRadius:0 //图片圆角半径
 })   
 
 //添加绘制文字任务
 canvas.addDrawTextTask(['【企服观察】美团上市后首份季报:B端成新增长点,出行业务仍拖累财报',{
    text:"美团第三季度营业收入191亿元,同比增长97%;毛利总额46亿元,同比增长33.2%。",
    fontSize:48,
    color:'666666',
    fontWeight:500,
 }],{
     x:110,
     y:496,
     width:1340,
     fontSize:54,
     fontWeight:'bolder',
     fontFamily:"PingFangSC-Regular,'Microsoft YaHei',SimSun,Arial,'Helvetica Neue',sans-serif",
     lineHeight:70,
     color:'#1a1a1a',
     marginBottom:40
 })

 //开始绘制
  canvas.draw(()=>{
      //绘制完成下载
      canvas.saveToPng("test")
 })
</script>

怎么样,是不是很简单,绘制图片只需要指定图片的url和起始位置坐标、宽高即可,绘制文字则需要设置起始位置、字体大小、行高、段间距等即可,下载也很简单只需要一行代码。

有兴趣可以访问github:点击访问

安装

npm安装

npm install --save li-canvas

下载js文件

通过github下载,然后调用即可

<script src="dist/li-canvas.js"></script>

初始化

使用li-canvas时需要先实例化对象,new LiCanvas(canvas_id,options),传入canvas的id,options选填,可以设置canvas背景和默认文字样式等

...
<script src="../dist/li-canvas.js"></script>
...
<canvas id="test" width="1563" height="1180"></canvas>
...

<script>    
    var canvas=new LiCanvas('test')
</script>

...

option是一个对象,可以传入以下值

  • width、height:即canvas的宽高,也可以通过html设置canvas的宽高,<canvas width="1563" height="1180"></canvas>

  • backgroundColor:canvas的背景色,如:'red','#00ff00',实例化之后并不会立即绘制背景,而是添加到一个任务队列,所有绘制操作都在调用draw()方法时执行,后面介绍

  • backgroundImage:canvas背景图片的url地址

  • backgroundRepeat:canvas背景图片的平铺模式,可选值有四种"repeat | repeat-x | repeat-y | no-repeat",默认为repeat

  • fontStyle:默认的文字样式,也是一个对象,可选值如下

fontStyle:{
    x:0,                      //文字起始位置左上角坐标x,默认0
    y:0,                      //文字起始位置左上角坐标y,默认0
    fontSize:14,              //字体大小,默认14,单位px
    fontStyle:'normal',       //可能的值,默认normal,可选的值:normal | italic | oblique
    fontWeight:'normal',      //同css的font-weight 如normal bold 500 600
    fontFamily:"PingFangSC-Regular",  //字体
    lineHeight:20,                    //行高
    color:'black',                    //颜色,如"black",”#00ff00“,默认black
    marginBottom:10,                  //段落之间的间距,默认10,单位px
    textDirection:'horizontal',       //文字方向,横排显示 或 竖排显示,默认横排 ”horizontal“,可选值horizontal | vertical
    rowDirection:'ltr',               //段落方向,仅当textDirection为vertical时有效,当文字采取竖向排版时,指定段落是从左到右还是从右到做,默认"ltr",即left to right,可选值ltr | rtl
},

    

图片绘制

绘制单张图片:

调用addDrawImageTask(image)添加一个绘图任务,其中参数image是一个对象,我们只需指明图片的url、绘制起始点坐标、绘制的宽高、圆角半径即可,可选参数为

  • src:图片的url地址

  • x:图片在canvas画布上的左上角x坐标

  • y:图片在canvas画布上的左上角y坐标

  • width:图片绘制宽度

  • height:图片绘制高度

  • borderRadius:图片圆角半径

调用addDrawImageTask(image)时,并没有立即绘制图片,而是添加了一个绘图任务,只有调用draw(callback)时,才执行绘图任务,绘图完成后调用callback回调函数

为什么这么做呢?因为图片绘制的时候需要先下载图片,这是个异步操作,所以先添加到任务列表,调用draw()的时候再按照任务添加顺序依次执行,任务全部执行完成后调用回调函数,回调函数中,我们一般获取图片数据或者保存下载图片

    var bg={
        src:document.getElementById('img').src,     //src有两种:1.读取页面中的图片数据 2.http/https形式的url地址
        x:0,//左上角的x坐标
        y:0,//左上角的y坐标
        width:1563,//图片绘制宽度
        height:1180,//图片绘制高度
        borderRadius:0 //图片圆角半径
    }

    var canvas=new LiCanvas('test')

    canvas.addDrawImageTask(bg)  //添加绘图任务,并没有立即进行绘图

    canvas.draw(()=>{
       console.log("绘制完成")
    })

绘制圆角或者圆形图片就非常简单了,我们只需要设置圆角半径borderRadius即可,如果图片宽高相等,borderRadius大于等于宽高的一半,不就是圆形图片了嘛


绘制多张图片

很简单多次调用addDrawImageTask(image)就可以实现多图绘制,也可以把image设置为一个数组

var imgs=[
        {
             src:"http://*****.com/***.png",
             x:0,
             y:0,
             width:100,
             height:100,
             borderRadius:0
        },
        {
             src:"http://*****.com/***.png",
             x:0,
             y:0,
             width:100,
             height:100,
             borderRadius:0
        }
    ]

    
    var canvas=new LiCanvas('test')

    canvas.addDrawImageTask(imgs)   //直接传入一个数组也可以实现多图绘制

    canvas.draw(()=>{
       console.log("绘制完成")
    })

是不是so easy

绘制文字

绘制单段文字

调用addDrawTextTask(text,fontStyle)可以完成文字绘制,只需指明要绘制的文字和文字样式即可,超出fontStyle.width会自动进行换行,这里的fontStyle会覆盖初始化时的fontStyle

  • text:要绘制的文字

  • fontStyle:文字样式,是个对象,可选值同初始化时的fontStyle,即

//可设置的fontStyle
{
    x:0,                      //文字起始位置左上角坐标x,默认0
    y:0,                      //文字起始位置左上角坐标y,默认0
    width:                    //文字一行的宽度,超出会自动进行换行
    fontSize:14,              //字体大小,默认14,单位px
    fontStyle:'normal',       //可能的值,默认normal,可选的值:normal | italic | oblique
    fontWeight:'normal',      //同css的font-weight 如normal bold 500 600
    fontFamily:"PingFangSC-Regular",  //字体
    lineHeight:20,                    //行高
    color:'black',                    //颜色,如"black",”#00ff00“,默认black
    marginBottom:10,                  //段落之间的间距,默认10,单位px
    textDirection:'horizontal',       //文字方向,横排显示 或 竖排显示,默认横排 ”horizontal“,可选值horizontal | vertical
    rowDirection:'ltr',               //段落方向,仅当textDirection为vertical时有效,当文字采取竖向排版时,指定段落是从左到右还是从右到做,默认"ltr",即left to right,可选值ltr | rtl
}
   var canvas=new LiCanvas('test')
   canvas.addDrawTextTask("要绘制的文字",{
           x:110,
           y:496,
           width:1340,
           fontSize:54,
           fontWeight:'bolder',
           fontFamily:"PingFangSC-Regular,'Microsoft YaHei',SimSun,Arial,'Helvetica Neue',sans-serif",
           lineHeight:70,
           color:'#1a1a1a',
           marginBottom:40
   })

    canvas.draw(()=>{
          console.log("绘制完成")
       })

绘制多段文字

像上面那样多调用几次即可,但是可能会略微繁琐,因为样式基本上都是一样的,而且有的文字是多行的,我们也不方便指明第二段的起始坐标

只需将text改为数组即可,可以共用fontStyle,而且后续的起始位置会根据行高和段间距自动计算

var canvas=new LiCanvas('test')
   canvas.addDrawTextTask(["要绘制的文字段落1","要绘制的文字段落2"],{
           x:110,
           y:496,
           width:1340,
           fontSize:54,
           fontWeight:'bolder',
           fontFamily:"PingFangSC-Regular,'Microsoft YaHei',SimSun,Arial,'Helvetica Neue',sans-serif",
           lineHeight:70,
           color:'#1a1a1a',
           marginBottom:40
   })

    canvas.draw(()=>{
          console.log("绘制完成")
       })

这样就能方便的绘制多段文字了,但是你可能又说,第二段我想要设置不同的文字大小,很简单,把文本改成一个对象即可,通过text属性指明文本内容,也可以指定其特有的fontStyle属性

var canvas=new LiCanvas('test')

  canvas.addDrawTextTask(["要绘制的文字段落1",{
       text:"要绘制的段落文字2",
       fontSize:60
       //...还可以添加更多fontStyle
   }],{
           x:110,
           y:496,
           width:1340,
   })


    canvas.draw(()=>{
          console.log("绘制完成")
       })

可以看到绘制文字很灵活,支持各种不同的情况

绘图draw()

上面调用addDrawImageTask、addDrawTextTask时,都是把绘图任务添加到任务队列,只有显示调用draw(callback)时才开始真正的绘制,绘制完成会调用回调函数callback,可以在callback中获取canvas的图片数据或者下载图片


保存下载图片

将canvas下载成图片非常简单,支持三种

  • 下载为png图片:saveToPng("文件名")

  • 下载为jpeg图片:saveToJpeg("文件名")

  • 下载为gif图片:saveToGif("文件名")

var bg={
        src:"http://***.jpg",
        x:0,
        y:0,
        width:1563,
        height:1180,
        borderRadius:0
    }

    var canvas=new LiCanvas('test')
    canvas.addDrawImageTask(bg)
    canvas.draw(()=>{
       canvas.saveToPng("li-canvas")
    })
</script>

获取图片数据

有时候,我们并不想下载图片,比如在微信浏览器中,我们其实是希望用户长按图片保存,此时,我们希望canvas合成的图片数据,插入到img的src中

调用:getImageData()可以获取合成的图片数据

var bg={
        src:"http://***.jpg",
        x:0,
        y:0,
        width:1563,
        height:1180,
        borderRadius:0
    }

    var canvas=new LiCanvas('test')
    canvas.addDrawImageTask(bg)
    canvas.draw(()=>{
       var imageData=canvas.getImageData()
       document.getElementById('img').src=imageData
    })


到这里就基本介绍完了,如果觉得还不错,可以访问github,有问题一起交流,如果能给我github点个赞,那就更感谢啦

github地址:https://github.com/501351981/li-canvas

分享到

点赞(2)