最近还在忙着基于ABP的项目,但本篇博客和ABP无关,喜欢ABP框架的朋友请点击传送门

这不,最近项目基本功能做的差不多了,现在在做一个数据统计的功能,需要绘制区域图(或折线图)和饼图。一开始,楼主就去Google了一下最常用的绘图插件都有哪些,最后直接去Github上搜索关键词chart,搜索结果如下:

点了几个进去看了之后,楼主考虑到项目要以后肯定要维护,万一维护的开发者英文不咋地呢(其实楼主我是喜欢看英文文档的)?所以,我起初选择了某度出品的Echarts.js。但是选择了它之后,查看文档学习,虽然文档是中文的,但我感觉这文档比英文还难读懂,因为有些术语解释不详细,最后好不容易做了个demo,但还出现了bug,开了一个Issue,维护人员简单地敷衍之后反而直接给关了,楼主表示很受伤也很气愤。心想,好吧,你某度牛逼,我不用你的Echarts行了吧,惹不起还躲不起嘛。

最后,经过几个朋友的介绍,他们都选择的Highcharts,去Highcharts官网看了下,感觉文档就是比Echarts详细,简单易懂,所以我也就选择了她。【这里建议新手朋友们先使用Highcharts,等对图表熟悉了再使用Echarts,毕竟Echarts的图表种类很丰富】而且,到现在,功能也都实现了,效果如下:

楼主在学习的时候,发现网上这方面的资料也不是很多,尤其是从服务端如何传数据到客户端,没有详细的解决方案,也是摸索了很久,这次,我直接将自己的解决方案拿出来和大家分享,供初学者参考,少走弯路,大神请绕道。

区域图

<div class="row">
<div class="portlet light bordered">
<div class="portlet-title">
<div class="caption">
<i class="fa fa-area-chart font-purple"></i>
<span class="caption-subject bold uppercase">收入趋势</span>
</div>
</div>
<div class="portlet-body">
<div id="incomeTrend" style="width:98%;height: 500px"> </div>
</div> </div> </div>

var dateSpan;
Highcharts.setOptions({
lang: { printChart: '打印图表',
downloadJPEG: '下载为JPEG图片',
downloadPDF: '下载为PDF',
downloadPNG: '下载为PNG图片',
downloadSVG: '下载为SVG矢量图',
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
weekdays: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
shortMonths: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
}
});
var isByDay = true;//default by days var option = { chart: {
type: 'area'
},
title: {
text: '收入趋势图'
},
subtitle: {
text: '没有选择时间范围的话,默认显示最近7天的数据'
},
credits: {
enabled: false
},
xAxis: {
type: 'datetime',
tickmarkPlacement: 'on',
title: {
enabled: false
},
dateTimeLabelFormats: {
day: "%Y-%m-%d",
week: "%A",
month: "%Y-%m",
year: "%Y"
}
},
yAxis: {
title: {
text: '单位:元'
},
labels: {
formatter: function () {
return this.value;
}
}
},
tooltip: {
shared: true,
valueSuffix: ' 元',
dateTimeLabelFormats: {
day: "%Y-%m-%d,%A",
week: "%A开始, %Y-%m-%d",
month: "%Y-%m",
year: "%Y"
}
},
plotOptions: {
area: {
stacking: 'normal',
lineColor: '#666666',
lineWidth: 1,
marker: {
lineWidth: 1,
lineColor: '#666666'
}
},
series: {
//pointStart: Date.UTC(nowDate.getFullYear(), nowDate.getMonth(), nowDate.getDate() - 7),
//pointInterval: 24 * 36e5 //一天
}
},
series: [{}]
} var url = getTargetUrl('Dashboard', "GetJsonResult");//这里是url
var drp = $('#dateRange').data('daterangepicker');
if (!dateSpan) {
dateSpan = { start: drp.startDate.format('YYYY-MM-DD'), end: drp.endDate.format('YYYY-MM-DD') }
} rawChart(isByDay); $('#createChart').click(function (e) {
if ($('#byMonth').attr('checked')) {//按月
isByDay = false;
//alert('选择了' + $('#byMonth').attr('checked'));
}
e.preventDefault();
drawChart(isByDay);
drawPieChart(isByDay);
}); $('#defaultChart').click(function (e) {
e.preventDefault();
drp.setStartDate(moment().subtract(7, "days"));
drp.setEndDate(moment().subtract(1, "days"));
dateSpan = { start: drp.startDate.format('YYYY-MM-DD'), end: drp.endDate.format('YYYY-MM-DD') };
$('#dateRange').val('');
isByDay = true;
drawChart(isByDay);
drawPieChart(isByDay);
}); function drawChart(isByDay) {
var year = moment(dateSpan.start).format('YYYY');
var month = moment(dateSpan.start).format('M') - 1;//js的date函数的月份是从0-11,所以这里减1
var day = moment(dateSpan.start).format('D');
//console.log(year,month,day);
if (isByDay) {
$.getJSON(url, dateSpan, function (datas) { option.series = datas;
option.plotOptions.series.pointStart = Date.UTC(year, month, day);
option.plotOptions.series.pointInterval = 24 * 36e5;
$('#incomeTrend').highcharts(option);
});
} else {
var start = drp.startDate.format('YYYY-MM');
var end = drp.endDate.format('YYYY-MM');
if (start == end) {
start = drp.startDate.subtract(5, "month").format('YYYY-MM');
}
year = moment(start).format('YYYY');
month = moment(start).format('M')-1;
dateSpan = { start: start, end: end }; $.getJSON(url, dateSpan, function (datas) {
option.series = datas;
option.plotOptions.series.pointStart = Date.UTC(year, month, 1);
option.plotOptions.series.pointInterval = 1;
option.plotOptions.series.pointIntervalUnit = "month";
$('#incomeTrend').highcharts(option);
});
} }

注意: 区域图和饼图公用同一个action,所以代码一起放到最后。

饼图

            <div class="row">
<div class="portlet light bordered col-md-8">
<div class="portlet-title">
<div class="caption">
<i class="fa fa-adjust font-red"></i>
<span class="caption-subject bold uppercase">收入比例</span>
</div>
</div>
<div class="portlet-body">
<div id="incomeRatio" style="width:90%;height: 500px"> </div>
</div>
</div>

var pieChartOption = {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: ''
},
credits: {
enabled: false
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f}%<br/> {y}元 ',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [
{
name: '占比',
colorByPoint: true,
data: []
}
]
}; function drawPieChart() {
var year = moment(dateSpan.start).format('YYYY');
var month = moment(dateSpan.start).format('M') - 1;//js的date函数的月份是从0-11,所以这里减1
var day = moment(dateSpan.start).format('D');
//console.log(year,month,day);
$.getJSON(url + "?chartType=pie", dateSpan, function (datas) {
pieChartOption.series[0].data = datas;
var sum=0;
for (var i = 0; i < datas.length; i++) {
sum += datas[i].y;
}
pieChartOption.title.text = "收入比例情况:(总收入"+sum+")元";
$('#incomeRatio').highcharts(pieChartOption);
});
} drawPieChart();

服务端Web层的C#代码如下:

        public async Task<ContentResult> GetJsonResult(string start, string end)
{
string dataJsonStr;
var defaultStart = DateTime.Parse(start);
var defaultEnd = DateTime.Parse(end);
var timeSpan = new DateTimeSpan { Start = defaultStart, End = defaultEnd };
var totalIncomeList = await _orderAppService.GetDateIncome(new GetDateIncomeDto
{
Start = defaultStart,
End = defaultEnd
});//总收入 var scanCodeChargeIncomeList = await _orderAppService.GetDateIncome(new GetDateIncomeDto
{
Start = defaultStart,
End = defaultEnd,
IsScanCodeChargingIncome = true
});//扫码充电收入
var lineSoldIncomeList = await _orderAppService.GetDateIncome(new GetDateIncomeDto
{
Start = defaultStart,
End = defaultEnd,
IsLineSoldIncome = true
});//售线收入 var castCoinsIncomeList = await _castCoinsAppService.GetDateCoinsIncome(new GetDateCoinsIncomeDto
{
Start = defaultStart,
End = defaultEnd
});//投币收入 var allKindsOfIncomeList = new List<DateIncomeListWithName>
{
new DateIncomeListWithName
{
DateIncomeDtos = castCoinsIncomeList,
Name = "投币"
},
new DateIncomeListWithName
{
DateIncomeDtos = lineSoldIncomeList,
Name = "售线"
},
new DateIncomeListWithName
{
DateIncomeDtos = scanCodeChargeIncomeList,
Name = "扫码充电"
}
};
if (Request.QueryString.Get("chartType") == "pie")//饼图
{
var pieDataList = new List<PieChartDataFormat>();
GetPieChartData(pieDataList, allKindsOfIncomeList);
dataJsonStr = JsonConvert.SerializeObject(pieDataList, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
}
else
{
var dataList = new List<ChartDataFormat>();
allKindsOfIncomeList.Add(new DateIncomeListWithName{DateIncomeDtos = totalIncomeList,Name = "总收入"});
GetData(dataList,allKindsOfIncomeList,timeSpan);
dataJsonStr = JsonConvert.SerializeObject(dataList, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
} return Content(dataJsonStr);
} private void GetData(List<ChartDataFormat> dataList, List<DateIncomeListWithName> incomeList, DateTimeSpan span)
{
var dateList = ConvertTimeSpanToList(span);
foreach (DateIncomeListWithName dateIncomeListWithName in incomeList)
{
var newList = CheckoutIncomeList(dateIncomeListWithName.DateIncomeDtos, dateList);
var list = newList.Select(dateIncomeDto => dateIncomeDto.Income).ToList(); dataList.Add(new ChartDataFormat
{
Name = dateIncomeListWithName.Name,
Data = list
}); }
} private void GetPieChartData(List<PieChartDataFormat> dataList, List<DateIncomeListWithName> incomeLists)
{
foreach (DateIncomeListWithName dateIncomeListWithName in incomeLists)
{
var total = dateIncomeListWithName.DateIncomeDtos.Sum(i => i.Income);
var item = new PieChartDataFormat
{
Name = dateIncomeListWithName.Name,
Y = total
};
dataList.Add(item);
} } List<DateIncomeDto> CheckoutIncomeList(List<DateIncomeDto> incomeList, List<DateTime> dateList)
{
var newIncomeList = new List<DateIncomeDto>();
newIncomeList = (from date in dateList
join incomeDto in incomeList on date.Date equals incomeDto.Date into result
from r in result.DefaultIfEmpty()
select new DateIncomeDto
{
Date = date.Date,
Income = r == null ? 0 : r.Income
}).ToList(); return newIncomeList;
} private List<DateTime> ConvertTimeSpanToList(DateTimeSpan span)
{
var list = new List<DateTime>();
for (DateTime i = span.Start; i <= span.End; i = i.AddDays(1))
{
list.Add(i);
}
return list;
}

上面这段代码,楼主自认为封装的还不错,很简洁(这已经成为楼主编程追求的目标),平均每个方法10行左右(除了第一个),仅供大家参考。

下面两个类定义了两种图表从Server端到Client端的数据格式 :####

    class ChartDataFormat
{
public string Name { get; set; }
public List<decimal> Data { get; set; }
} class PieChartDataFormat
{
public string Name { get; set; }
public decimal Y { get; set; }
}

应用服务层也贴一个方法的代码,仅供参考

        public async Task<List<DateIncomeDto>> GetDateIncome(GetDateIncomeDto input)
{
var query= _orderRepository.GetAll()
.Where(o => o.Status == OrderStatus.Freezen || o.Status == OrderStatus.Settled || o.Status == OrderStatus.HasInformedDevice)
.Where(o => o.OrderDate >= input.Start && o.OrderDate <= input.End)
.WhereIf(input.IsLineSoldIncome,o=>o.OrderType==OrderType.LineSold)
.WhereIf(input.IsScanCodeChargingIncome,o=>o.OrderType==OrderType.Charge)
.OrderBy(o => DbFunctions.TruncateTime(o.OrderDate))
.GroupBy(o => DbFunctions.TruncateTime(o.OrderDate))
.Select(group => new DateIncomeDto{Date=group.Key.Value,Income=group.Sum(item=>item.PayFee??0)}); var list = await query.ToListAsync();
return list;
}

这些就是整个图表的实现方案,切记仅供参考,不可生搬硬套,如因程序bug导致您公司的重大损失,本人一概不负责任。此话莫当真,纯属娱乐一下。

Javascript图表插件HighCharts用法案例的更多相关文章

  1. 图表插件Highcharts的动态化赋值,实现图表数据的动态化设置显示

    在很早之前就介绍过图表插件Highcharts的使用了,在2014年的随笔<基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts>,这里基本上都介绍 ...

  2. 图表插件——Highcharts插件的使用(一柱状图)

    1.下载Highcharts插件 官方下载网址:http://www.highcharts.com/download 2.引入需要的js文件 <script src="~/Script ...

  3. 纯JavaScrip图表插件——Highcharts

    简介 Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习.个人网站和非商业用途使用.目前H ...

  4. jQuery HighchartsTableHTML表格转Highcharts图表插件

    版权申明jQuery HighchartsTable 由 PMSIpilot 创建,中文使用文档由Highcharts中文网发布本文由Theo.红烧鸡翅膀.Mr.Zhang 翻译整理,版权归Highc ...

  5. 13个JavaScript图表(JS图表)图形绘制插件【转】

    现在网络上又有越来越多的免费的(JS 图表)JavaScript图表图形绘制插件.我之前给一家网站做过复杂的图形,我们用的是 highchart.在那段时间,没有很多可供选择的插件.但现在不同了,很容 ...

  6. 13个JavaScript图表(JS图表)图形绘制插件

    转自:http://blog.jobbole.com/13671/ 1. Flash 过去是最佳解决方案,但很多人多在从那迁移: 2. 现代浏览器及其更强大的计算能力,使其在转化绘制实时数据方面的能力 ...

  7. python 全栈开发,Day58(bootstrap组件,bootstrap JavaScript 插件,后台模板,图表插件,jQuery插件库,Animate.css,swiper,运行vue项目)

    一.bootstrap组件 无数可复用的组件,包括字体图标.下拉菜单.导航.警告框.弹出框等更多功能. 组件和插件的区别? 插件:一个功能,比如js文件 组件:html css js 组件包含插件 面 ...

  8. highcharts图表插件初探

    转载请注明出处:http://www.cnblogs.com/liubei/p/highchartsOption.html HighCharts简介 Highcharts 是一个用纯JavaScrip ...

  9. HighCharts 图表插件 自定义绑定 时间轴数据

    HighCharts 图表插件 自定义绑定 时间轴数据,解决时间轴自动显示数据与实际绑定数据时间不对应问题! 可能要用到的源码片段:http://code.662p.com/list/14_1.htm ...

随机推荐

  1. 金蝶K/3 Cloud 界面解析过程

    服务端 目前也就是iis服务器生成Json描述返回给不同的展现端最解析. 不同的展现端,可以有Silverlight.WPF.Html5.Winform 当然还有IOS和Android端做解析展现 对 ...

  2. Matlab(3) -- 编写M文件(函数)

    转自:http://blog.csdn.net/misskissc/article/details/8178089 matlab的命令编辑窗口(Command Window)界面主要是用来调用系统命令 ...

  3. 我开发的SNMP编译器和浏览器

    我开发的SNMP编译器和浏览器 什么是SNMP SNMP(Simple Network Management Protocol,简单网络管理协议)的前身是简单网关监控协议(SGMP),用来对通信线路进 ...

  4. LoopBackJS 之 文件上传下载——使用loopback-component-storage

    参考链接: http://loopback.io/doc/en/lb2/Storage-component.html#creating-a-storage-component-data-source ...

  5. OpenCV 学习之路(1)

    OpenCV的第一个代码: #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #i ...

  6. LInux配置jdk(mac和windows)

    我的linux使用的是VMware搭建的虚拟环境,用的是CENTOS6.5 一.准备工作: 1.确定系统安装的是成功的. 2.系统没有其他的问题 3.确定没有安装过其他版本的jdk,两个jdk会反冲 ...

  7. MySQL入门手册

    本文内容摘自MySQL5.6官方文档,主要选取了在实践过程中所用到的部分文字解释,力求只摘录重点,快速学会使用MySQL,本文所贴代码地方就是我亲自练习过的代码,凡本文没有练习过的代码都没有贴在此处, ...

  8. iOS游戏截图或广告图尺寸要求

    统一的标准:72 dpi,RGB,扁平化,非透明,高质量的JPEG或者PNG文件格式 ====================================================== 3. ...

  9. ios xcode 下 报出 ”xx“is missing from working copy 的问题

    在项目中提交过svn后,再在本机上删除不用的图片资源后,build后会有   ”xx“is missing from working copy  的警告.在网上找了些资料后,总结下. 直接在终端下用s ...

  10. [转]linux shell数据重定向(输入重定向与输出重定向)详细分析

      在了解重定向之前,我们先来看看linux 的文件描述符. linux文件描述符:可以理解为linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄,通过句柄就可以实现文件 ...