2

我们正在尝试从基于 Silverlight 的图表控件转向更多无插件控件。我们喜欢 HighCharts,现在正在测试将其实现到我们现有的代码库中。我们发现 DotNet.HighCharts 可能是快速创建图表而无需解析所有 javascript 的竞争者。

我的问题是,当图表包含在数据中时,您如何传递要在图表中使用的数据DataTable跟随这里的答案,我已经看到 Linq 可能是要走的路。但是,我很难让代码真正构建。DotNet.HighCharts 的文档没有显示任何提取非静态数据的示例,所以那里没有运气。到目前为止,这是我的代码片段:

    Dim da3 As New SqlDataAdapter(sql3, conn3)
    da3.Fill(dt3)
    da3.Dispose()
    conn3.Close()

    Dim chart3 As Highcharts = New Highcharts("chart").InitChart(New Chart() With { _
     .PlotShadow = False _
    }).SetTitle(New Title() With { _
     .Text = "Browser market shares at a specific website, 2010" _
    }).SetTooltip(New Tooltip() With { _
     .Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }" _
    }).SetPlotOptions(New PlotOptions() With { _
     .Column = New PlotOptionsColumn With { _
      .AllowPointSelect = True, _
      .Cursor = Cursors.Pointer, _
      .DataLabels = New PlotOptionsColumnDataLabels() With { _
       .Color = ColorTranslator.FromHtml("#000000"), _
       .Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }" _
      } _
     } _
    }).SetSeries(New Series() With { _
     .Type = ChartTypes.Column, _
     .Name = "Browser share", _
     .Data = New Helpers.Data(dt3.Select(Function(x) New Options.Point() With {.X = x.periodyear, .Y = x.rate}).ToArray()) _
    })
    ltrChart3.Text = chart3.ToHtmlString()

我正在导入以下内容:

Imports DotNet.Highcharts
Imports DotNet.Highcharts.Options
Imports System.Data
Imports System.Data.SqlClient
Imports DotNet.Highcharts.Enums
Imports System.Drawing
Imports System.Collections.Generic
Imports System.Linq

我得到的错误.Data = New Helpers.Data(dt3.Select(Function(x) New Options.Point() With {.X = x.periodyear, .Y = x.rate}).ToArray()) _在线。我得到Lambda expression cannot be converted to 'String' because 'String' is not a delegate type了我的错误Function....rate}

编辑: 第一次尝试修改现有代码

    Dim chart1 As Highcharts = New DotNet.Highcharts.Highcharts("test")

    Dim series As Series = New Series()
    series.Name = "CO Rates"
    For i As Integer = 0 To dt.Rows.Count - 1
        series.Data = New Helpers.Data(New Object() {dt.Rows(i)("periodyear"), dt.Rows(i)("rate")})
    Next
    chart1.SetSeries(series).InitChart(New Chart() With { _
                                       .Type = ChartTypes.Column})

这只会产生 2 列,第一列位于 x 位置 0,其值为 2011,另一列位于 x 位置 1,其值为 8.3。这非常奇怪,因为在我看来它正在获取 dataTable 中的最后一个点,然后将其 {x, y} 值 ({2011, 8.3}) 变成 2 个不同的点,其中 x 和 y 值都是 y {0, x} 和 {1, y} 之类的值。我需要得到:

  • 从数据表中获取的具有 {periodyear, rate} 的单个系列。
  • 将来我想为每个位置创建一个序列,其 {periodyear, rate} 取自数据表。

编辑 2: 好的,我让它将结果转换为数据字典,我让图表显示所有点。现在唯一的问题是将 转换dt.Rows(i)("periodyear")为 DateTime 值。这是到目前为止的代码(在 PaseExact 方法上失败):

Dim series As Series = New Series()
        series.Name = "CO Rates"

        Dim xDate As DateTime
        Dim data As New Dictionary(Of DateTime, Decimal)
        For i As Integer = 0 To dt.Rows.Count - 1
            xDate = DateTime.ParseExact(dt.Rows(i)("periodyear").ToString, "YYYY", Globalization.CultureInfo.InvariantCulture)
            data.Add(xDate, dt.Rows(i)("rate"))
        Next

        Dim chartData As Object(,) = New Object(data.Count - 1, 1) {}
        Dim x As Integer = 0
        For Each pair As KeyValuePair(Of DateTime, Decimal) In data
            chartData.SetValue(pair.Key, x, 0)
            chartData.SetValue(pair.Value, x, 1)
            x += 1
        Next

        Dim chart1 As Highcharts = New Highcharts("chart1").InitChart(New Chart() With { _
         .Type = ChartTypes.Column _
        }).SetTitle(New Title() With { _
         .Text = "Chart 1" _
        }).SetXAxis(New XAxis() With { _
         .Type = AxisTypes.Linear _
        }).SetSeries(New Series() With { _
         .Data = New Helpers.Data(chartData) _
        })

如果我将其更改为字符串值(例如 1980),然后将 x 轴的 AxisTypes 更改为线性,我会显示数据。它只是以某种方式关闭 - 1980 看起来像 1,980。婴儿步...

编辑 N: 这是最终的工作解决方案。这似乎可以使用一些清理。例如,我不确定是否需要创建一个字典来放入我的 X/Y 值,然后遍历字典以将数据添加到我的 chartData 对象。这似乎是双重工作。

    Dim stfipsList = (From r In dt.AsEnumerable() Select r("stfips")).Distinct().ToList()
    Dim SeriesList As New List(Of Series)(stfipsList.Count)
    Dim seriesItem(stfipsList.Count) As Series
    Dim xDate As DateTime
    Dim fakeDate As String
    Dim sX As Integer

    sX = 1
    For Each state In stfipsList
        Dim data As New Dictionary(Of DateTime, Decimal)
        Dim stateVal As String = state.ToString
        Dim recCount As Integer = dt.Rows.Count - 1

        For i As Integer = 0 To recCount
            If dt.Rows(i)("stfips").ToString = stateVal Then
                fakeDate = "1/1/" + dt.Rows(i)("periodyear").ToString
                xDate = DateTime.Parse(fakeDate)
                data.Add(xDate.Date, dt.Rows(i)("unemprate"))
            End If
        Next
        Dim chartData As Object(,) = New Object(data.Count - 1, 1) {}
        Dim x As Integer = 0
        For Each pair As KeyValuePair(Of DateTime, Decimal) In data
            chartData.SetValue(pair.Key, x, 0)
            chartData.SetValue(pair.Value, x, 1)
            x += 1
        Next
        seriesItem(sX) = New Series With {
                    .Name = state.ToString, _
                    .Data = New Helpers.Data(chartData)
        }

        SeriesList.Add(seriesItem(sX))

        sX = sX + 1
    Next

    Dim chart1 As Highcharts = New Highcharts("chart1").InitChart(New Chart() With { _
     .Type = ChartTypes.Line _
    }).SetTitle(New Title() With { _
     .Text = "Annual Unemployment Rate" _
    }).SetTooltip(New Tooltip() With { _
     .Formatter = "function() { return '<b>'+ this.series.name + ': ' + Highcharts.dateFormat('%Y', this.x) +'</b>: '+ this.y +' %'; }" _
    }).SetXAxis(New XAxis() With { _
     .Type = AxisTypes.Datetime _
     }).SetYAxis(New YAxis() With { _
       .Min = 0, _
       .Title = New YAxisTitle() With { _
        .Text = "Unemployment Rate", _
        .Align = AxisTitleAligns.High _
      } _
    }).SetSeries(SeriesList.[Select](Function(s) New Series() With { _
                 .Name = s.Name, _
                 .Data = s.Data _
                }).ToArray())

    ltrChart1.Text = chart1.ToHtmlString()
4

2 回答 2

3

请参阅下面的我的控制器 ActionResults 之一,它执行您所要求的。它是用 C# 编写的,但可以很容易地修改为 VB。有比您要求的信息更多的信息,但它可能会在 Visual Studio 中使用 Highcharts 时提供其他问题的可见性。

我正在做的是创建一个系列列表,然后将列表传递给 highcharts。这样做的好处是您不必单独创建每个系列。

public ActionResult CombinerBarToday(DateTime? utcStartingDate = null,
                                             DateTime? utcEndingDate = null)
        {
            //TEMPORARILY USED TO FORCE A DATE
            //utcStartingDate = new DateTime(2012, 1, 9, 0, 0, 1);
            //utcEndingDate = new DateTime(2012, 1, 9, 23, 59, 59);

            //GET THE GENERATED POWER READINGS FOR THE SPECIFIED DATETIME
            var firstQ = from s in db.PowerCombinerHistorys
                         join u in db.PowerCombiners on s.combiner_id equals u.id
                         where s.recordTime >= utcStartingDate
                         where s.recordTime <= utcEndingDate
                         select new
                         {
                             Combiner = u.name,
                             Current = s.current,
                             RecordTime = s.recordTime,
                             Voltage = s.voltage,
                             Power = s.current * s.voltage
                         };

            //APPLY THE GROUPING
            var groups = firstQ.ToList().GroupBy(q => new
            {
                q.Combiner,
                Date = q.RecordTime.Date,
                Hour = q.RecordTime.Hour
            });

            List<CombinerKwh> stringGroupedKwhlist = new List<CombinerKwh>();

            //CALCULATE THE AVERAGE POWER GENERATED PER HOUR AND ADD TO LIST
            foreach (var group in groups)
            {
                stringGroupedKwhlist.Add(new CombinerKwh(
                                         group.Key.Combiner,
                                         new DateTime(group.Key.Date.Year, group.Key.Date.Month, group.Key.Date.Day, group.Key.Hour, 0, 0),
                                         group.Average(g => g.Power) / 1000d
                                         ));
            }

            //GET A LIST OF THE COMBINERS CONTAINS IN THE QUERY
            var secondQ = (from s in firstQ 
                           orderby s.Combiner 
                           select new
                                {
                                    Combiner = s.Combiner
                                }
                           ).Distinct();

            /* THIS LIST OF SERIES WILL BE USED TO DYNAMICALLY ADD AS MANY SERIES 
             * TO THE HIGHCHARTS AS NEEDEDWITHOUT HAVING TO CREATE EACH SERIES INDIVIUALY */
            List<Series> allSeries = new List<Series>();

            TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

            //LOOP THROUGH EACH COMBINER AND CREATE SERIES
            foreach (var distinctCombiner in secondQ)
            {
                var combinerDetail = from h in stringGroupedKwhlist
                                     where h.CombinerID == distinctCombiner.Combiner
                                     orderby TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone)
                                     select new
                                            {
                                                CombinerID = h.CombinerID,
                                                //CONVERT FROM UTC TIME TO THE LOCAL TIME OF THE SITE
                                                Interval = TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone),
                                                KWH = h.KWH
                                            };

                //REPRESENTS 24 PLOTS FOR EACH HOUR IN DAY
                object[] myData = new object[24];

                foreach (var detailCombiner in combinerDetail)
                {
                    if (detailCombiner.KWH != 0)
                    {
                        myData[detailCombiner.Interval.Hour] = detailCombiner.KWH;
                    }
                }

                allSeries.Add(new Series
                                    {
                                        Name = distinctCombiner.Combiner,
                                        Data = new Data(myData)
                                    });
            }

            Highcharts chart = new Highcharts("chart")
            .InitChart(new Chart { DefaultSeriesType = ChartTypes.Spline })
            .SetTitle(new Title { Text = "Combiner History" })
            .SetXAxis(new XAxis
            {
                Categories = new[] { "0:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM", "6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM", "6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM" },
                Labels = new XAxisLabels
                                       {
                                           Rotation = -45,
                                           Align = HorizontalAligns.Right,
                                           Style = "font: 'normal 10px Verdana, sans-serif'"
                                       },
                Title = new XAxisTitle { Text = "Time(Hour)" },
                //Type = AxisTypes.Linear
            })
            .SetYAxis(new YAxis
            {
                //Min = 0,
                Title = new YAxisTitle { Text = "Kwh" }
            })

            .SetSeries(allSeries.Select(s => new Series { Name = s.Name, Data = s.Data }).ToArray());

            return PartialView(chart);
        }
于 2012-04-11T18:12:53.227 回答
2

在这里您可以找到如何从 DataTable 创建系列的示例:http: //dotnethighcharts.codeplex.com/discussions/287106

同样从示例项目中,您可以找到如何“从字典绑定数据”和“从对象列表绑定数据”

于 2012-04-05T21:56:56.103 回答