查看原文
其他

canvas 入门实战--邀请卡生成与下载

前端大全 2022-06-29

(点击上方公众号,可快速关注)

来源:守候

https://segmentfault.com/a/1190000012418898


1.前言

写了很多的javascript和css3的文章,是时候写一篇canvas的了。canvas是html5提供的一个新的功能!至于作用,就是一个画布。然后画笔就是javascript。canvas的用途非常的广,特别是html5游戏以及数据可视化这两个方面。现在canvas给我的感觉就和css3一样,可以不用太厉害,但是必须要会基础的用法。但是以后对canvas的需求,肯定会越来越大。所以canvas很值得学习,而且学好canvas,就是很好的一个加分项。对于这篇文章,我也是以canvas初学者的角度写的,会有很多改善的地方。如果大家觉得我有什么可以改善的,或者建议,欢迎指点迷津!代码已上传github,需要的欢迎star(downloadImg)。

大家看这篇文章之前,要了解javascript的一些基础,也要看着了解一些canvas的api(canvas-MSN教程,canvas菜鸟教程)

2.邀请卡实例

邀请卡自动生成这个会有的,毕竟有时候,很多邀请卡都是一样的,就是被邀请的人不一样而已,也就是说,整个邀请卡,就是一个名字不一样,那么下面。就写一套代码,根据名字生成邀请卡!

2-1.运行效果

html代码:

  1.    <html>

  2.    <head>

  3.        <meta charset="utf-8">

  4.        <title>下载图片</title>

  5.        <style>

  6.            .set-option {

  7.                float: left;

  8.                width: 400px;

  9.            }

  10.            .set-option .text {

  11.                width: 200px;

  12.                height: 40px;

  13.                padding-left: 10px;

  14.                border-radius: 4px;

  15.                border: 1px solid #ccc;

  16.            }

  17.            .set-option td {

  18.                padding: 10px 0;

  19.            }

  20.            .set-option td:first-child {

  21.                text-align: right;

  22.                padding-right: 10px;

  23.            }

  24.            .set-option p {

  25.                margin: 0;

  26.                line-height: 16px;

  27.            }

  28.            .check-box {

  29.                width: 16px;

  30.                height: 16px;

  31.                margin: 0;

  32.                vertical-align: top;

  33.            }

  34.            button {

  35.                width: 200px;

  36.                height: 50px;

  37.                border: none;

  38.                color: #fff;

  39.                font-size: 16px;

  40.                cursor: pointer;

  41.                display: block;

  42.                margin: 10px auto;

  43.            }

  44.            button:hover {

  45.                opacity: .9;

  46.            }

  47.            .btn-all {

  48.                background: #f90;

  49.            }

  50.            .btn-save {

  51.                background: #09f;

  52.            }

  53.            .btn-download {

  54.                background: #4CAF50;

  55.            }

  56.        </style>

  57.    </head>

  58.    <body>

  59.    <div>

  60.        <div class="set-option">

  61.            <table>

  62.                <tr>

  63.                    <td>画布尺寸</td>

  64.                    <td><input type="text" class="text" id="size"/></td>

  65.                </tr>

  66.                <tr>

  67.                    <td>背景图片</td>

  68.                    <td><input type="file" id="file"/></td>

  69.                </tr>

  70.                <tr>

  71.                    <td>用户名</td>

  72.                    <td>

  73.                        <input type="text" class="text" id="user-name"/>

  74.                    </td>

  75.                </tr>

  76.                <tr>

  77.                    <td>用户名x坐标</td>

  78.                    <td>

  79.                        <input type="number" class="text" id="text-option-x"/></br>

  80.                        <p><input type="checkbox" class="check-box" value="1" id="is-center-x">居中显示</p>

  81.                    </td>

  82.                </tr>

  83.                <tr>

  84.                    <td>用户名y坐标</td>

  85.                    <td>

  86.                        <input type="number" class="text" id="text-option-y"/></br>

  87.                        <p><input type="checkbox" class="check-box" value="1" id="is-center-y">居中显示</p>

  88.                    </td>

  89.                </tr>

  90.                <tr>

  91.                    <td>用户名字体大小</td>

  92.                    <td><input type="number" class="text" id="text-size"/></td>

  93.                </tr>

  94.                <tr>

  95.                    <td>文字颜色</td>

  96.                    <td><input type="text" class="text" id="text-color"/></td>

  97.                </tr>

  98.                <tr>

  99.                    <td>图片类型</td>

  100.                    <td>

  101.                        <select type="text" class="text" id="img-type">

  102.                            <option value="jpg">jpg</option>

  103.                            <option value="png">png</option>

  104.                        </select>

  105.                    </td>

  106.                </tr>

  107.            </table>

  108.            <button id="save-image" class="btn-save">效果预览</button>

  109.            <button id="download-img" class="btn-download">下载当前图片</button>

  110.            <button id="download-all" class="btn-all">批量导出</button>

  111.        </div>

  112.        <div class="show-canvas">

  113.            <canvas width=200 height=200 id="thecanvas"></canvas>

  114.        </div>

  115.    </div>

  116.    </body>

  117.    </html>

效果如图,那么大家细想一下,关于一张邀请卡,有什么东西是需要改变的!看到上图相比不难发现!有如下需要改变的属性:图片的大小,图片,用户名,用户名的坐标(x,y,x轴是否居中,y轴是否居中),用户名字体的大小,用户名字体的颜色,以及下载图片的类型。

这样就得到了如下的参数(大家看到有些参数是有值的,可以想成默认值就行了)

  1.    var option = {

  2.        img: '111.jpg',

  3.        width: 500,

  4.        height: 350,

  5.        fontSize: "20px Microsoft YaHei",

  6.        color: "black",

  7.        text: '守候',

  8.        imgType: 'jpg',

  9.        x: 30,

  10.        y: 30,

  11.        xCenter: false,

  12.        yCenter: false,

  13.    };

2-2.步骤

1.初步效果

根据上面的参数,先初步画一个效果,代码基本都是一个写法,没什么技巧。

  1.    //画图

  2.    function draw(obj) {

  3.        var canvas = document.getElementById("thecanvas");

  4.        //画布大小

  5.        canvas.width = obj.width;

  6.        canvas.height = obj.height;

  7.        //设置图片

  8.        var img = new Image();

  9.        img.src = obj.img;

  10.        var ctx = canvas.getContext("2d");

  11.        //设置字体的坐标

  12.        var _x = obj.x, _y = obj.y;

  13.        //是否居中显示

  14.        if (obj.xCenter) {

  15.            _x = obj.width / 2;

  16.        }

  17.        if (obj.yCenter) {

  18.            _y = obj.height / 2;

  19.        }

  20.        //图片加载后

  21.        img.onload = function () {

  22.            //先画图片

  23.            ctx.drawImage(img, 0, 0);

  24.            //设置文字的大小

  25.            ctx.font = obj.fontSize;

  26.            //设置文字的颜色

  27.            ctx.fillStyle = obj.color;

  28.            //设置文字坐标

  29.            if (obj.xCenter) {

  30.                ctx.textAlign = "center";

  31.            }

  32.            //画文字

  33.            ctx.fillText(obj.text, _x, _y);

  34.        };

  35.    }

  36.    window.onload = function () {

  37.        draw(option);

  38.    }


2.动态改变参数

看到图已经画好了,工作其实已经完成一半了!

下面就是动态改变参数!这一步其实很简单。

首先,改变画布的尺寸

  1.    //画布尺寸

  2.    //获取按钮

  3.    var size = document.getElementById("size");

  4.    size.addEventListener("blur", function () {

  5.        //根据空格,区分高宽

  6.        var _width = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[0]),

  7.            _height = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[1]);

  8.        //把参数的width和height改掉

  9.        option.width = _width || 100;

  10.        option.height = _height || 100;

  11.        //重新画图

  12.        draw(option);

  13.    });

上面代码设置了,只要输入框失去了焦点,就会改变画布的大小,下面来运行下,看下效果(gif图差强人意,大家看懂就好)

canvas没有层级的说法,只要改canvas,都要重绘。哪怕就是一个字移动一个像素。

做好了这个,下面做选择图片的功能!

  1.    //选择图片

  2.    //获取图片控件

  3.    var file = document.getElementById("file"), imagesFile, imageData;

  4.    file.addEventListener('change', function (e) {

  5.        //获取图片

  6.        imagesFile = e.target.files[0];

  7.        //把图片转base64

  8.        var reader = new FileReader();

  9.        reader.readAsDataURL(imagesFile);

  10.        //图片加载后

  11.        reader.onload = function (e) {

  12.            //设置option的img属性,再冲洗年绘制

  13.            imageData = this.result;

  14.            option.img = imageData;

  15.            draw(option);

  16.        }

  17.    });


下面开始改文字,用户名这个有点不一样,我以空格分割。如果输入多个用户名,以第一个用户名重绘。下面代码,注释就不写了,还是和上面的逻辑一样!

  1.    //用户名

  2.    var userName = document.getElementById("user-name");

  3.    userName.addEventListener("blur", function () {

  4.        var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/);

  5.        option.text = _text[0];

  6.        draw(option);

  7.    });


下面开始用户名的坐标,代码方面,也是改option的相关属性。

  1.        optionXCenter.addEventListener("change", function () {

  2.            if (optionXCenter.checked) {

  3.                option.xCenter = true;

  4.            }

  5.            else {

  6.                option.xCenter = false;

  7.                option.x = parseInt(optionX.value);

  8.            }

  9.            draw(option);

  10.        });

  11.        //纵坐标

  12.        var optionY = document.getElementById("text-option-y");

  13.        optionY.value = option.y;

  14.        var optionYCenter = document.getElementById("is-center-y");

  15.        optionY.addEventListener("input", function () {

  16.            if (optionYCenter.checked) {

  17.                option.yCenter = true;

  18.            }

  19.            else {

  20.                option.yCenter = false;

  21.                option.y = parseInt(optionY.value);

  22.            }

  23.            draw(option);

  24.        });

  25.        //是否垂直居中显示

  26.        optionYCenter.addEventListener("change", function () {

  27.            if (optionYCenter.checked) {

  28.                option.yCenter = true;

  29.            }

  30.            else {

  31.                option.yCenter = false;

  32.                option.y = parseInt(optionY.value);

  33.            }

  34.            draw(option);

  35.        });


是否水平居中显示:

其他的属性,字体大小和颜色,基本是一样的代码,运行的效果图我不放了!

  1.    //字体颜色

  2.    var textColor = document.getElementById("text-color");

  3.    textColor.addEventListener("blur", function () {

  4.        textColor.value === "" ? option.color = "#fff" : option.color = '#' + textColor.value;

  5.        draw(option);

  6.    });

  7.    //字体大小

  8.    var textSize = document.getElementById("text-size");

  9.    textSize.addEventListener("input", function () {

  10.        textSize.value === "" ? option.fontSize = '20px Microsoft YaHei' : option.fontSize = textSize.value + 'px Microsoft YaHei';

  11.        draw(option);

  12.    });

3.按钮操作

效果预览

就是预览当前canvas的一个效果,这个就很简单了,就是新开一个窗口,然后把图片写进去而已。

  1.    //预览图片

  2.    function saveImageInfo() {

  3.        var mycanvas = document.getElementById("thecanvas");

  4.        //生成图片

  5.        var image = mycanvas.toDataURL("image/png");

  6.        var w = window.open('about:blank', 'image from canvas');

  7.        //把图片新进新的窗口

  8.        w.document.write("<img src='" + image + "' alt='from canvas'/>");

  9.    }

  10.    var saveButton = document.getElementById("save-image");

  11.    saveButton.addEventListener('click', saveImageInfo);


下载当前图片

下载图片这个,基本也是写法的,都是些记忆的东西。

  1.    //图片类型

  2.    var imgType = document.getElementById("img-type");

  3.    imgType.addEventListener("change",function () {

  4.        option.imgType=this.value;

  5.    });

  6.    //下载图片

  7.    function downloadImg(fileName) {

  8.        //获取canvas

  9.        var myCanvas = document.getElementById("thecanvas");

  10.        //设置图片类型

  11.        var image = myCanvas.toDataURL("image/" + option.imgType).replace("image/" + option.imgType, "image/octet-stream");

  12.        var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');

  13.        save_link.href = image;

  14.        //设置下载图片的名称

  15.        save_link.download = fileName + '.' + option.imgType;

  16.        //下载图片

  17.        var event = document.createEvent('MouseEvents');

  18.        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);

  19.        save_link.dispatchEvent(event);

  20.    }

批量下载图片

这个复杂一点,但也不难,下面一步一步来!

1、首先批量导出,那么用户名我这里是使用空格分割,那么现在我在option里面,弄一个字段textAll,所有文字的集合。all代表是否是批量下载。fn属性代表回调函数

  1.    //批量导出

  2.    var downloadAll = document.getElementById("download-all");

  3.    downloadAll.addEventListener('click', function () {

  4.        var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/);

  5.        option.textAll = _text;

  6.        option.all = true;

  7.        option.fn = downloadImg;

  8.        draw(option);

  9.    });

2、然后修改绘制的函数draw,判断是否是全部绘制的情况!

  1.    function draw(obj) {

  2.        var canvas = document.getElementById("thecanvas");

  3.        //画布大小

  4.        canvas.width = obj.width;

  5.        canvas.height = obj.height;

  6.        //设置图片

  7.        var img = new Image();

  8.        img.src = obj.img;

  9.        var ctx = canvas.getContext("2d");

  10.        //设置字体的坐标

  11.        var _x = obj.x, _y = obj.y;

  12.        //是否居中显示

  13.        if (obj.xCenter) {

  14.            _x = obj.width / 2;

  15.        }

  16.        if (obj.yCenter) {

  17.            _y = obj.height / 2;

  18.        }

  19.        //图片加载后

  20.        img.onload = function () {

  21.            //是否是全部打印

  22.            if(obj.all){

  23.                //遍历textAll

  24.                for(var i=0;i<obj.textAll.length;i++){

  25.                    //绘制图片

  26.                    ctx.drawImage(img,0,0);

  27.                    //设置字体大小

  28.                    ctx.font=obj.fontSize;

  29.                    //设置字体颜色

  30.                    ctx.fillStyle=obj.color;

  31.                    //是否居中显示

  32.                    if(obj.xCenter){

  33.                        ctx.textAlign="center";

  34.                    }

  35.                    //绘制文字

  36.                    ctx.fillText(obj.textAll[i], _x,_y);

  37.                    //是否回调

  38.                    if(obj.fn){

  39.                        obj.fn(obj.textAll[i]);

  40.                    }

  41.                }

  42.                //最后取消全部批量下载

  43.                defult.all=false;

  44.            }

  45.            else{

  46.                ctx.drawImage(img,0,0);

  47.                ctx.font=obj.fontSize;

  48.                ctx.fillStyle=obj.color;

  49.                if(obj.xCenter){

  50.                    ctx.textAlign="center";

  51.                }

  52.                ctx.fillText(obj.text, _x,_y);

  53.            }

  54.        };

  55.    }

3.小结

关于canvas入门的第一篇文章,就写到这里了。写完之后,也发现自己对canvas的也是有很多的不懂!上文的这例子,知识canvas很简单的一个入门实例。canvas如果深入学习,能做到很多让人惊讶的效果,这个得以后要加强学习,如果发现些值得记录的知识,我也会写文章。canvas是一个非常值得学习的知识,也是很有趣的一个知识。期待与大家有更多的交流和学习!


觉得本文对你有帮助?请分享给更多人

关注「前端大全」,提升前端技能

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存