温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何用Blazor技术封装G2Plot实现Charts组件

发布时间:2021-11-15 14:39:59 阅读:289 作者:柒染 栏目:大数据
开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这期内容当中小编将会给大家带来有关如何用Blazor技术封装G2Plot实现Charts组件,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

Blazor是一个使用 .NET 生成交互式客户端 Web UI 的框架。目前社区刚起步,相关的组件并不多,有幸有一群爱好者正在努力建设社区,我作为社区一员也来贡献一些内容。这里我就分享分享我封装G2Plot后的Blazor组件ant-design-charts-blazor。

ant-design-charts-blazor属于Ant Design of Blazor的一个开源项目,我们的目标是做Ant Design在Blazor生态圈最优秀的实现,废话不多说,先来看一下目前实现的图表。

如何用Blazor技术封装G2Plot实现Charts组件

安装与使用

项目地址:

ant-design-blazor/ant-design-charts-blazor  github.com

安装 Nuget 包引用

$ dotnet add package AntDesign.Charts

wwwroot/index.html(WebAssembly) 或Pages/_Host.razor(Server) 中引入静态文件:

<script src="https://unpkg.com/@antv/g2plot@latest/dist/g2plot.js"></script><script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>

_Imports.razor中加入命名空间

@using AntDesign.Charts

最后就可以在.razor组件中引用啦!

<Line Data="data" Config="config" />@code{    object[] data = new object[] {        new  { year= "1991", value= 3 },        new  { year= "1992", value= 4 },        new  { year= "1993", value= 3.5 },        new  { year= "1994", value= 5 },        new  { year= "1995", value= 4.9 },        new  { year= "1996", value= 6 },        new  { year= "1997", value= 7 },        new  { year= "1998", value= 9 },        new  { year= "1999", value= 13 },};    LineConfig config = new LineConfig()    {        title = new Title()        {            visible = true,            text = "曲线折线图",        },        description = new Description()        {            visible = true,            text = "用平滑的曲线代替折线。",        },        padding = "auto",        forceFit = true,        xField = "year",        yField = "value",        smooth = true,    };}

组件的使用相对于原先的G2Plot并没有太多变化,主要针对C#语法的特点增加了强类型支持,属性命名规则符合C#语法习惯等。

所以这篇文章不想多聊如何使用的问题,我想谈谈在对G2Plot封装的过程中遇到的一些困难和实现方式,希望能为Blazor社区做出一些绵薄的贡献,如大佬看了有更好的实现方式希望告知在下。

Config对象的封装

G2Plot是通过传入一个Config对象来配置图表的呈现内容,而且只需要给出必要的参数即可,这一切设计的都非常合理。

但是用C#实现的时候就遇上了问题,当Config对象通过InvokeVoidAsync传到JS后,对象会包含所有属性,这对于G2Plot来说就画蛇添足了,有些默认属性会被带进来的空属性给覆盖了,图表显示就出现了问题。

当然最简单的就是把值为Null的属性从Config剔除,嘿嘿,我就是这么干的。通过一个递归遍历对象中的所有属性,移除没有值的属性。

function isEmptyObj(o) {    for (let attr in o) return !1;    return !0}function processArray(arr) {    for (let i = arr.length - 1; i >= 0; i--) {        if (arr[i] === null || arr[i] === undefined) arr.splice(i, 1);        else if (typeof arr[i] == 'object') removeNullItem(arr[i], arr, i);    }    return arr.length == 0}function proccessObject(o) {    for (let attr in o) {        if (o[attr] === null || o[attr] === undefined) delete o[attr];        else if (typeof o[attr] == 'object') {            removeNullItem(o[attr]);            if (isEmptyObj(o[attr])) delete o[attr];        }    }}//清除没有值的项function removeNullItem(o, arr, i) {    let s = ({}).toString.call(o);    if (s == '[object Array]') {        if (processArray(o) === true) {            if (arr) arr.splice(i, 1);        }    } else if (s == '[object Object]') {        proccessObject(o);        if (arr && isEmptyObj(o)) arr.splice(i, 1);    }}

一个问题解决了,有一个问题来了,JS/TS是弱类型语言,他对象中的属性可以在实例化时任意添加,C#可不行,他被定义约束的死死的,这就遇到下面两个问题:

  1. 有些配置属性不可能穷举所有的属性定义。

  2. 而且作为组件的封装者不可能无时差的跟进G2Plot对Config定义的变化。

针对这两个问题,我们需要C#中有一个类似的弱类型的对象,这时候我看上了object,它可以定义成任何类型,如果用它做Config参数,可谓是一劳永逸,岂不美哉。

理想是美好的,现实是残酷的。如果用object,那么C#的强类型就彻底丧失,编写图表配置时完全没有提示,基本就是盲写,太恐怖了,C#的优雅荡然无存。

这时突然脑子冒出个念头,为啥不能使用两个配置,一个是强类型的,一个是object,然后将他们合并成最终的配置给到G2Plot,完美。

基本原理就是通过一个递归将传入JS的配置对象挨个对比,并将它们合并,JS实现代码如下

function deepObjectMerge(source, target) {    for (var key in target) {        if (source[key] && source[key].toString() === "[object Object]") {            deepObjectMerge(source[key], target[key])        } else {            source[key] = target[key]        }    }    return source;}

Blazor中使用方法如下(部分代码)

<Tabs>    <TabPane Key="1">        <Tab>示例1</Tab>        <ChildContent>            <Line Data=data1 Config="config1" OtherConfig="otherConfig1" />        </ChildContent>    </TabPane></Tabs>@code{    LineConfig config1 = new LineConfig()    {        XField = "date",        YField = "value",    };    object otherConfig1 = new    {        = new object[]        {            new{                Visible = true,                data =new object []{new { date = "2019-05-01", value = 4.9 },new  { date = "2019-10-01" } },               Label = new                {                    Visible = true,                    Field = "festival",                },            },        },    };}

G2Plot对象方法调用

通过Config生成的图表是静态的,没有生命的死物,我们需要通过调用它的一些函数给予他生命,比如更新配置,更新数据,设置高亮等等。

那么问题就来了,IJSRuntime提供的InvokeAsync方法只能返回可以序列化成json的对象,通过new G2Plot得到的对象不属于此列,我们如何在C#代码中得到G2Plot对象就是个难题了。

好在Blazor提供了一个ElementReference对象给我们,它只能作为Html对象的引用,没法作为JS对象引用,有点可惜,不过它给我们分配了唯一的Id,既然如此,我们就曲线救国。

第一步,得到div的ElementReference

<div @ref="Ref"></div>@code{    protected ElementReference Ref;}

第二步,构造的G2Plot对象,并放到一个叫“chartsContainer”的JS对象中,以Ref.Id作为索引

const plot = new G2Plot[type](domRef, config);plot.render();window.AntDesignCharts.chartsContainer[domId] = plot;

第三步,如果需要调用G2Plot对象的方法,那么直接拿着Ref.Id去“chartsContainer”中找到对象后调用,下面是“changeData”方法的实现

changeData(domId, data, all) {    if (window.AntDesignCharts.chartsContainer[domId] == undefined) return;    window.AntDesignCharts.chartsContainer[domId].changeData(data, all);},

第四步,组件销毁时及时清理“chartsContainer”中不用的对象

public async void Dispose()    await JS.InvokeVoidAsync(InteropDestroy, Ref.Id);}

到目前已经完成绝大部分功能,还有一些功能需要进一步技术攻关。

上述就是小编为大家分享的如何用Blazor技术封装G2Plot实现Charts组件了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/3772973/blog/4449356

AI

开发者交流群×