4 Replies - 481 Views - Last Post: 16 February 2013 - 03:15 AM Rate Topic: -----

#1 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Making Linechart, Grid not aligned with points

Posted 14 February 2013 - 04:34 AM

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:
   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:
Posted Image

Thanks in advance

Is This A Good Question/Topic? 0
  • +

Replies To: Making Linechart, Grid not aligned with points

#2 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1067
  • View blog
  • Posts: 4,178
  • Joined: 02-July 08

Re: Making Linechart, Grid not aligned with points

Posted 14 February 2013 - 02:19 PM

It is probably a very subtle value that is moving the lines. Debugging the code and write down the x and y coordinates and see how they march out. As your seeing it's probably off by 1, but increments that each iteration. It maybe a thickness that is causing the problem.

It might be helpful to let people looking to know it's WPF.
Was This Post Helpful? 0
  • +
  • -

#3 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Re: Making Linechart, Grid not aligned with points

Posted 14 February 2013 - 10:57 PM

Hello old friend.
I've tried subtracting the the thickness * i
But it didn't help, also try a lot of other thing.
But i just can't found it..

Yes, it is WPF. Sorry about that.
Was This Post Helpful? 0
  • +
  • -

#4 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1067
  • View blog
  • Posts: 4,178
  • Joined: 02-July 08

Re: Making Linechart, Grid not aligned with points

Posted 15 February 2013 - 12:43 PM

Ok, how about writing down the values as they iterate, Debug.Writeline if it makes it easier.
Was This Post Helpful? 0
  • +
  • -

#5 EndLessMind  Icon User is offline

  • These are the droids you're looking for
  • member icon

Reputation: 194
  • View blog
  • Posts: 1,099
  • Joined: 13-March 09

Re: Making Linechart, Grid not aligned with points

Posted 16 February 2013 - 03:15 AM

Okey, so i found the error.
The calculations where correct, but i did 2 mistakes
1) i used Math.Round(int) of some dumb reason i can't remember
2) i had defined the gridsize-variables like Dim gridSizeH = 0, and the automatically turn them into integer. So even though i removed Math.Round(int), i was still getting the rounded values.

Solution:
I changed
Dim gridSizeH = 0
Dim gridSizeW = 0


to
Dim gridSizeH As Double = 0
Dim gridSizeW As Double = 0


and removed all Math.Round(int) from the code.


And _HAWK_, i have been using Debug.WriteLine/Console.WriteLine for some time, but because the values some times differed with 1 px and sometimes with 4px i could not figure it out with just that. But thanks anyway.

Cheers
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1