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专属命名空间
     * 元素允许包含来自不同的 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 `
        
            
            ${ this.style }
            
            
             
${ this.innerHTML }
`; } /** * fabric 获取 canvas 对象 * @param body * @return {*} */ getCanvas(body) { let id = new Date().getTime() + ''; body.append(``); 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').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); } }

效果: