echarts .NET类库开源
前言:
2012年从长沙跑到深圳,2016年又从深圳回到长沙,兜兜转转一圈,又回到了原点.4年在深圳就呆了一家公司,回长沙也是因为深圳公司无力为继,长沙股东老板挽留,想想自己年纪也不小了.就回来了,在长沙工作几月,也没什么太多的不适应.不用赶着项目上线,不用加班,想想其实也不错.
从12年在长沙就想写点开源的东西,不过实在不敢献丑.这次机缘巧合,有个朋友一个项目需要用到大量报表,我找到百度的开源echarts项目(感谢开源,4年工作以来用到很多很好的开源项目,对工作助力颇多),看着就挺舒服的,又看到了@abel533写的java类库,萌生了想写一个.net类库的想法.项目后来没做下去了,但是echart类库倒是坚持写下来了.断断续续几个月的时间,终于有点样子了.之所以写这篇博客,是因为最近在园子里看到很多看衰.net的文章,我无法判断对错,也不想引起争论,不过我只是简单喜欢编程的人,能够做自己喜欢的事就好,其实好的环境需要大家一起营造,我也想为.net阵营做一些有意义的事情.
源码:
源码地址:https://github.com/idoku/EChartsSDK
echart地址:http://echarts.baidu.com/
先放几张eharts的图感受一下:
折线图
柱状图
散点图
饼图
正文
ECharts .Net类库
当前版本1.0.1
Echarts
本项目是一个供.NET开发者使用的ECharts的开发包,主要目的是方便在.NET中构件Echarts中可能用的全部数据结构,完整的Option结构. ChartOption中的数据Series,包含Line-折线图,Bar-柱状图,Pie-饼图,Scatter-散点图等,支持Echarts中所有图表.支持所有Style类,如AreaStyle,ItemStyle,LineStyle等.支持多种Data数据类型,一个通用的Data数据,以及PieData,PolarData,TreeData等个性化数据结构.
你可以使用本项目直接构件一个Option对象,使用方法JsonTools.ObjectToJson2(option),(直接使用Json方式返回存在问题,因为function不是标准化的json格式,转换会报错).
图表类型
- Line - 折线(面积)图
- Bar - 柱状(条形)图
- Scatter - 散点(气泡)图
- K - K线图
- Pie - 饼(圆环)图
- Radar - 雷达(面积)图
- Chord - 和弦图
- Force - 力导向布局图
- Map - 地图
- Gauge - 仪表盘
- Funnel - 漏斗图
- Heatmap - 热力图
- EventRiver - 事件河流图
- Venn - 韦恩图
- Tree - 树图
- Treemap - 矩形树图
- WordCloud - 词云
Echarts组件
- Axis - 坐标轴
- Grid - 网格
- Title - 标题
- Tooltip - 提示
- Legend - 图例
- DataZoom - 数据区域缩放
- DataRange - 值域漫游
- Toolbox - 工具箱
- Timeline - 时间线
ChartOption说明
- ChartOption 是echarts的主要类.
- 使用JsonTools.ObjectToJson2方法返回给前端时,需要使用eval('(' + data + ')')转换为JSON结构.
Function说明
由于json标准中不包含function类型,一般json库都不支持这种类型,处理这种类型最简单的方式是转换json字符串时,对字符串进行处理.
读者可以自行使用其他自定义方式实现,本项目使用的.net自带的JRaw()方式.不管是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | "formatter" : function( params ) { // for text color var color = colorList[ params [0].dataIndex]; var res = '<div style="color:' + color + '">' ; res += '<strong>' + params [0].name + '消费(元)</strong>' for ( var i = 0, l = params .length; i < l; i++) { res += '<br/>' + params [i].seriesName + ' : ' + params [i].value } res += '</div>' ; return res; }, |
和
"color": (function (){ var zrColor = require('zrender/tool/color'); return zrColor.getLinearGradient( 0, 400, 0, 300, [[0, 'green'],[1, 'yellow']] ) })(),
都可以利用JRaw来实现.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | option.ToolTip().Trigger(TriggerType.axis) .BackgroundColor( "rgba(255,255,255,0.7)" ) .Formatter( new JRaw( @"function(params) { // for text color var color = colorList[params[0].dataIndex]; var res = '<div style=""color:' + color + '"">'; res += '<strong>' + params[0].name + '消费(元)</strong>' for (var i = 0, l = params.length; i < l; i++) { res += '<br/>' + params[i].seriesName + ' : ' + params[i].value } res += '</div>'; return res; }" )) style.Emphasis().BarBorderColor( "green" ).BarBorderWidth(5) .Color( new JRaw( @"(function (){ var zrColor = require('zrender/tool/color'); return zrColor.getLinearGradient( 0, 400, 0, 300, [[0, 'red'],[1, 'orange']] ) })()" )) |
EchartsWeb
本项目通过ASP.NET MVC和ASP.NET web api模拟了echarts官网网站中的全部示例,主要目的是方便大家参考使用和调整结构.
1.简单Line示例
演示地址: http://echarts.idoku.cn/home/example?api=line1
例子中给出的json结构.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | { "calculable" : true , "title" : { "text" : "未来一周天气变化" , "subtext" : "纯虚构数据" , "show" : true }, "tooltip" : { "trigger" : "axis" }, "legend" : { "data" : [ "最高温度" , "最低温度" ] }, "xAxis" : [ { "data" : [ "周一" , "周二" , "周三" , "周四" , "周五" , "周六" , "周日" ], "boundaryGap" : false , "type" : "category" } ], "yAxis" : [ { "type" : "value" , "axisLabel" : { "formatter" : "{value} ℃" } } ], "series" : [ { "data" : [ 13, 10, 12, 10, 13, 13, 14 ], "type" : "line" , "name" : "最高温度" , "markPoint" : { "data" : [ { "name" : "最大值" , "type" : "max" }, { "name" : "最小值" , "type" : "min" } ] }, "markLine" : { "data" : [ { "name" : "平均值" , "type" : "average" } ] } }, { "data" : [ 3, -1, 1, -1, 3, 3, 4 ], "type" : "line" , "name" : "最低温度" , "markPoint" : { "data" : [ { "name" : "周最低" , "value" : -1, "xAxis" : 1, "yAxis" : -0.5 } ] }, "markLine" : { "data" : [ { "name" : "平均值" , "type" : "average" } ] } } ] } |
对应的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | [AcceptVerbs( "GET" , "POST" )] [ActionName( "line1" )] public string StdLine() { IList< string > weeks = ChartsUtil.Weeks(); IList< int > datas1 = ChartsUtil.Datas(7, 10, 15); IList< int > datas2 = ChartsUtil.Datas(7, -2, 5); int min = datas2.Min(); int index = datas2.IndexOf(min); ChartOption option = new ChartOption(); option.title = new Title() { show = true , text = "未来一周天气变化" , subtext = "纯虚构数据" }; option.tooltip = new ToolTip() { trigger = TriggerType.axis }; option.legend = new Legend() { data = new List< object >(){ "最高温度" , "最低温度" } }; option.calculable = true ; option.xAxis = new List<Axis>() { new CategoryAxis() { type = AxisType.category, boundaryGap= false , data = new List< object >(weeks) } }; option.yAxis = new List<Axis>() { new ValueAxis() { type = AxisType.value, axisLabel = new AxisLabel(){ formatter= new JRaw( "{value} ℃" ).ToString() } } }; option.series = new List< object >() { new Line() { name = "最高温度" , type = ChartType.line, data = datas1, markPoint = new MarkPoint() { data = new List< object >() { new MarkData() { name = "最大值" , type= MarkType.max, }, new MarkData() { name = "最小值" , type= MarkType.min, } } }, markLine = new MarkLine() { data = new List< object >() { new MarkData() { name = "平均值" , type = MarkType.average } } } }, new Line(){ name= "最低温度" , type = ChartType.line, data = datas2, markPoint= new MarkPoint(){ data = new List< object >(){ new MarkData(){ name= "周最低" , value = min, xAxis = index, yAxis = min+0.5, } } }, markLine = new MarkLine(){ data = new List< object >(){ new MarkData(){ type = MarkType.average, name = "平均值" } } } } }; var result = JsonTools.ObjectToJson2(option); return result; } |
2.使用function的bar示例.
演示地址: http://echarts.idoku.cn/home/example?api=bar10#
给出的json代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | { "title" : { "text" : "温度计式图表" , "subtext" : "Form ExcelHome" , "sublink" : "http://e.weibo.com/1341556070/AizJXrAEa" }, "toolbox" : { "feature" : { "mark" : { "show" : true }, "dataView" : { "show" : true , "readOnly" : false }, "restore" : { "show" : true }, "saveAsImage" : { "show" : true } }, "show" : true }, "tooltip" : { "trigger" : "axis" , "formatter" : function ( params ){ return params [0].name + '<br/>' + params [0].seriesName + ' : ' + params [0].value + '<br/>' + params [1].seriesName + ' : ' + ( params [1].value + params [0].value); }, "axisPointer" : { "type" : "shadow" } }, "legend" : { "data" : [ "Acutal" , "Forecast" ] }, "grid" : { "y2" : 30, "y" : 80 }, "xAxis" : [ { "data" : [ "Cosco" , "CMA" , "APL" , "OOCL" , "Wanhai" , "Zim" ], "type" : "category" } ], "yAxis" : [ { "boundaryGap" : [ 0.0, 0.1 ], "type" : "value" } ], "series" : [ { "stack" : "sum" , "data" : [ 260, 200, 220, 120, 100, 80 ], "type" : "bar" , "name" : "Acutal" , "itemStyle" : { "normal" : { "color" : "tomato" , "barBorderColor" : "tomato" , "barBorderRadius" : 0, "barBorderWidth" : 6, "label" : { "show" : true , "position" : "insideTop" } } } }, { "stack" : "sum" , "data" : [ 40, 80, 50, 80, 80, 70 ], "type" : "bar" , "name" : "Forecast" , "itemStyle" : { "normal" : { "color" : "#fff" , "barBorderColor" : "tomato" , "barBorderRadius" : 0, "barBorderWidth" : 6, "label" : { "show" : true , "position" : "top" , "formatter" : function ( params ) { for ( var i = 0, l = option.xAxis[0].data.length; i < l; i++) { if (option.xAxis[0].data[i] == params .name) { return option.series[0].data[i] + params .value; } } }, "textStyle" : { "color" : "tomato" } } } } } ] } |
对应的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | [AcceptVerbs( "GET" , "POST" )] [ActionName( "bar10" )] public string TemperatureBar() { ChartOption option = new ChartOption(); option.Title().Text( "温度计式图表" ).Subtext( "Form ExcelHome" ). Sublink( "http://e.weibo.com/1341556070/AizJXrAEa" ); option.ToolTip().Trigger(TriggerType.axis) .Formatter( new JRaw( @"function (params){ return params[0].name + '<br/>' + params[0].seriesName + ' : ' + params[0].value + '<br/>' + params[1].seriesName + ' : ' + (params[1].value + params[0].value); }" )) .AxisPointer().Type(AxisPointType.shadow); option.Legend().Data( "Acutal" , "Forecast" ); Feature feature = new Feature(); feature.Mark().Show( true ); feature.DataView().Show( true ).ReadOnly( false ); feature.Restore().Show( true ); feature.SaveAsImage().Show( true ); option.ToolBox().Show( true ).SetFeature(feature); option.Grid().Y(80).Y2(30); CategoryAxis x = new CategoryAxis(); x.Data( "Cosco" , "CMA" , "APL" , "OOCL" , "Wanhai" , "Zim" ); option.XAxis(x); ValueAxis y = new ValueAxis(); y.BoundaryGap( new List< double >() { 0,0.1 }); option.YAxis(y); var tomatoStyle = new ItemStyle(); tomatoStyle.Normal().Color( "tomato" ).BarBorderRadius(0) .BarBorderColor( "tomato" ).BarBorderWidth(6) .Label().Show( true ).Position(StyleLabelTyle.insideTop); Bar b1 = new Bar( "Acutal" ); b1.Stack( "sum" ); b1.SetItemStyle(tomatoStyle); b1.Data(260, 200, 220, 120, 100, 80); var forecastStyle = new ItemStyle(); forecastStyle.Normal().Color( "#fff" ).BarBorderRadius(0) .BarBorderColor( "tomato" ).BarBorderWidth(6) .Label().Show( true ).Position(StyleLabelTyle.top) .Formatter( new JRaw( @"function (params) { for (var i = 0, l = option.xAxis[0].data.length; i < l; i++) { if (option.xAxis[0].data[i] == params.name) { return option.series[0].data[i] + params.value; } } }" )) .TextStyle().Color( "tomato" ); Bar b2 = new Bar( "Forecast" ); b2.Stack( "sum" ); b2.SetItemStyle(forecastStyle); b2.Data(40, 80, 50, 80, 80, 70); option.Series(b1, b2); var result = JsonTools.ObjectToJson2(option); return result; } |
博客总结:
排版真是硬伤~~~因为在项目期间,百度将echarts版本升级到了3.0,但是我已经实现了一半,所以就没有使用新的3.0来实现.而且上面说到的项目没有做下去,所以我是参考了@abel533的写法,实际中使用会碰到什么问题暂时不清楚,如果有园友使用中碰到什么问题,欢迎与我交流.第一次做开源项目,欢迎大家批评指正.
作 者:doku
出 处:http://www.cnblogs.com/kulong995/
关于作者:喜欢编程,喜欢美食,专注于.NET项目开发。
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
2010-03-03 The C# Programming Language(Third Edition) Part III