zoukankan      html  css  js  c++  java
  • Canvas -- 应用Konva绘制canvas保存成图片,显示在页面中

    需求:移动端,做如下图片的一个海报,可以长按保存,其中标题文字,说明文字,logo图片,二维码(动态生成二维码)图片,都是可变元素,其余部分是一张图片!

    我的canvas学习笔记gitlab

    如果前端来做,首先,我想到的就是利用canvas绘制出来,然后,转换成img,放在页面中,这样用户就可以通过长按保存功能,保存图片了!

    思路步骤以及遇到的坑

    1. 使用Konva库绘制canvas,绘制文字(可以绘制在同一个组上);
    2. 先生成二维码图片,再将二维码图片绘制到层上;
    3. 绘制logo图片和背景图片;
    4. canvas正确设置宽高属性单位必须是px、百分比适配;

    HTML

    <div id="wrapper"><div id="container"></div></div>
    

    文字绘制方法封装

    // @param: data 数组(因为可能有多个文字)
    function TextTitle(data){
        this._init(data);
    }
    TextTitle.prototype = {
        _init: function(data){
            this.data = data;
            // 新建文字组
            this.textGroup = new Konva.Group({
                x: 0,y: 0
            })
            var self = this;
            this.data.forEach(function(item,index){
                var x = item.x === 0 ? 0 : (item.x || 1);
                var y = item.y === 0 ? 0 : (item.y || 1);
                var txt = new Konva.Text({
                    x: x,y: y,
                    text: item.text,
                     item.width,
                    height: item.height,
                    fontSize: item.fontSize || 16,
                    fontStyle: item.fontStyle || 'normal',
                    fontFamily: item.fontFamily || 'Arial',
                    align: item.align || 'left',
                    fill: item.fill || '#000',
                });
                self.textGroup.add(txt);
            })
        },
        addToGroupOrLayer: function(arg){
            arg.add(this.textGroup);
        }
    }
    

    整个图片绘制

    // 创建舞台
    var stage = new Konva.Stage({
        container: 'container', // 需要存放舞台的dom容器
         621/2, // 设置全屏
        height: 974/2
    });
    // 创建层
    var layer = new Konva.Layer(); // 创建一个层
    // stage.add(layer); // 把层添加到舞台(这里写在了最后)
    
    // 中心点坐标
    // var cenX = stage.width()/2; // 注意Konva获取数据都是用方法获取值
    // var cenY = stage.height()/2;
    
    // 创建一个组存放文字
    var group = new Konva.Group({
        x: 0,y: 0
    })
    // 绘制文字数据
    var dataObj = [
        { // 创建标题的文字
            x: 0,
            y: 30,
             stage.width(),
            align: 'center',
            text: "活动名称",
            fontSize: 26,
            fontStyle: 'bold',
            fill: 'white'
        },
        { // 创建活动说明文字
            x: 0,
            y: 66,
             stage.width(),
            align: 'center',
            text: '最终解释权归门店所有',
            fontSize: 16,
            fill: 'white' 
        }
    ];
    var text = new TextTitle(dataObj);
    // 绘制二维码
    // 创建二维码图片,先转成img,再绘制到canvas中,然后将img移除
    var divEle = document.createElement("div"); 
    var divattr = document.createAttribute("id");  
    divattr.value = "temp"; 
    divEle.setAttributeNode(divattr);  
    document.getElementById("wrapper").appendChild(divEle);  
    new QRCode(document.getElementById("temp"), {
        text: window.location.href, // 首页链接
         72, //生成的二维码的宽度
        height: 72, //生成的二维码的高度
        colorDark : "#000000", // 生成的二维码的深色部分
        colorLight : "#ffffff", //生成二维码的浅色部分
        correctLevel : QRCode.CorrectLevel.H
    });
    var qrcodeImg = $('#temp img')[0];
    // 绘制logo,背景的图片
    var imgBig = new Image();
    imgBig.src = "base64图片";
    // 将绘制方法都写在图片onload内部
    imgBig.onload = function(){
        var kImage = new Konva.Image({
            image: imgBig,
            x: 0,
            y: 0,
             stage.width(),
            height: stage.height()
        });
        group.add(kImage);
        // 添加二维码图片
        var qrCodeImage = new Konva.Image({
            image: qrcodeImg,
            x: 204,
            y: 366,
             72,
            height: 72
        });
        group.add(qrCodeImage);
        layer.add(group);
        text.addToGroupOrLayer(layer);
        layer.draw();
        stage.add(layer); // 把层添加到舞台
        // 绘制完二维码后将标签删除
        var temp = document.getElementById("temp");  
        document.getElementById('wrapper').removeChild(temp);
    
        // 使用canvas.toDataURL()方法,将canvas生成base64
        var dataURL = stage.toDataURL();
        var actulImg = new Image();
        actulImg.src = dataURL;
        actulImg.onload = function(){ // 生成后删除canvas
            var konvajs = document.getElementsByClassName('konvajs-content')[0];
            document.getElementById('container').removeChild(konvajs); 
            document.getElementById('container').appendChild(actulImg);
        }
    }
    

    使用的是canvas.toDataURL()方法,出现跨域问题

    报错信息:

    Konva error: Unable to get data URL. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
    

    翻译:Konva错误:无法获取数据URL。未能对“htmlcanvaseelement”执行“toDataURL”:无法导出受污染的画布

    整个报错信息的原因就是,使用canvas.toDataURL()方法,出现跨域问题了。

    因为很多情况下都会使用CDN存储的图片,在这里使用本地图片还是不现实,所以,需要解决这个问题。

    解决办法尝试:

    1. img设置img.crossOrigin = "anonymous"是没用的;
    2. URL.createObjectURL和URL.revokeObjectURL也是转换图片格式的方式,自测没写通;
    3. 将图片转换成base64使用(这里需要借助后端配合了),如果使用这种办法,出现某个图片或者二维码图片未显示出来,可能是绘制顺序出错。

    使用base64图片方式,在PC模拟器上效果显示是符合的,那么我们用微信浏览器试试吧!

    问题又出现了:

    1. 生成的canvas不虚,img图片太虚虚虚虚虚虚虚......导致根本没办法使用;
    2. 生成的二维码不见了,safari浏览器可以显示出二维码,偶发性如果第一次进入,点击显示的按钮,safair整张图片都不显示了,应该是未生成就显示了;

    后续再开发再更新!!!

    使用html2canvas.js实现页面截图(生成海报效果)

    生成海报功能最终使用的是html2canvas.js库实现的,不过过程中也有些兼容性问题需要解决,下面是生成海报方法:

    createIMG () { //一键生成图片
       window.scrollTo(0, 0); // 解决部分手机生成图片大片白边
       var _this = this;
       // 海报布局,将布局好的结构进行canvas转换,再将canvas转换成图片
       var targetDom = document.getElementById("pic_wrapper_page");
       html2canvas( targetDom, 
         {
          useCORS: true,   
          height: targetDom.offsetHeight-2,// 解决部分手机生成图片部分白边
           targetDom.offsetWidth-2,
         }).then(function(canvas) {
            var image = canvas.toDataURL("image/png");  
            _this.pic_src = image  // 最终生成的图片
        });                    
    }
    
  • 相关阅读:
    Python"sorted()"和".sort()"的区别
    pandas.DataFrame.sample
    List和Tuple的中的method对比
    Python格式输出汇总
    Ubuntu12.04安装配置vncserver
    Ubuntu12.04安装配置x11vnc
    Python的list中的选取范围
    Python中使用"subplot"在一张画布上显示多张图
    pylab和pyplot的区别
    c++下new与delete基础用法
  • 原文地址:https://www.cnblogs.com/lisaShare/p/12682358.html
Copyright © 2011-2022 走看看