svg 渲染 html 标签 及 添加到 canvas 中

主要用到 svg 的  foreignObject  

https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/foreignObject

 

记录demo

import { fabric } from "fabric";
import { Pieces } from "../@share/pieces";

/**
 * svg 将 html 内容转成 图片并添加到 canvas 中;支持改变并重新渲染
 */
export class SvgForeignObject {
    width = '100px';
    height = '50px';
    styleObj = {
        'font-weight': 'bold',
        'background-color': 'blue',
        'font-size': '16px',
        'color': '#fff',
        'border-radius': '5px',
        'width': this.width,
        'height': this.height,
    };
    style = ''; // 最终使用的样式列表
    innerHTML = 'Button';

    constructor() {
        let body = $('body');

        // fabric 获取 canvas 对象
        let canvas = this.getCanvas(body);

        // 添加改变样式的操作按钮
        this.addButtons(canvas, body);

        // 开始绘制
        this.init(canvas, body);
    }

    /**
     * 流程整理成调用方法
     * @param canvas
     * @param body
     */
    init(canvas, body) {
        // 获取模板字符串
        let str = this.getSvg();

        // 将 svg 添加到 canvas 中
        this.addSvgToCanvas(canvas, str);

        // 添加 svg 到 body,直观效果
        this.addSvgToBody(body, str);
    }

    /**
     * 拼接 svg template
     * xmlns="http://www.w3.org/2000/svg"  SVG专属命名空间
     * <foreignObject>元素允许包含来自不同的 XML 命名空间的元素。在浏览器的上下文中,很可能是 XHTML / HTML。
     * @return {string}
     */
    getSvg() {
        // 拼接样式
        this.style = '.btn {';
        let attrs = Object.keys(this.styleObj);
        attrs.forEach(attr => {
            this.style = this.style + attr + ':' + this.styleObj[attr] + ';';
        });
        this.style += '}';

        // 返回最终 svg str
        return `
        <svg width="${ this.width }" height="${ this.height }" xmlns="http://www.w3.org/2000/svg">
            <style>
            ${ this.style }
            </style>
            <foreignObject  height="100%" width="100%">
             <div class="btn" xmlns="http://www.w3.org/1999/xhtml" >${ this.innerHTML }</div>
            </foreignObject>
        </svg>`;
    }

    /**
     * fabric 获取 canvas 对象
     * @param body
     * @return {*}
     */
    getCanvas(body) {
        let id = new Date().getTime() + '';
        body.append(`<canvas id="${ id }" width="500" height="500" style="border:1px solid grey;"></canvas>`);
        return new fabric.Canvas(id);
    }

    /**
     * 添加 svg 到 canvas 中,使用 dataUrl 形式
     * @param canvas
     * @param str
     */
    addSvgToCanvas(canvas, str) {
        let dataUrl = 'data:image/svg+xml;base64,' + window.btoa(str);
        new fabric.Image.fromURL(dataUrl, (img) => {
            let objs = canvas.getObjects();
            if (objs.length) {
                // 存在则删除
                canvas.remove(objs[0]);
            }
            canvas.add(img);
            img.center();
            img.sendBackwards();
        });
    }

    /**
     * 添加改变样式的 按钮
     * @param canvas
     * @param body
     */
    addButtons(canvas, body) {
        body.append(`<button class="button">Change Style</button>`);
        $('.button').on('click', (e) => {
            this.styleObj['background-color'] = Pieces.getColor();
            this.styleObj['color'] = Pieces.getColor();
            this.innerHTML = 'Button' + Math.round(Math.random() * 10);
            // 重绘
            this.init(canvas, body);
        });
    }

    /**
     * svg 添加到 body 中
     * @param body
     * @param str
     */
    addSvgToBody(body, str) {
        if (document.getElementsByTagName('svg').length) {
            // 存在说明为更新,删除旧样式
            document.getElementsByTagName('svg')[0].remove();
        }
        body.append(str);
    }
}

 

效果:

 

 

 

posted @ 2022-06-14 16:41  名字不好起啊  阅读(874)  评论(0编辑  收藏  举报