• SVG: 将 svg 导出成图片


    svg 导出成图片会有很多限制, 外链的图片, 样式均会丢失,推荐使用 saveSvgAsPng.js 进行导出

    以下是借鉴库写的导出函数:

    function reEncode(data) {
        return decodeURIComponent(
            encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, (match, p1) => {
                const c = String.fromCharCode(`0x${p1}`);
                return c === '%' ? '%25' : c;
            })
        )
    }
    
    
    function export2Base64Img(svgDom, MIMEType, option) {
        var serializer = new XMLSerializer();
        var source = serializer.serializeToString(svgDom);
        // 方式一: unescape(encodeURIComponent(txt))
        // var path = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(source)));
        // 方式二: decodeURIComponent(encodeURIComponent(txt))
        var path = "data:image/svg+xml;base64," + window.btoa(reEncode(source));
        var canvas = document.createElement("canvas"),
            context = canvas.getContext("2d"),
            img = new Image(),
            pixelRatio = window.devicePixelRatio || 1,
            _exportPath, handler
        option = option || {};
    
        canvas.width = parseFloat(svgDom.getAttribute('width')); //  * pixelRatio
        canvas.height = parseFloat(svgDom.getAttribute('height')); //  * pixelRatio 
        img.src = path;
        img.onload = function () {
            // 增加底色
            if (option.background) {
                context.beginPath();
                context.rect(0, 0, canvas.width, canvas.height);
                context.fillStyle = option.background;
                context.fill();
                context.closePath();
            }
            //
            context.drawImage(img, 0, 0);
    
            var marker = option.watermark || "";
    
            if (marker) {
                context.font = "18px 微软雅黑";
                context.fillStyle = "rgba(12, 0, 70, 0.5)";
    
                var textWidth = context.measureText(marker).width,
                    textHegith = 50,
                    pk = 1.2,
                    rotate = (option.rotation || -45) * Math.PI / 180,
                    sinReg = Math.sin(rotate),
                    cosReg = Math.cos(rotate),
                    width = Math.abs(canvas.width * cosReg) + Math.abs(canvas.height * sinReg),
                    height = Math.abs(canvas.height * cosReg) + Math.abs(canvas.width * sinReg);
    
                    var xf = Math.ceil(width / textWidth * pk);
                    var yf = Math.ceil(height / textHegith);
    
                    context.rotate(rotate);
    
                    for (var i = 0; i < yf; i++) {
                        for (var k = 0; k < xf; k++) {
                            context.fillText(marker, textWidth * k * pk - canvas.height * cosReg, textHegith * i)
                        }
                    }
                }
    
    
            document.body.appendChild(canvas);
            _exportPath = canvas.toDataURL(MIMEType || 'image/png', 1)
            typeof handler === 'function' && handler(_exportPath)
            document.body.removeChild(canvas)
        }
    
        return new Promise(function (resolve, reject) {
            handler = resolve
        })
    }
    View Code

    一个小例子;

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            * {
                /* margin: 0; */
                padding: 0;
            }
    
            body {
                background: #f3f3f3;
            }
    
            svg .pinkCircle {
                fill: rgba(145, 92, 101, 0.671);
                stroke: #f60;
                stroke-width: 5;
            }
    
            svg .blackRect {
                fill: black;
                stroke: #ccc;
                stroke-width: 2;
            }
        </style>
    </head>
    
    <body>
        <p>Svg Start</p>
        <svg width="800" height="600" id="svg">
            <!-- 圆形: cx, cy, r -->
            <circle cx="80" cy="40" r="15" class="pinkCircle"></circle>
            <circle cx="180" cy="40" r="15" class="pinkCircle"></circle>
            <circle cx="100" cy="100" r="25" class="pinkCircle"></circle>
            <!-- fill="pink" stroke="#f60" stroke-width="5" 也可以直接设置属性的方式 -->
    
            <!-- 矩形: x, y, rx, ry -->
            <rect x="80" y="50" class="blackRect" width="60" height="42" rx="8" ry="20"></rect>
            <!-- 通过 class 定义的样式只能定义填充和边框, 无法定义 svg内几何图形的大小或位置 -->
            <!-- rect 标签的 坐标位置用 x, y来表示, 而且额外可以定义 rx, ry; 表示圆角在 水平/垂直方向上的曲率半径 -->
    
            <!-- 椭圆 -->
            <ellipse cx="120" cy="120" rx="60" ry="20"></ellipse>
            <!-- cx: 椭圆中心点的水平位置
                 cy: 椭圆中心点的垂直位置
                 rx: 椭圆水平方向上的半径
                 ry: 椭圆垂直方向上的半径
                ???? 椭圆什么时候会有中心点? 而且椭圆是有两个中心点
                椭圆的绘制方法:
                https://jingyan.baidu.com/article/4ae03de30f5bfc3efe9e6b7f.html -->
    
            <!-- 多边形 -->
            <polygon points="300,300 350,350 420,300"></polygon>
            <!-- points 一系列的 x 和 y 坐标点, 描述了多边形各个角的位置
                多边形是一个封闭的形状, 如果制定了几个点, 那么这几个点自动会与第一个点相连 -->
    
            <!-- 线 -->
            <line x1="0" y1="0" x2="700" y2="700" stroke="black" stoke-width="2"></line>
            <!-- x1: 起点的水平位置
                y1: 起点的垂直位置
                x2: 终点的水平位置
                y2: 终点的垂直位置 -->
    
            <!-- 路径 -->
            <!-- d: 告知浏览器如何绘图 -->
            <!-- M: moveto 的缩写, 目标是一个假想的点 
                q 告诉光标要绘制一条贝塞尔曲线, 什么是贝塞尔曲线:? 可以从B站中去搜索查看, 一段几十分钟的讲解, 很复杂, 到处都在用的贝塞尔曲线 -->
            <path d="M 100 500 L 300 500 L 200 300 z" fill="orange" stroke="black" stroke-width="3" />
    
            <!-- 文本 -->
            <text x="120" y="520" font-size="30" fill="blue" stroke="#ccc" stroke-width="2" font-family="Comic Sans MS"
                text-anchor="start" opacity="0.5">hello Svg
    
                <a xlink:href="http://www.baidu.com" target="_blank">这是一个链接</a>
            </text>
            <!-- svg 的基本文本属性与 HTML 同名, font-size, font-family, font-weight, font-style
            除了颜色除外, 这些都是。 svg文本和图形一样, 颜色都叫"填充", 同样, 也可以在文本周围添加 "笔触" -->
            <!-- x 和 y 属性指定了文本锚点的位置, 默认情况下, 锚点标识了文本的开始并与文本基线垂直对齐
                设置 text-anchor 可以改变锚点的位置, 值有 start, center, end
                svg 没有办法简单绘制一个文本块并让它们自动换行
            -->
    
            <!--  svg 绘图中, 还可以使用 opacity 设置透明度等;  -->
        </svg>
    
        <script>
            function reEncode(data) {
                return decodeURIComponent(
                    encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, (match, p1) => {
                        const c = String.fromCharCode(`0x${p1}`);
                        return c === '%' ? '%25' : c;
                    })
                )
            }
    
            function export2Base64Img(svgDom, MIMEType, option) {
                var serializer = new XMLSerializer();
                var source = serializer.serializeToString(svgDom);
                // 方式一: unescape(encodeURIComponent(txt))
                // var path = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(source)));
                // 方式二: decodeURIComponent(encodeURIComponent(txt))
                var path = "data:image/svg+xml;base64," + window.btoa(reEncode(source));
                var canvas = document.createElement("canvas"),
                    context = canvas.getContext("2d"),
                    img = new Image(),
                    pixelRatio = window.devicePixelRatio || 1,
                    _exportPath, handler
                option = option || {};
    
                canvas.width = parseFloat(svgDom.getAttribute('width')); //  * pixelRatio
                canvas.height = parseFloat(svgDom.getAttribute('height')); //  * pixelRatio 
                img.src = path;
                img.onload = function () {
                    // 增加底色
                    if (option.background) {
                        context.beginPath();
                        context.rect(0, 0, canvas.width, canvas.height);
                        context.fillStyle = option.background;
                        context.fill();
                        context.closePath();
                    }
                    //
                    context.drawImage(img, 0, 0);
    
                    var marker = option.watermark || "";
    
                    if (marker) {
                        context.font = "18px 微软雅黑";
                        context.fillStyle = "rgba(12, 0, 70, 0.5)";
    
                        var textWidth = context.measureText(marker).width,
                            textHegith = 50,
                            pk = 1.2,
                            rotate = (option.rotation || -45) * Math.PI / 180,
                            sinReg = Math.sin(rotate),
                            cosReg = Math.cos(rotate),
                            width = Math.abs(canvas.width * cosReg) + Math.abs(canvas.height * sinReg),
                            height = Math.abs(canvas.height * cosReg) + Math.abs(canvas.width * sinReg);
    
                        var xf = Math.ceil(width / textWidth * pk);
                        var yf = Math.ceil(height / textHegith);
    
                        context.rotate(rotate);
    
                        for (var i = 0; i < yf; i++) {
                            for (var k = 0; k < xf; k++) {
                                context.fillText(marker, textWidth * k * pk - canvas.height * cosReg, textHegith * i)
                            }
                        }
                    }
    
    
                    document.body.appendChild(canvas);
                    _exportPath = canvas.toDataURL(MIMEType || 'image/png', 1)
                    typeof handler === 'function' && handler(_exportPath)
                    document.body.removeChild(canvas)
                }
    
                return new Promise(function (resolve, reject) {
                    handler = resolve
                })
            }
    
    
            var svg = document.getElementById("svg");
            svg.onclick = function () {
                var img = export2Base64Img(svg, null, {
                    watermark: 'copyright reserved 2020 版权所有',
                    background: '#fff'
                });
                img.then(function (base64src) {
                    // console.log('路径:::', base64src)
                    downLoad(base64src, '图.png')
                })
            }
            function downLoad(url, fileName) {
                var oA = document.createElement("a");
                oA.download = fileName || '';
                oA.style.display = 'none'
                oA.href = url;
                document.body.appendChild(oA);
                oA.click();
                oA.remove();
            }
    
        </script>
    </body>
    
    </html>
    View Code
  • 相关阅读:
    词频统计
    第二周每周例行报告
    事务管理(ACID)
    Redis
    jar包和war包的区别
    CSS实现Loading加载动画
    如何实现“返回顶部”的页面效果
    PHP页面跳转-常见方法
    局域网络调试方式
    Thinkphp 统计数据库字段总值
  • 原文地址:https://www.cnblogs.com/liuyingde/p/14133116.html
Copyright © 2020-2023  润新知