Blazor入门-简单svg绘制+导出图像

参考:
SVG 教程 | 菜鸟教程
https://www.runoob.com/svg/svg-tutorial.html

本地环境:win10, visual studio 2022 community


注意:本文只给出思路和框架,对于具体的计算细节,考虑到日后会写入软件著作权和专利文书,因此不会展示。(虽然大概率要经过修改后才会放进文书,但是考虑到隐私保护,还是不写了。不过基本都是三角函数)

效果

在这里插入图片描述
导出效果:
在这里插入图片描述

实现

思路

<svg>标签内,首先绘制两个圆,形成圆环;然后再使用循环,每次绘制一组<path><line><text>。需要着重考虑的是:

  • <path>的数据属性(d)、<line>中起终点坐标和<text>坐标的计算(这部分是三角函数,不展开)
  • 导出按钮的onclick函数编写
  • 实际的导出函数(js)

前端

    <div>
        <svg id="mySvg" width="100%" xmlns="http://www.w3.org/2000/svg" style="display:none">
            <rect  width="100%" height="100%" fill="white" />
            <circle cx="@cx" cy="@cy" r="@outerRadius" fill="#ccc" stroke="#ccc" stroke-width="1" />
            <circle cx="@cx" cy="@cy" r="@innerRadius" fill="#fff" stroke="#ccc" stroke-width="1" />
            @foreach (DisplayPart p in v.Parts)
            {
                <g>
                    <path d="@p.PathData" opacity="0.5" fill="@p.Color" stroke="black" stroke-width="2" data-toggle="tooltip" title="@p.Name" />
                    <line x1="@p.Lcx" y1="@p.Lcy" x2="@p.Tcx" y2="@p.Tcy" stroke="black" stroke-width="1" />
                    <text x="@p.Tcx" y="@p.Tcy" fill="black">@p.Name</text>
                </g>
                
            }
        </svg>
    </div>

    <div id="exportBtnDiv" style="display:none">
        <button value="" class="btn btn-primary" id="ExportSvgBtn" @onclick="ExportSvg">
            导出图谱
        </button>
    </div>

注意:

  • <rect width="100%" height="100%" fill="white" />是为svg增加白色背景
  • 其中@开头的变量都是在code中定义的
  • v.PartsList<DisplayPart>DisplayPart是自定义的一个类型

随后,在@code{}块中,实现ExportSvgBtn

    private async Task ExportSvg()
    {
        var svgElement = await JsRuntime.InvokeAsync<IJSObjectReference>("document.getElementById", "mySvg");
        await module.InvokeVoidAsync("exportSvgToImage", svgElement, "png");
    }

其中JsRuntime是:

@inject IJSRuntime JsRuntime

而module在前面定义过,这里用它可以调用在别处定义的js函数。
参考:
Blazor入门-调用js+例子-CSDN博客
https://blog.csdn.net/pxy7896/article/details/138670348

跟这篇文章里一样设置即可。

下载svg图像的js代码

export function exportSvgToImage(svgElement, format) {
    if (format == null)
        return;
    var svgXml = new XMLSerializer().serializeToString(svgElement);
    var imageUrl = "data:image/svg+xml;base64," + btoa(svgXml);
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    var img = new Image();
    img.onload = function () {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        var a = document.createElement("a");
        a.download = "exported_image." + format;
        a.href = canvas.toDataURL("image/" + format);
        a.click();
    };
    img.src = imageUrl;
}

注意:函数前面写export的原因已在上一节的参考文章里解释。

报错

Error: Microsoft.JSInterop.JSException: Failed to execute ‘btoa’ on ‘Window’: The string to be encoded contains characters outside of the Latin1 range.

这个错误通常发生是因为要编码的字符串中包含了Latin1范围之外的字符。解决方案是修改 exportSvgToImage 函数的这句:

var imageUrl = "data:image/svg+xml;base64," + btoa(svgXml);

改为:

var utf8 = unescape(encodeURIComponent(svgXml));
var imageUrl = "data:image/svg+xml;base64," + btoa(utf8);

下载svg图像时,只显示一部分

使用上面下载图像的js代码时,输出的图像可能只有一部分,如下图所示:
在这里插入图片描述
解决方案是将canvas的宽高设置为跟svg元素一致:

    canvas.width = svgElement.clientWidth;
    canvas.height = svgElement.clientHeight;

改进

未来会通过算法调整label的位置和line的线形,以避免label重叠。如果可以的话,会再写:)

写了,但是写得有限,希望能有所启发吧。

Blazor入门-svg绘制-碰撞检测和图形坐标调整-CSDN博客
https://blog.csdn.net/pxy7896/article/details/139261297

  • 32
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值