asp.net - 如何在 DevExpress BootstrapChart 的不同窗格中分隔线系列组?
问题描述
现在,我正在使用DevExpress BootstrapChart (v17.2.13.0)开发 Web 应用程序,并且已将控件与对象数据源绑定。以下是用于在图表中显示的示例数据:
这是我的目标:
- 该图将在不同的窗格中显示“ademand_im”和“rdemand_im”的值(我将它们命名为“A”和“B”窗格)
- 每个窗格都将“data_time”(日期和时间)作为 X 轴,将值(“ademand_im”或“rdemand_im”)作为 Y 轴
- 此外,每个窗格中的值将按“hardware_id”分组,因此,在这种情况下,每个窗格中应该有 2 行系列“83245551”和“88310991”(请注意, “hardware_id”可以不时变化)。
所以图表应该是这样的:
但是,我此时只能实现的是,线系列要么显示在两个窗格中但未分组,要么在图表中不显示任何内容。
这是我的代码:
<dx:BootstrapChart ID="chart" ClientInstanceName="chart" runat="server"
DataSourceID="ods_ChartData" Height="640px" TitleText="Chart Data" CrosshairEnabled="true" Panes="A,B">
<ClientSideEvents Init="OnChartInit" />
<SettingsToolTip Shared="true" Enabled="true" OnClientCustomizeTooltip="ChartToolTip" />
<ArgumentAxis ArgumentType="System.DateTime" GridVisible="True" MinorGridVisible="True"
TickVisible="True" MinorTickVisible="True" TickInterval="1" MinorTickCount="3" TitleText="Date">
<Label DisplayMode="Rotate" RotationAngle="-0" Format-Formatter="FormatDate" />
</ArgumentAxis>
<ValueAxisCollection>
<dx:BootstrapChartValueAxis Pane="A" TitleText="ademand_im" />
<dx:BootstrapChartValueAxis Pane="B" TitleText="rdemand_im" />
</ValueAxisCollection>
<SettingsCommonSeries Type="Line" ArgumentField="data_time" Point-Size="0" />
<SettingsSeriesTemplate NameField="hardware_id" />
<SeriesCollection>
<dx:BootstrapChartLineSeries Pane="A" ValueField="ademand_im" />
<dx:BootstrapChartLineSeries Pane="B" ValueField="rdemand_im" />
</SeriesCollection>
</dx:BootstrapChart>
在此代码中,如果我删除“SettingsSeriesTemplate”行,数据将显示在两个窗格中,但在每个窗格中仅显示为单行。但是,如果我保留这条线,图表将不会显示任何内容。
解决方案
在我尝试了解此控件的工作原理后,我发现的唯一解决方案是我必须将“hardware_id”列转换为“ademand_im”和“rdemand_im”值,这可能不是理想的值。
因此,应该将表转换为具有“ademand_im_83245551”、“ademand_im_88310991”、“rdemand_im_83245551”和“rdemand_im_88310991”列,而不是“hardware_id”、“ademand_im”和“rdemand_im”列。
这是转换后的表格的样子:
这是我用来转换表格的函数代码(VB.NET):
<Extension()>
Public Function PivotDataTableColumnGroup(srcData As DataTable, rowGroupField As String, pivotColumnField As String, valueGroupFields As IEnumerable(Of String),
Optional ValueGroupColumnName As Func(Of String, String, String) = Nothing,
Optional otherFields As IEnumerable(Of String) = Nothing,
Optional GetOtherFieldValue As Func(Of DataTable, String, Object, Object) = Nothing
) As DataTable
Dim groupValueList As List(Of Object) = srcData.GetDistinctValuesByColumnName(rowGroupField)
Dim pivotValueList As List(Of Object) = srcData.GetDistinctValuesByColumnName(pivotColumnField)
Dim hasOtherFieldColumn As Boolean = Not (otherFields Is Nothing Or GetOtherFieldValue Is Nothing)
Dim dt As New DataTable
With dt
.Columns.Add(rowGroupField, srcData.Columns(rowGroupField).DataType)
For i As Integer = 0 To valueGroupFields.Count - 1
For j As Integer = 0 To pivotValueList.Count - 1
Dim columnName As String = GetColumnNameFromGroupFieldAndPivotValues(valueGroupFields(i), pivotValueList(j), ValueGroupColumnName)
dt.Columns.Add(columnName, srcData.Columns(valueGroupFields(i)).DataType)
Next
Next
If hasOtherFieldColumn Then
For i As Integer = 0 To otherFields.Count - 1
.Columns.Add(otherFields(i), srcData.Columns(otherFields(i)).DataType)
Next
End If
For i As Integer = 0 To groupValueList.Count - 1
Dim currentGroupValue As Object = groupValueList(i)
Dim dr As DataRow = dt.NewRow()
dr(rowGroupField) = currentGroupValue
If hasOtherFieldColumn Then
For j As Integer = 0 To otherFields.Count - 1
dr(otherFields(j)) = DBNullIfNothing(GetOtherFieldValue(srcData, otherFields(j), currentGroupValue))
Next
End If
For j As Integer = 0 To valueGroupFields.Count - 1
Dim currentField As String = valueGroupFields(j)
For k As Integer = 0 To pivotValueList.Count - 1
Dim currentPivotValue As Object = pivotValueList(k)
Dim columnName As String = GetColumnNameFromGroupFieldAndPivotValues(valueGroupFields(j), pivotValueList(k), ValueGroupColumnName)
Dim value As Object = (From row In srcData.AsEnumerable
Where row(rowGroupField) = currentGroupValue _
AndAlso row(pivotColumnField) = currentPivotValue
Select row(currentField)
).FirstOrDefault
dr(columnName) = DBNullIfNothing(value)
Next
Next
dt.Rows.Add(dr)
Next
End With
Return dt
End Function
<Extension()>
Public Function GetDistinctValuesByColumnName(dt As DataTable, columnName As String) As List(Of Object)
Dim valueList As List(Of Object) = (From row As DataRow In dt.AsEnumerable
Where Not IsDBNull(row(columnName))
Order By row(columnName)
Select row(columnName) Distinct
).ToList
Return valueList
End Function
Private Function GetColumnNameFromGroupFieldAndPivotValues(groupField As String, pivotValue As Object, Optional ValueGroupColumnName As Func(Of String, String, String) = Nothing) As String
Dim columnName As String = groupField & "_" & pivotValue.ToString()
If ValueGroupColumnName IsNot Nothing Then
columnName = ValueGroupColumnName(groupField, pivotValue)
End If
Return columnName
End Function
Public Function DBNullIfNothing(o As Object) As Object
If o Is Nothing Then Return DBNull.Value
Return o
End Function
这就是我使用该函数转换表格的方式:
Dim chartData As DataTable = result.PivotDataTableColumnGroup("data_time", "hardware_id", {"ademand_im", "rdemand_im"}, Nothing, Nothing, Nothing)
ResultChartData = chartData 'Stored in ASPxHiddenField in JSON form
之后,我必须在后面的代码中手动添加图表系列,而不是在 aspx 文件中设置图表系列属性:
Private Sub chart_LoadProfile_DataBound(sender As Object, e As EventArgs) Handles chart_LoadProfile.DataBound
Using ResultChartData
Dim seriesList As List(Of String) = (From col As DataColumn In ResultChartData.Columns
Where col.ColumnName <> "data_time"
Order By col.ColumnName
Select col.ColumnName
).ToList
Dim hardWardCount As Integer = (From s In seriesList Where s.Contains("ademand_im_")).Count
Dim showInLegend As Boolean = hardWardCount > 1
With chart_LoadProfile.SeriesCollection
.Clear()
For i As Integer = 0 To seriesList.Count - 1
Dim fieldName As String = seriesList(i)
Dim hardwareId As String = seriesList(i).Split("_")(2)
Dim series As New BootstrapChartLineSeries
With series
.ArgumentField = "data_time"
.ValueField = fieldName
.Point.Size = 0
.ShowInLegend = showInLegend
If fieldName.Contains("ademand_im_") Then
.Pane = "A"
.Name = "kW - " & hardwareId
Else
.Pane = "B"
.Name = "kVar - " & hardwareId
End If
End With
.Add(series)
Next
End With
End Using
End Sub
推荐阅读
- ios - CMPedometer queryPedometerData() 返回错误的步数
- java - java servlet PrintWriter#flush 停止抛出异常
- visual-studio - Visual Studio 2017 - 测试运行器 - 调试选定的测试 - NUnit - 不工作
- ruby-on-rails - 使用多态方式具有多种地址类型和与模型的关联?
- mongodb - 使用 Spring-Data 进行分页:PageRequest 泄漏到 REST 控制器中
- excel - 从子形状切换到组以选择
- python - 从ListView重定向到Django 2.1中的另一个ListView
- python - doit 在 dodo.py 中运行每个函数。我可以改变它吗?
- mysql - MySQL - 如何选择与最近日期相关的值+所有值的最大值/最小值
- spring - 使用 AMQP 1.0 使用 Qpid 从客户端动态创建队列和主题