canvs 画分享海报

本文将介绍如何利用JavaScript和TypeScript的canvas API来创建吸引人的分享海报。内容包括canvas的基本用法,绘制图形、文字以及图片的方法,以及在实际项目中如何优化和适配不同屏幕尺寸。
摘要由CSDN通过智能技术生成
class Share {
    constructor(options = {} as any) {
        (<any>this).picArr = [];
    }
    public createPic() {
        let _this: any = this;
        if (!_this.sharepic) {
            _this.sharepic = document.createElement('div');
            _this.sharepic.className = 'draw-img-cover';
            _this.sharepic.innerHTML = `<div class="share-pic-box">\
            <div class="close"></div>\
            <div class="share-pic-box"><div id="shareCanvas"></div></div>\
            <p class="save-share-card">保存图片分享</p>\
        </div>`;
            let data = { zid: (<any>window).zid, a: 'GetEditorInfo', c: 'Author_Ajax' };
            jsonp('/Mbase/index.php', data).then(function (result: any) {
                if (result.status === 0) {
                    _this.drawCanvas(result.data);
                }
            });
            document.body.appendChild(_this.sharepic);
            _this.sharepic.addEventListener('click', function (e: any) {
                if (e.target.tagName !== 'IMG') {
                    _this.sharepic.style.display = 'none';
                }

            });

        }
        _this.sharepic.style.display = 'block';
    }
    public drawCanvas(data: any) {

        let _this = this;
        // 生成图片
        let shareBox = document.createElement('canvas');

        let ctx = shareBox.getContext('2d');

        let cw = document.body.offsetWidth;

        let ratio = cw / 750;


        (<any>_this).sharepic.querySelectorAll('.share-pic-box').forEach(function (item: any) {
            item.style.width = 540 * ratio + 'px';
            item.style.height = 960 * ratio + 'px';
        });
        ratio = 1.44;
        shareBox.width = 540;
        shareBox.height = 960;

        // ctx.rect(0, 0, shareBox.width, shareBox.height);
        // ctx.fillStyle = '#fff';
        ctx.fill();
        // 背景图
        (<any>_this).picArr.push({
            src: '/bg.png',
            x: 0 * ratio,
            y: 0 * ratio,
            w: shareBox.width,
            h: shareBox.height
        });

        (<any>_this).picArr.push({
            src: data.img,
            type: 'circle',
            r: 44 * ratio,
            cx: 188 * ratio,  // 圆心x
            cy: 276 * ratio, // 圆心y
            x: 144 * ratio,
            y: 232 * ratio,
            w: 88 * ratio,
            h: 88 * ratio
        });

        // icon v
        if (data.desc.length > 0) {
            (<any>_this).picArr.push({
                src: 'icon_V@2x.png',
                x: 212 * ratio,
                y: 300 * ratio,
                w: 20 * ratio,
                h: 20 * ratio
            });
        }

        // 二维码
        (<any>_this).picArr.push({
            src: data.codeImg,
            x: 251 * ratio,
            y: 543 * ratio,
            w: 94 * ratio,
            h: 94 * ratio
        });


        let len = (<any>_this).picArr.length;
        /**
         * 递归函数 canvas画图
         *
         * @param {*} n 图片提前存储在数据中,按序加载图片绘制
         */
        function drawPics(n: any) {
            let item = (<any>_this).picArr[n];
            if (n < len) {
                let img = new Image();
                img.crossOrigin = '*'; // 跨域处理
                img.src = item.src;
                img.onload = function () {
                    if (item.type === 'circle') {
                        _this.getCirclePic(ctx, item.cx, item.cy, item.r, img, item.x, item.y, item.w, item.h);
                    } else {
                        ctx.drawImage(img, item.x, item.y, item.w, item.h);

                    }
                    drawPics(n + 1); // 递归
                };
            } else {
                // 分享描述
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 68 * ratio,
                    y: 100 * ratio,
                    color: '#fff',
                    line: 3,
                    width: 239 * ratio,
                    fontSize: 22 * ratio,
                    lineHeight: 30 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: data.descript
                });

                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: (188 - data.title.length * 12) * ratio,
                    y: 357 * ratio,
                    color: '#222',
                    line: 1,
                    fontSize: 24 * ratio,
                    lineHeight: 0 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: data.title
                });
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: (188 - (data.level.length + data.desc.length + 1) * 6) * ratio,
                    y: 382 * ratio,
                    color: '#666',
                    line: 1,
                    width: 200 * ratio,
                    fontSize: 14 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: `${data.level} ${data.desc}`
                });
                // 分割线
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 129 * ratio,
                    y: 445 * ratio,
                    color: '#F0F0F0',
                    line: 1,
                    width: 10 * ratio,
                    fontSize: 18 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: '|'
                });
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 244 * ratio,
                    y: 445 * ratio,
                    color: '#F0F0F0',
                    line: 1,
                    width: 10 * ratio,
                    fontSize: 18 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: '|'
                });
                // 文章
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 59 * ratio,
                    y: 463 * ratio,
                    color: '#999',
                    line: 1,
                    width: 200 * ratio,
                    fontSize: 14 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: '文章'
                });
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 51 * ratio,
                    y: 434 * ratio,
                    color: '#222',
                    line: 1,
                    width: 100 * ratio,
                    fontSize: 24 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: data.docNum
                });
                // 粉丝
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 174 * ratio,
                    y: 463 * ratio,
                    color: '#999',
                    line: 1,
                    width: 200 * ratio,
                    fontSize: 14 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: '粉丝'
                });
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 158 * ratio,
                    y: 434 * ratio,
                    color: '#222',
                    line: 1,
                    width: 100 * ratio,
                    fontSize: 24 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: data.fansNum
                });

                // 获赞
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 289 * ratio,
                    y: 463 * ratio,
                    color: '#999',
                    line: 1,
                    width: 200 * ratio,
                    fontSize: 14 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: '获赞'
                });
                _this.drawMultiLineTextOnCanvas(ctx, {
                    x: 273 * ratio,
                    y: 434 * ratio,
                    color: '#222',
                    line: 1,
                    width: 100 * ratio,
                    fontSize: 24 * ratio,
                    lineHeight: 20 * ratio,
                    align: 'left',
                    baseline: 'normal',
                    text: data.likeNum
                });
                let sharePic = shareBox.toDataURL('image/jpeg', 1.2);
                if (sharePic) {
                    document.getElementById('shareCanvas').innerHTML = '<img src="' + sharePic + '" />';
                }
            }
        }
        drawPics(0);
        (<any>_this).sharepic.querySelectorAll('.save-share-card').forEach(function (item: any) {
            item.addEventListener('click', function (e: any) {
                let fileName = 'share.jpg';
                let alink = document.createElement("a");
                alink.href = shareBox.toDataURL('image/jpeg', 1.2);
                alink.download = fileName;
                alink.click();
            })

        });
    }
    // 绘制圆形头像
    public getCirclePic(ctx: any, x: number, y: number, r: number, pic: HTMLImageElement, dx: number, dy: number, dWidth: number, dHeight: number) {
        //  x:圆心x轴位置 
        //  y:圆心x轴位置 
        //  r:圆半径
        //  pic:图片 
        //  dx:图片左上角x轴位置
        //  dy:图片左上角y轴位置 
        //  dWidth:图片的宽 
        //  dHeight:图片的高
        ctx.save();
        ctx.beginPath();
        ctx.arc(x, y, r, 0, 2 * Math.PI, false);
        ctx.fill();
        ctx.clip();
        ctx.drawImage(pic, dx, dy, dWidth, dHeight);
        ctx.restore();
    }
    // 把需要绘制的文字根据参数改成多行,然后逐行绘制
    public getCanvasMultiLineText(ctx: any, text: string, width: number, fontSize: number) {
        ctx.font = fontSize + 'px arial';
        if (text === '') {
            return;
        }
        let textArr = text.trim().split('');
        let textLen = textArr.length;
        let line = '';
        let lineArr = [];
        for (let i = 0; i < textLen; i++) {
            let word = line + textArr[i];
            let metrics = ctx.measureText(word);
            if (metrics.width > width && i > 0) {
                lineArr.push(line);
                line = textArr[i];
            } else {
                line = word;
            }
            if (i === textLen - 1) {
                lineArr.push(line);
            }
        }
        return lineArr;
    }
    // 逐行绘制文本
    public drawMultiLineTextOnCanvas(ctx: any, options: any) {
        let str = options.text;
        if (str === undefined) {
            return;
        }

        let textLineArr = this.getCanvasMultiLineText(ctx, options.text, options.width, options.fontSize);
        let lineLen = textLineArr.length;
        for (let i = 0; i < lineLen; i++) {
            if (i < options.line) {
                let text = textLineArr[i].trim();
                if (i === options.line - 1) {
                    let textLen = text.length;
                    if (lineLen > options.line) {
                        text = text.substring(0, textLen - 1) + '...';
                    }
                }
                ctx.save();
                ctx.fillStyle = options.color;
                ctx.font = options.fontSize + 'px arial';
                ctx.textAlign = options.align;
                ctx.textBaseline = options.baseline;
                ctx.fillText(text, options.x, options.y + (i * options.lineHeight));
                ctx.restore();
            }
        }
    };

}

export default Share;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值