Custom drawing and drawing related


Q: How can I draw extra things over a Chart?


You should use the TChart1.Canvas object ( see TeeChart's Help documentation ). However, you should do all your drawing code at the TChart1_OnAfterDraw event for the drawings to be persistent during chart repaints and  printing.

For text output, in TeeChart v.3 you should use TChart1.TeeTextOut. In TeeChart 4 and 5 you can use the default TChart1.Canvas.TextOut method.


Q: Why doesn't my Canvas text show in the Print Preview window and why doesn't it print?


In debug mode of Visual Basic, Visual C++ etc. items drawn to the TChart.Canvas object will not appear in the Print Preview window and will not print. However, if you compile your project and make an executable of it you will find that these items appear and print as expected.


Q: I have a chart with stock prices. I want to label certain points A,B,C or some other textual description.


You could put this code in the OnAfterDraw event. It will draw a line between 2 points and put a message over the 2nd point with the value of the difference between the 2 points. (Example in Visual Basic)

With TChart1
  If .SeriesCount > 0 Then
  If .Series(0).Count > 10 Then
      'Set up drawing pen
      .Canvas.Pen.Color = vbBlue
      .Canvas.Pen.Width = 1
      .Canvas.Pen.Style = psDot
      .Canvas.Brush.Style = bsClear
      'Add a line. You don't need it in your example but it may be
        of interest
      'The key here is to take the point that you are interested 
        in on the Axis
      ' and convert it to screen co-ordinates 
      .Canvas.MoveTo .Axis.Bottom.CalcXPosValue(.Series(0).XValues.
                      Value(3)), _
                     .Axis.Left.CalcYPosValue(.Series(0).YValues.Value(3))
      .Canvas.LineTo .Axis.Bottom.CalcXPosValue(.Series(0).XValues.
                      Value(10)), _
                     .Axis.Left.CalcYPosValue(.Series(0).YValues.Value(10))
      'Here setting the Brush to solid to put a non transparent box 
       behind the text (optional)
      'You can put a box round the text (rectangle method) and/or 
       change colours, etc.
      .Canvas.Brush.Style = bsSolid
      'Again use point index to screen co-ordinate conversion
      .Canvas.TextOut .Axis.Bottom.CalcXPosValue(.Series(0).XValues.
                       Value(3)), _
                      .Axis.Left.CalcYPosValue(.Series(0).YValues.
                       Value(3)),
                       "Point value: " + Str$(.Series(0).YValues.Value(3))
      .Canvas.TextOut .Axis.Bottom.CalcXPosValue(.Series(0).XValues.
                       Value(10)), _
                      .Axis.Left.CalcYPosValue(.Series(0).YValues.
                       Value(10)), _
                      "Point value: " + Str$(.Series(0).YValues.Value(10))
      ' Position of line 2 of the message is decided by taking the 
        text height
      .Canvas.TextOut .Axis.Bottom.CalcXPosValue(.Series(0).XValues.
                       Value(10)), _
                      .Axis.Left.CalcYPosValue(.Series(0).YValues.
                       Value(10)) + _
                      .Canvas.TextHeight("Any letter"), "Change is: " + _
                      Str$(.Series(0).YValues.Value(10) - .Series(0). 
                           YValues.Value(3))
    End If
  End If
End With

With the TeeChart Pro v5 ActiveX Control the situation is a little different in the sense that rather than drawing directly to the Chart Canvas you can use Annotation Tools to contain your text. This gives you much more flexibility in terms of easily being able to format both the text and the text box (Example in Visual Basic).

Dim Anno1, Anno2, Anno3 As Integer

Private Sub Form_Load()
With TChart1
    .AddSeries scPoint
    .Series(0).FillSampleValues 15
    Anno1 = .Tools.Add(tcAnnotate)
    Anno2 = .Tools.Add(tcAnnotate)
    Anno3 = .Tools.Add(tcAnnotate)
    For i = 0 To .Tools.Count - 1
        With .Tools.Items(i).asAnnotation.Shape
            .Font.Name = "Broadway"
            .Font.Color = vbGreen
            .Gradient.Visible = True
            .Gradient.Direction = gdRightLeft
            .Gradient.EndColor = vbBlue
            .ShadowColor = vbYellow
        End With
    Next i
    .Environment.InternalRepaint
End With
End Sub

Private Sub TChart1_OnAfterDraw()
With TChart1
  If .SeriesCount > 0 Then
  If .Series(0).Count > 10 Then
      'Set up drawing pen
      .Canvas.Pen.Color = vbBlue
      .Canvas.Pen.Width = 1
      .Canvas.Pen.Style = psDot
      .Canvas.Brush.Style = bsClear
      'Add a line. You don't need it in your example but it may be of interest
      'The key here is to take the point that you are interested in on the Axis
      ' and convert it to screen co-ordinates
      .Canvas.MoveTo .Axis.Bottom.CalcXPosValue(.Series(0).XValues.Value(3)), _
                     .Axis.Left.CalcYPosValue(.Series(0).YValues.Value(3))
      .Canvas.LineTo .Axis.Bottom.CalcXPosValue(.Series(0).XValues.Value(10)), _
                     .Axis.Left.CalcYPosValue(.Series(0).YValues.Value(10))
      'In version 5 we can use Annotation Tools to draw the text
      'Again use point index to screen co-ordinate conversion
      With .Tools.Items(Anno1).asAnnotation
            .Shape.CustomPosition = True
            .Shape.Left = TChart1.Axis.Bottom.CalcXPosValue(TChart1.Series(0).XValues.Value(3))
            .Shape.Top = TChart1.Axis.Left.CalcYPosValue(TChart1.Series(0).YValues.Value(3))
            .Text = "Point value: " + Str$(TChart1.Series(0).YValues.Value(3))
      End With
      With .Tools.Items(Anno2).asAnnotation
            .Shape.CustomPosition = True
            .Shape.Left = TChart1.Axis.Bottom.CalcXPosValue(TChart1.Series(0).XValues.Value(10))
            .Shape.Top = TChart1.Axis.Left.CalcYPosValue(TChart1.Series(0).YValues.Value(10))
            .Text = "Point value: " + Str$(TChart1.Series(0).YValues.Value(10))
      End With
      With .Tools.Items(Anno3).asAnnotation
            .Shape.CustomPosition = True
            .Shape.Left = TChart1.Axis.Bottom.CalcXPosValue(TChart1.Series(0).XValues.Value(10))
            .Shape.Top = TChart1.Axis.Left.CalcYPosValue(TChart1.Series(0).YValues.Value(10)) + _
                      (TChart1.Canvas.TextHeight("Any letter") * 1.25)
            .Text = "Change is: " + Str$(TChart1.Series(0).YValues.Value(10) - TChart1.Series(0).YValues.Value(3))
      End With
    End If
  End If
End With
End Sub

Private Sub TChart1_OnUndoZoom()
TChart1.Environment.InternalRepaint
End Sub

Private Sub TChart1_OnZoom()
TChart1.Environment.InternalRepaint
End Sub

Q: Is there a way to show a tooltip showing the value when I put the mousepointer over a point in the Chart?


This code, for VB5, will show the value of a Point (of a Point Series) when the mouse is passed over it.

Global variable
Dim OnSeriesPoint As Boolean

Private Sub TChart1_OnMouseMove(ByVal Shift As TeeChart.EShiftState, 
ByVal X As Long, ByVal Y As Long)
'Check to see whether over Series and if Textout Mark already shown.
'This example shows X,Y value of Point
With TChart1
  If .Series(0).Clicked(X, Y) <> -1 And OnSeriesPoint = False Then
   .Canvas.Brush.Style = bsSolid
   .Canvas.Pen.Color = vbBlack
   .Canvas.TextOut X + 10, Y, _
     Str$(.Series(0).XValues.Value(.Series(0).XScreenToValue(X))) 
           & " " & _
     Str$(.Series(0).YValues.Value(.Series(0).XScreenToValue(X))) & " "
   OnSeriesPoint = True
  End If
'Repaint Chart to clear Textoutputted Mark
  If .Series(0).Clicked(X, Y) = -1 And OnSeriesPoint = True Then
    OnSeriesPoint = False
    .Repaint
  End If
End With
End Sub
Alternatively you could use the following code in VB6 to achieve the same end:
Private Sub TChart1_OnMouseMove(ByVal Shift As TeeChart.EShiftState, ByVal X As Long, ByVal Y As Long)
Dim tmp As Integer
    tmp = TChart1.Series(0).Clicked(X, Y)
    If tmp > -1 Then
        TChart1.ToolTipText = TChart1.Series(0).XValues.Value(tmp) & "  " & TChart1.Series(0).YValues.Value(tmp)
    Else
        TChart1.ToolTipText = ""
        TChart1.Repaint
    End If
End Sub