ChartDirector 6.0 (ASP/COM/VB Edition)

Zooming and Scrolling Demonstration (2) (Windows)




This sample program demonstrates a general zoomable and scrollable chart. The followings are the key elements of this sample program:

The main source code listing of this sample program is included at the end of this section. The code consists of the following main parts:

Source Code Listing

[Windows Version (in Visual Basic)] vbdemo\frmZoomScrollDemo2.frm
Option Explicit

Private cd As New ChartDirector.API

' XY data points for the chart
Private dataX0()
Private dataY0()
Private dataX1()
Private dataY1()
Private dataX2()
Private dataY2()
    
' The full x-axis and y-axis scales at no zooming.
Private minX As Double
Private maxX As Double
Private minY As Double
Private maxY As Double

' Internal variables to keep track of which navigation button is pushed
Private activeNavigateButton As Long

' The index of the navigation buttons in the NavigatePB array
Private Const upLeftPB = 0
Private Const upPB = 1
Private Const upRightPB = 2
Private Const LeftPB = 3
Private Const CenterPB = 4
Private Const RightPB = 5
Private Const downLeftPB = 6
Private Const downPB = 7
Private Const downRightPB = 8

' Internal variables to keep track of dragging of the navigation window
Private isDraggingNavigatePad As Boolean
Private mouseDownXCoor As Double
Private mouseDownYCoor As Double

'
' Initialize the form
'
Private Sub Form_Load()

    ' Initially, set mouse usage to pointer mode
    Call PointerPB_Click
        
    ' Load the data
    Call loadData
    
    ' Can draw the chart now
    Call ChartViewer1.UpdateViewPort(True, True)

End Sub

'
' Load the data
'
Private Sub loadData()
    '
    ' For simplicity, in this demo, we just use hard coded data. In a real application,
    ' the data probably read from a dynamic source such as a database. (See the
    ' ChartDirector documentation on "Using Data Sources with ChartDirector" if you need
    ' some sample code on how to read data from database to array variables.)
    '
    dataX0 = Array(10, 15, 6, -12, 14, -8, 13, -3, 16, 12, 10.5, -7, 3, -10, -5, 2, 5)
    dataY0 = Array(130, 150, 80, 110, -110, -105, -130, -15, -170, 125, 125, 60, 25, 150, 150, 15, _
        120)
    dataX1 = Array(6, 7, -4, 3.5, 7, 8, -9, -10, -12, 11, 8, -3, -2, 8, 4, -15, 15)
    dataY1 = Array(65, -40, -40, 45, -70, -80, 80, 10, -100, 105, 60, 50, 20, 170, -25, 50, 75)
    dataX2 = Array(-10, -12, 11, 8, 6, 12, -4, 3.5, 7, 8, -9, 3, -13, 16, -7.5, -10, -15)
    dataY2 = Array(65, -80, -40, 45, -70, -80, 80, 90, -100, 105, 60, -75, -150, -40, 120, -50, _
        -30)
End Sub

'
' User clicks on the Pointer pushbutton
'
Private Sub PointerPB_Click()
    ChartViewer1.MouseUsage = cvScrollOnDrag
End Sub

'
' User clicks on the Zoom In pushbutton
'
Private Sub ZoomInPB_Click()
    ChartViewer1.MouseUsage = cvZoomIn
End Sub

'
' User clicks on the Zoom Out pushbutton
'
Private Sub ZoomOutPB_Click()
    ChartViewer1.MouseUsage = cvZoomOut
End Sub


'
' User presses on one of the navigation buttons
'
Private Sub NavigatePB_MouseDown(Index As Integer, Button As Integer, Shift As Integer, _
    X As Single, Y As Single)
    If Index = CenterPB Then
        ' Center button - center the view port at the origin (0, 0)
        Call scrollChartTo(ChartViewer1, 0.5 - ChartViewer1.ViewportWidth / 2, _
            0.5 - ChartViewer1.ViewportHeight / 2)
    Else
        ' Enable the timer to shift the view port once per 100ms until button is released
        activeNavigateButton = Index
        ButtonTimer.Enabled = True
    End If
End Sub

'
' User releases the navigation button
'
Private Sub NavigatePB_MouseUp(Index As Integer, Button As Integer, Shift As Integer, _
    X As Single, Y As Single)
    ' Stop the button timer
    activeNavigateButton = -1
    ButtonTimer.Enabled = False
End Sub

'
' Navigation button timer - fires once per 100ms if navigation button is pressed
'
Private Sub ButtonTimer_Timer()
    If activeNavigateButton <> -1 Then
        ' Get current view port position
        Dim vpLeft As Double
        Dim vpTop As Double
        vpLeft = ChartViewer1.ViewportLeft
        vpTop = ChartViewer1.ViewportTop

        ' Each tick scroll the chart by 5% in the button direction
        If activeNavigateButton = LeftPB Or activeNavigateButton = upLeftPB Or _
            activeNavigateButton = downLeftPB Then
            vpLeft = vpLeft - ChartViewer1.ViewportWidth * 0.05
        End If
        If activeNavigateButton = RightPB Or activeNavigateButton = upRightPB Or _
            activeNavigateButton = downRightPB Then
            vpLeft = vpLeft + ChartViewer1.ViewportWidth * 0.05
        End If
        If activeNavigateButton = upPB Or activeNavigateButton = upLeftPB Or _
            activeNavigateButton = upRightPB Then
            vpTop = vpTop - ChartViewer1.ViewportHeight * 0.05
        End If
        If activeNavigateButton = downPB Or activeNavigateButton = downLeftPB Or _
            activeNavigateButton = downRightPB Then
            vpTop = vpTop + ChartViewer1.ViewportHeight * 0.05
        End If
        
        ' Scroll to the new view port position
        Call scrollChartTo(ChartViewer1, vpLeft, vpTop)
    End If
End Sub

'
' User moves zoom control slide bar
'
Private Sub ZoomBar_Scroll()

    ' Remember the center point
    Dim centerX As Double, centerY As Double
    centerX = ChartViewer1.ViewportLeft + ChartViewer1.ViewportWidth / 2
    centerY = ChartViewer1.ViewportTop + ChartViewer1.ViewportHeight / 2

    ' Aspect ratio and zoom factor
    Dim aspectRatio As Double, zoomTo As Double
    aspectRatio = ChartViewer1.ViewportWidth / ChartViewer1.ViewportHeight
    zoomTo = CDbl(ZoomBar.value) / ZoomBar.Max

    ' Zoom while preserving aspect ratio
    ChartViewer1.ViewportWidth = zoomTo * IIf(aspectRatio > 1, aspectRatio, 1)
    ChartViewer1.ViewportHeight = zoomTo * IIf(aspectRatio > 1, 1, 1 / aspectRatio)
        
    ' Adjust ViewPortLeft and ViewPortTop to keep center point unchanged
    ChartViewer1.ViewportLeft = centerX - ChartViewer1.ViewportWidth / 2
    ChartViewer1.ViewportTop = centerY - ChartViewer1.ViewportHeight / 2
        
    ' Update the chart
    Call ChartViewer1.UpdateViewPort(True, False)
   
End Sub

'
' User click on the navigate window
'
Private Sub NavigateWindow_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbLeftButton Then
        ' Save the mouse coordinates to keep track of how far the navigateWindow has been dragged.
        isDraggingNavigatePad = True
        mouseDownXCoor = X
        mouseDownYCoor = Y
    End If
End Sub

'
' User drags the navigate window
'
Private Sub NavigateWindow_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If isDraggingNavigatePad Then
    
        ' Is currently dragging - compute where is the navigateWindow being dragged to
        Dim newLabelLeft As Double, newLabelTop As Double
        newLabelLeft = NavigateWindow.Left + X - mouseDownXCoor
        newLabelTop = NavigateWindow.Top + Y - mouseDownYCoor
    
        ' Ensure the navigateWindow is within the navigatePad container
        Dim internalPadWidth As Long, internalPadHeight As Long
        internalPadWidth = NavigatePad.Width - ScaleX(2, vbPixels, ScaleMode)
        internalPadHeight = NavigatePad.height - ScaleY(2, vbPixels, ScaleMode)
        
        If newLabelLeft < 0 Then
            newLabelLeft = 0
        ElseIf newLabelLeft > internalPadWidth - NavigateWindow.Width Then
            newLabelLeft = internalPadWidth - NavigateWindow.Width
        End If
        If newLabelTop < 0 Then
            newLabelTop = 0
        ElseIf newLabelTop > internalPadHeight - NavigateWindow.height Then
            newLabelTop = internalPadHeight - NavigateWindow.height
        End If
    
        ' Update the navigateWindow position as it is being dragged
        NavigateWindow.Left = newLabelLeft
        NavigateWindow.Top = newLabelTop
        
        ' Update the view port to reflect the navigation window
        ChartViewer1.ViewportLeft = CDbl(NavigateWindow.Left) / internalPadWidth
        ChartViewer1.ViewportTop = CDbl(NavigateWindow.Top) / internalPadHeight
        Call ChartViewer1.UpdateViewPort(True, False)
    End If
End Sub

'
' User release mouse button on the navigate window
'
Private Sub NavigateWindow_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    isDraggingNavigatePad = False
End Sub

'
' Utility to scroll the view port to the given position if necessary
'
Private Sub scrollChartTo(viewer As ChartViewer, vpLeft As Double, vpTop As Double)
    ' Validate the parameters
    Call viewer.validateViewPort

    ' Update chart only if the view port has changed
    If vpLeft <> viewer.ViewportLeft Or vpTop <> viewer.ViewportTop Then
        viewer.ViewportLeft = vpLeft
        viewer.ViewportTop = vpTop
        Call viewer.UpdateViewPort(True, False)
    End If
End Sub

'
' Mouse moves over ChartViewer
'
Private Sub ChartViewer1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = 0 Then
        ' Mouse is over chart with mouse button released (not dragging)
        ' Update image map if necessary
        Call updateImageMap(ChartViewer1)
    End If
End Sub

'
' User clicks on a hot spot on the chart
'
Private Sub ChartViewer1_ClickHotSpot(hotSpot As Collection, Button As Integer, Shift As Integer, _
    X As Single, Y As Single)
    ' We show the pop up dialog only when the mouse action is not zoom in or zoom out
    If ChartViewer1.MouseUsage <> cvZoomIn And ChartViewer1.MouseUsage <> cvZoomOut Then
        'In this demo, just list out the information provided by ChartDirector about hot spot
        ParamViewer.Display hotSpot
    End If
End Sub

'
' The ViewPortChanged event handler. This event occurs when the user changes the ChartViewer
' view port by dragging scrolling, or by zoom in/out, or the ChartViewer.updateViewPort method
' is being called.
'
Private Sub ChartViewer1_ViewPortChanged(needUpdateChart As Boolean, needUpdateImageMap As Boolean)
    If Not isDraggingNavigatePad Then
        ' Update the navigator window size and position to reflect the view port
        Dim internalPadWidth As Long, internalPadHeight As Long
        internalPadWidth = NavigatePad.Width - ScaleX(2, vbPixels, ScaleMode)
        internalPadHeight = NavigatePad.height - ScaleY(2, vbPixels, ScaleMode)
        
        NavigateWindow.Left = CInt(ChartViewer1.ViewportLeft * internalPadWidth)
        NavigateWindow.Top = CInt(ChartViewer1.ViewportTop * internalPadHeight)
        NavigateWindow.Width = Int(ChartViewer1.ViewportWidth * internalPadWidth)
        NavigateWindow.height = Int(ChartViewer1.ViewportHeight * internalPadHeight)
    End If
    
    ' Synchronize the zoom bar value with the view port width/height
    ZoomBar.value = Int(0.5 + IIf(ChartViewer1.ViewportWidth > ChartViewer1.ViewportHeight, _
        ChartViewer1.ViewportHeight, ChartViewer1.ViewportWidth) * ZoomBar.Max)
        
    ' Update chart and image map if necessary
    If needUpdateChart Then
        Call drawChart(ChartViewer1)
    End If
    If needUpdateImageMap Then
        Call updateImageMap(ChartViewer1)
    End If
    
End Sub

'
' Draw the chart
'
Private Sub drawChart(viewer As ChartViewer)
    ' Create an XYChart object 500 x 480 pixels in size, with light blue (c0c0ff) as background
    ' color
    Dim c As XYChart
    Set c = cd.XYChart(500, 480, &HC0C0FF)

    ' Set the plotarea at (50, 40) and of size 400 x 400 pixels. Use light grey (c0c0c0) horizontal
    ' and vertical grid lines. Set 4 quadrant coloring, where the colors of the quadrants alternate
    ' between lighter and deeper grey (dddddd/eeeeee).
    Call c.setPlotArea(50, 40, 400, 400, -1, -1, -1, &HC0C0C0, &HC0C0C0).set4QBgColor(&HDDDDDD, _
        &HEEEEEE, &HDDDDDD, &HEEEEEE, &H0)

    ' Enable clipping mode to clip the part of the data that is outside the plot area.
    Call c.setClipping

    ' Set 4 quadrant mode, with both x and y axes symetrical around the origin
    Call c.setAxisAtOrigin(cd.XYAxisAtOrigin, cd.XAxisSymmetric + cd.YAxisSymmetric)

    ' Add a legend box at (450, 40) (top right corner of the chart) with vertical layout and 8 pts
    ' Arial Bold font. Set the background color to semi-transparent grey (40dddddd).
    Dim legendBox As legendBox
    Set legendBox = c.addLegend(450, 40, True, "arialbd.ttf", 8)
    Call legendBox.setAlignment(cd.TopRight)
    Call legendBox.setBackground(&H40DDDDDD)

    ' Add titles to axes
    Call c.xAxis().setTitle("Alpha Index")
    Call c.yAxis().setTitle("Beta Index")

    ' Set axes line width to 2 pixels
    Call c.xAxis().setWidth(2)
    Call c.yAxis().setWidth(2)

    ' The default ChartDirector settings has a denser y-axis grid spacing and less-dense x-axis grid
    ' spacing. In this demo, we want the tick spacing to be symmetrical. We use around 40 pixels
    ' between major ticks and 20 pixels between minor ticks.
    Call c.xAxis().setTickDensity(40, 20)
    Call c.yAxis().setTickDensity(40, 20)

    '
    ' In this example, we represent the data by scatter points. If you want to represent the data by
    ' somethings else (lines, bars, areas, floating boxes, etc), just modify the code below to use
    ' the layer type of your choice.
    '

    ' Add scatter layer, using 11 pixels red (ff33333) X shape symbols
    Call c.addScatterLayer(dataX0, dataY0, "Group A", cd.Cross2Shape(), 11, &HFF3333)

    ' Add scatter layer, using 11 pixels green (33ff33) circle symbols
    Call c.addScatterLayer(dataX1, dataY1, "Group B", cd.CircleShape, 11, &H33FF33)

    ' Add scatter layer, using 11 pixels blue (3333ff) triangle symbols
    Call c.addScatterLayer(dataX2, dataY2, "Group C", cd.TriangleSymbol, 11, &H3333FF)

    If maxX = minX Then
        ' The axis scale has not yet been set up. This means this is the first time the chart is
        ' drawn and it is drawn with no zooming. We can use auto-scaling to determine the
        ' axis-scales, then remember them for future use.

        ' explicitly auto-scale axes so we can get the axis scales
        Call c.layout

        ' save the axis scales for future use
        minX = c.xAxis().getMinValue()
        maxX = c.xAxis().getMaxValue()
        minY = c.yAxis().getMinValue()
        maxY = c.yAxis().getMaxValue()
    Else
        ' Compute the zoomed-in axis scales using the overall axis scales and ViewPort size
        Dim xScaleMin As Double
        Dim xScaleMax As Double
        Dim yScaleMin As Double
        Dim yScaleMax As Double
        xScaleMin = minX + (maxX - minX) * ChartViewer1.ViewportLeft
        xScaleMax = minX + (maxX - minX) * (ChartViewer1.ViewportLeft + ChartViewer1.ViewportWidth)
        yScaleMin = maxY - (maxY - minY) * (ChartViewer1.ViewportTop + ChartViewer1.ViewportHeight)
        yScaleMax = maxY - (maxY - minY) * ChartViewer1.ViewportTop
        ' *** use the following formula if you are using a log scale axis ***
        ' xScaleMin = minX * ((maxX / minX) ^ ChartViewer1.ViewPortLeft)
        ' xScaleMax = minX * ((maxX / minX) ^ (ChartViewer1.ViewPortLeft + _
        '     ChartViewer1.ViewPortWidth))
        ' yScaleMin = maxY * ((minY / maxY) ^ (ChartViewer1.ViewPortTop + _
        '     ChartViewer1.ViewPortHeight))
        ' yScaleMax = maxY * ((minY / maxY) ^ ChartViewer1.ViewPortTop)
    
        ' Set the axis scales
        Call c.xAxis().setLinearScale(xScaleMin, xScaleMax)
        Call c.xAxis().setRounding(False, False)
        Call c.yAxis().setLinearScale(yScaleMin, yScaleMax)
        Call c.yAxis().setRounding(False, False)
    End If

    ' Set the chart image to the ChartViewer
    Set viewer.Chart = c
End Sub

'
' Apply image map used on the chart if not already applied
'
Private Sub updateImageMap(viewer As ChartViewer)
    If viewer.ImageMap = "" Then
        viewer.ImageMap = viewer.Chart.getHTMLImageMap("clickable", "", _
            "title='[{dataSetName}] Alpha = {x}, Beta = {value}'")
    End If
End Sub