Hi everyone.
I'm in the making of a LineChart that only requires integer's as data-points.
The only think that won't work, it the grid in the background.
The grid is suppose to be draw so that it is aligned with the data-points on the chart,
but for some reason, it's a bit of on some points, both vertically and horizontally.
Let's say the a have a list of data-points where each point is number of minutes, then i would like the vertical lines to be at each point, and a horizontal line for each hour on the chart scale.
I'm almost got it working, but sometimes it's a bit off.
Here is the code i use to calculate the points for each data-point (because they are 1-dimensional), and draw them on the screen, also, the code that draw an Ellipse on each data-point:
And here is the code that's draw's the grid:
I really hope someone can help me solve this, it's really bugging me.
Here is a picture of how it behaves now:
![Posted Image]()
Thanks in advance
I'm in the making of a LineChart that only requires integer's as data-points.
The only think that won't work, it the grid in the background.
The grid is suppose to be draw so that it is aligned with the data-points on the chart,
but for some reason, it's a bit of on some points, both vertically and horizontally.
Let's say the a have a list of data-points where each point is number of minutes, then i would like the vertical lines to be at each point, and a horizontal line for each hour on the chart scale.
I'm almost got it working, but sometimes it's a bit off.
Here is the code i use to calculate the points for each data-point (because they are 1-dimensional), and draw them on the screen, also, the code that draw an Ellipse on each data-point:
Public Sub UpdateChart(ByVal line As List(Of Line), ByVal grid As Boolean)
Lines = line
DrawLineInfo(line)
Me.grid = grid
Dim w As Integer = Me.canvas.ActualWidth
Dim h As Integer = Me.canvas.ActualHeight
Dim Points As List(Of DataPoints)
Dim highest As Integer = 0
For Each l As Line In Lines
Points = l.DataPoints
For Each i As DataPoints In Points
If i.DataPoint > highest Then
highest = i.DataPoint
End If
Next
Next
Dim minOver As Integer = highest - (60 * TimeSpan.FromMinutes(highest).Hours)
If minOver > 0 Then
highest = 60 * (TimeSpan.FromMinutes(highest).Hours + 1)
End If
lblHigh.Content = highest
lblMiddle.Content = Math.Round(highest / 2)
Dim ValuePerPixelX = h / (highest / 2)
Dim ValuePerPixelY = w / line(0).DataPoints.Count
Me.canvas.Children.Clear()
If grid Then
DrawGrid(highest, True, Lines(0).DataPoints.Count)
End If
For Each l As Line In Lines
Odds = False
Points = l.DataPoints
Dim pointArray As New List(Of Point)
For i As Integer = 0 To Points.Count - 1
'' Beräkna kordinaterna för data-punkterna i diagramet
'' Resultatet är beroende av hur många data-punkter vi har, diagramets höjd samt bredd, och det det högsta värdet som ska visas
Dim p As New Point(Math.Round(ValuePerPixelY * i), Math.Round((Points(i).DataPoint * h) / highest))
pointArray.Add(p)
Next
For i As Integer = 0 To pointArray.Count - 1
''Skapa en ny linje
Dim myLine As New System.Windows.Shapes.Line()
myLine.Stroke = l.LineColor
''Om Y-värdet inte är = NaN, ang då start-positionen för linjen
''Om Y-värdet ÄR = NaN, ang Y som 0
If Not Double.IsNaN(pointArray(i).Y) Then
myLine.Y1 = pointArray(i).Y
myLine.X1 = pointArray(i).X
Else
myLine.Y1 = 0
myLine.X1 = pointArray(i).X
End If
'' Kontrollera att vi inte läser utanför vår array, eftersom vi här läser in en position före vår for-loop's step
'' Om vi gör det, så är vi på den sista data-punkten, så då sätter vi slutet av sträcket till samma position som början.
'' Detta för att få ett fint avslut på linje-diagramet
'' Men innan vi anger positionerna, så måste vi kontrollera så att Y-värdet inte är = NaN
'' Det hade resulterat i en krasch
If i < pointArray.Count - 1 Then
If Not Double.IsNaN(pointArray(i + 1).Y) Then
myLine.X2 = pointArray(i + 1).X
myLine.Y2 = pointArray(i + 1).Y
Else
myLine.X2 = pointArray(i + 1).X
myLine.Y2 = 0
End If
Else
If Not Double.IsNaN(pointArray(i).Y) Then
myLine.Y2 = pointArray(i).Y
myLine.X2 = pointArray(i).X
Else
myLine.Y2 = 0
myLine.X2 = 0
End If
End If
myLine.StrokeThickness = 2
Me.canvas.Children.Add(myLine)
If Not l.DataPoints(i).Info = Nothing Then
DrawDataPointMarker(myLine, l.DataPoints(i), l.xUnit, l.yUnit)
End If
Next
Me.canvas.InvalidateVisual()
Next
End Sub
Private Sub DrawDataPointMarker(ByVal line As System.Windows.Shapes.Line, ByVal data As DataPoints, ByVal xunit As String, ByVal yunit As String)
Dim myEllipse As New Ellipse()
myEllipse.Fill = line.Stroke
myEllipse.StrokeThickness = 2
myEllipse.Stroke = Brushes.Black
' Set the width and height of the Ellipse.
myEllipse.Width = 12
myEllipse.Height = 12
Controls.Canvas.SetTop(myEllipse, line.Y1 - 6)
Controls.Canvas.SetLeft(myEllipse, line.X1 - 6)
' myEllipse.ToolTip = data.Info
myEllipse.Tag = data.DataPoint & "@" & data.Info & "@" & xunit & "@" & yunit
AddHandler myEllipse.MouseEnter, AddressOf Ellipse_MouseEnter
AddHandler myEllipse.MouseLeave, AddressOf Ellipse_MouseLeave
Me.canvas.Children.Add(myEllipse)
Dim l As New Label
If data.Info.Substring(0, 4) = "den " Then
l.Content = data.Info.Substring(4)
Else
l.Content = data.Info
End If
l.FontSize = 10
Dim scale As New ScaleTransform()
scale.ScaleY() = -1
l.RenderTransform = scale
If Odds Then
Controls.Canvas.SetBottom(l, Me.canvas.ActualHeight - 15)
Odds = False
Else
Controls.Canvas.SetBottom(l, Me.canvas.ActualHeight - 25)
Odds = True
End If
If data.Info.Substring(0, 4) = "den " Then
Controls.Canvas.SetLeft(l, line.X1 - (MeasureString(data.Info.Substring(4), l).Width / 2) - 4)
Else
Controls.Canvas.SetLeft(l, line.X1 - (MeasureString(data.Info, l).Width / 2) - 4)
End If
Me.canvas.Children.Add(l)
End Sub
And here is the code that's draw's the grid:
Private Sub DrawGrid(ByVal max As Integer, Optional ByVal gridS As Boolean = False, Optional ByVal datapoints As Integer = 0)
Dim w As Double = Me.canvas.ActualWidth
Dim h As Double = Me.canvas.ActualHeight
Dim gridSizeH = 0
Dim gridSizeW = 0
If Not gridS Then
If max < 50 Then
gridSizeH = 30
gridSizeW = 30
ElseIf max > 49 And max < 100 Then
gridSizeH = 28
gridSizeW = 28
ElseIf max > 99 And max < 150 Then
gridSizeH = 26
gridSizeW = 26
ElseIf max > 149 And max < 200 Then
gridSizeH = 24
gridSizeW = 24
ElseIf max > 199 And max < 250 Then
gridSizeH = 22
gridSizeW = 22
ElseIf max > 249 And max < 300 Then
gridSizeH = 20
gridSizeW = 20
ElseIf max > 299 And max < 350 Then
gridSizeH = 18
gridSizeW = 18
ElseIf max > 349 And max < 400 Then
gridSizeH = 16
gridSizeW = 16
ElseIf max > 399 And max < 450 Then
gridSizeH = 14
gridSizeW = 14
ElseIf max > 449 And max < 400 Then
gridSizeH = 12
gridSizeW = 12
ElseIf max > 399 Then
gridSizeH = 10
gridSizeW = 10
End If
Else
If max > 60 Then
gridSizeH = Math.Round(h / TimeSpan.FromMinutes(max).Hours)
gridSizeW = w / datapoints
Else
gridSizeH = 30
gridSizeW = 30
End If
End If
''Draw Horizontal Lines
For i As Integer = 0 To (w / gridSizeW)
Dim myLine As New System.Windows.Shapes.Line()
myLine.Stroke = Brushes.DimGray
myLine.StrokeThickness = 1
myLine.X1 = (gridSizeW) * i
myLine.Y1 = 0
myLine.X2 = (gridSizeW) * i
myLine.Y2 = h
Me.canvas.Children.Add(myLine)
If i = Math.Round(w / gridSizeW) Then
Exit For
End If
Next
''Draw Vetrial Lines
For i As Integer = 0 To (h / gridSizeH)
Dim myLine As New System.Windows.Shapes.Line()
If i = Math.Round((h / gridSizeH) / 2) Then
myLine.Stroke = Brushes.Black
Else
myLine.Stroke = Brushes.DimGray
End If
myLine.StrokeThickness = 1
myLine.X1 = 0
myLine.Y1 = (gridSizeH) * i
myLine.X2 = w
myLine.Y2 = (gridSizeH) * i
Me.canvas.Children.Add(myLine)
If i = Math.Round(h / gridSizeH) Then
Exit For
End If
Next
End Sub
I really hope someone can help me solve this, it's really bugging me.
Here is a picture of how it behaves now:

Thanks in advance