zoukankan      html  css  js  c++  java
  • Javascript图表插件HighCharts用法案例

    最近还在忙着基于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="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="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导致您公司的重大损失,本人一概不负责任。此话莫当真,纯属娱乐一下。

  • 相关阅读:
    tech 浅谈 Yield
    Python strip lstrip rstrip使用方法
    Python strip lstrip rstrip使用方
    Python 的学习脚印(1)
    python中列表的赋值
    python的re模块的sub方法
    Python的异常处理机制
    [python] shutil模块
    【ActiveMq】启动amq时遇到java.net.URISyntaxException: Illegal character in hostname at index处理方法
    【sql总结】
  • 原文地址:https://www.cnblogs.com/farb/p/JavascriptHighchartsUseCase.html
Copyright © 2011-2022 走看看