Platforms to show: All Mac Windows Linux Cross-Platform
/ChartDirector/math function plot
Required plugins for this example: MBS ChartDirector Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /ChartDirector/math function plot
This example is the version from Mon, 12th Jan 2020.
Project "math function plot.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
EventHandler Sub Open()
End EventHandler
End Class
MenuBar MenuBar1
MenuItem FileMenu = "&File"
MenuItem PrintA1 = "Print..."
MenuItem UntitledSeparator = "-"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem UntitledMenu1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem UntitledMenu0 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
Class ChartDirectorControl Inherits Canvas
Const kModeDefault = 0
Const kModeMove = 1
Const kModeZoomIn = 2
Const kModeZoomOut = 3
Event ItemClicked(XLabel As String, X As Integer, DataSet As Integer, DataSetName As String, Value As Double, Title As String, Sector As Integer, Label As String)
End Event
Event Open()
End Event
Event Render(ViewPort As CDViewPortManagerMBS, Factor As Double, Width As Integer, Height As Integer) As CDBaseChartMBS
End Event
EventHandler Function MouseDown(X As Integer, Y As Integer) As Boolean
isMouseDown = true
If (AllowZoom = True) And (Keyboard.AsyncOptionKey = True) Then
// Zoom In
Mode = kModeZoomIn
StartX = X
StartY = Y
StartX2 = X
StartY2 = Y
ElseIf (AllowZoom = True) And (Keyboard.AsyncShiftKey = True) Then
// Zoom Out
Mode = kModeZoomOut
StartX = X
StartY = Y
StartX2 = X
StartY2 = Y
Else
Dim HotSpotID As Integer
// Check if over a hotspot; Nil check prevents spurious NilObjectExceptions
If (ImageMapHandler <> Nil) Then HotSpotID = ImageMapHandler.getHotSpot(X, Y)
If (HotSpotID > 0) Then
// Click
Mode = kModeDefault
SendClickEvent
ElseIf (AllowMove = True) Then
// Move
Mode = kModeMove
MouseCursor = System.Cursors.HandClosed
StartX = X
StartY = Y
ViewPort.startDrag // Call to initiate drag within the ViewPort
End If
End If
Return (True)
End EventHandler
EventHandler Sub MouseDrag(X As Integer, Y As Integer)
If (Mode = kModeMove) Then
// If the chart has been dragged/repositioned then complete the ViewPort drag and refresh the image
If (ViewPort.dragTo(CDBaseChartMBS.kDirectionHorizontalVertical, StartX - X, Y - StartY) = True) Then Redraw
ElseIf (Mode = kModeZoomIn) Or (Mode = kModeZoomOut) Then
// Calculate the coordinates for the scaling/drawing of the selection rectangle
Dim L, T, W, H As Integer
StartX2 = X
StartY2 = Y
L = Min(StartX, StartX2)
T = Min(StartY, StartY2)
W = StartX2 - StartX
H = StartY2 - StartY
If (W < 0) Then W = -W
If (H < 0) Then H = -H
// Composite the current chart image with the selection rectangle
// trigger refresh
RectangleTop = t
rectangleLeft = l
rectangleWidth = w
rectangleHeight = h
me.Invalidate
End If
End EventHandler
EventHandler Sub MouseExit()
// Finalize redraw
CleanUp
End EventHandler
EventHandler Sub MouseMove(X As Integer, Y As Integer)
If (AllowZoom = True) And (Keyboard.AsyncOptionKey = True) Then
// Zoom In
MouseCursor = System.Cursors.MagnifyLarger
CleanUp // Finalize redraw
ElseIf (AllowZoom = True) And (Keyboard.AsyncShiftKey = True) Then
// Zoom Out
MouseCursor = System.Cursors.MagnifySmaller
CleanUp // Finalize redraw
Else
Dim HotSpotID As Integer
// Check if over a hotspot; Nil check prevents spurious NilObjectExceptions
If (ImageMapHandler <> Nil) Then HotSpotID = ImageMapHandler.getHotSpot(X, Y)
If (HotSpotID > 0) Then
MouseCursor = System.Cursors.StandardPointer
DrawItemInfo(X, Y)
ElseIf (AllowMove = True) Then
MouseCursor = System.Cursors.HandOpen
CleanUp // Finalize redraw
Else
MouseCursor = System.Cursors.StandardPointer
CleanUp // Finalize redraw
End If
End If
End EventHandler
EventHandler Sub MouseUp(X As Integer, Y As Integer)
isMouseDown = false
If (Mode = kModeMove) Then
// Move
MouseCursor=System.Cursors.HandOpen
ElseIf (Mode = kModeZoomIn) Then
// Zoom In (On Point)
If (Abs(X - StartX) < 3) And (Abs(Y - StartY) < 3) Then
// Zoom In (On Point)
If (ViewPort.canZoomIn(CDBaseChartMBS.kDirectionHorizontalVertical) = True) Then
If (ViewPort.zoomAt(CDBaseChartMBS.kDirectionHorizontalVertical, X, Y, ZoomInRatio) = True) Then Redraw
Else
// Cannot zoom in...
Redraw
Beep
End If
Else
// Zoom In (On Rectangle)
If (ViewPort.canZoomIn(CDBaseChartMBS.kDirectionHorizontalVertical) = True) Then
If (ViewPort.zoomTo(CDBaseChartMBS.kDirectionHorizontalVertical, X, Y, StartX, StartY) = True) Then Redraw
Else
// Cannot zoom in...
Redraw
Beep
End If
End If
ElseIf (Mode = kModeZoomOut) Then
// Zoom Out (On Point)
If (ViewPort.canZoomOut(CDBaseChartMBS.kDirectionHorizontalVertical) = True) Then
If (ViewPort.zoomAt(CDBaseChartMBS.kDirectionHorizontalVertical, X, Y, ZoomOutRatio) = True) Then Redraw
else
// Cannot zoom out...
Redraw
Beep
End If
End If
End EventHandler
EventHandler Sub Open()
// Initialize the ViewPort manager class
ViewPort = New CDViewPortManagerMBS
// Set ViewPort coordinant constraints
ViewPort.setViewPortHeight(1.0)
ViewPort.setViewPortTop(0.0)
ViewPort.setViewPortWidth(1.0)
ViewPort.setViewPortLeft(0.0)
// Set Zoom In and Zoom Out constraints (if desired; otherwise allow infinite zoom)
'ViewPort.setZoomInWidthLimit(0.01)
'ViewPort.setZoomInHeightLimit(0.01)
'ViewPort.setZoomOutWidthLimit(1.0)
'ViewPort.setZoomOutHeightLimit(1.0)
// Initialize scalable image for use in rendering the selection rectangle
RectanglePicture = New Picture(32, 32, 32)
RectanglePicture.Graphics.ForeColor = &cFF0000
RectanglePicture.Graphics.FillRect(0, 0, 32, 32)
RectanglePicture.Mask.Graphics.ForeColor = &cCCCCCC
RectanglePicture.Mask.Graphics.FillRect(0, 0, 32, 32)
// Set the initial cursor style
MouseCursor = System.Cursors.HandOpen
// Call overridden superclass method
Open
// fix some properties if set wrong in IDE
me.DoubleBuffer = false
me.EraseBackground = false
#if RBVersion >= 2013.0 then
me.Transparent = False
#endif
End EventHandler
EventHandler Sub Paint(g As Graphics, areas() As REALbasic.Rect)
// Handle drawing the composited image to the drawing region
If overlay <> Nil Then
g.DrawPicture overlay,0,0
Else
Draw(G)
end if
End EventHandler
Private Sub CleanUp()
// Finalize redraw
Me.rectangleWidth = 0
Me.Invalidate
Me.NeedClear = False
Me.Overlay = Nil
End Sub
Function CurrentPicture() As Picture
// Return the currently displayed chart image
Return (LastPicture)
End Function
Private Sub Draw(G As Graphics)
// Prepare ViewPort coordinates for chart rendering
ViewPort.validateViewPort
// Trigger chart rendering (actual chart configuration and data plotting)
Current = Render(ViewPort, 1.0, G.Width, G.Height)
If (Current = Nil) Then
// If there is no valid chart object returned, clear the drawing region
G.ClearRect(0, 0, G.Width, G.Height)
Else
// Get the chart image based on the returned chart object
LastPicture = Current.makeChartPicture
// Support control border drawing
If (Border = True) Then
LastPicture.Graphics.PenHeight = 1
LastPicture.Graphics.PenWidth = 1
LastPicture.Graphics.ForeColor = &c000000
LastPicture.Graphics.DrawRect(0, 0, G.Width, G.Height)
LastPicture.Mask.Graphics.PenHeight = 1
LastPicture.Mask.Graphics.PenWidth = 1
LastPicture.Mask.Graphics.ForeColor = &c000000
LastPicture.Mask.Graphics.DrawRect(0, 0, G.Width, G.Height)
End If
if CleanGraphicsBeforeDrawing then
g.ClearRect 0, 0, g.Width, g.Height
end if
// Draw composited chart image
G.DrawPicture(LastPicture, 0, 0)
// Update ViewPort to current chart coordinants
ViewPort.setChartMetrics(Current.getChartMetrics)
// Process ImageMap data to support data point rollovers, etc.
Dim ImageMapString As String
ImageMapString = Current.getHTMLImageMap("myurl" )
ImageMapHandler = New CDImageMapHandlerMBS(ImageMapString)
End If
End Sub
Private Sub DrawItemInfo(X As Integer, Y As Integer)
Dim Index as integer
Dim Key, KeyValue As String
Dim XLabel As String
Dim XValue As String
Dim DataSet As String
Dim DataSetName As String
Dim Value As String
Dim Title As String
Dim Sector As String
Dim Label As String
// Error check
If (ImageMapHandler = Nil) Then Return
// Do key/value pair priming calls
Index = 0
Key = ImageMapHandler.getKey(Index)
KeyValue = ImageMapHandler.getValue(Index)
Do
// NOTE: This is not the complete supported list of parameters; Refer to ChartDirector documentation on 'Parameter Substitution and Formatting' for additional parameters
Select Case Key
Case "xlabel"
XLabel = KeyValue
Case "x"
XValue = KeyValue
Case "dataset"
DataSet = KeyValue
Case "datasetname"
DataSetName = KeyValue
Case "value"
Value = KeyValue
Case "title"
Title = KeyValue
Case "sector"
Sector = KeyValue
Case "label"
Label = KeyValue
End Select
Index = Index + 1
// Get next key/value pair
Key = ImageMapHandler.getKey(Index)
KeyValue = ImageMapHandler.getValue(Index)
Loop Until Key.Len = 0
// Compose label graphic
If (Label <> "") Then Value = Label + ": " + Value
Dim B As Picture = New Picture(Width, Height, 32)
Dim G As Graphics = B.Graphics
Dim W As Integer = 6 + G.StringWidth(Value)
Dim H As Integer = 20
// Add some space between the cursor position and the initial label drawing position
X = X + 10
Y = Y + 10
// If we are too close to the right, we need to move our label drawing position left
If (X + W > G.Width) Then X = X - 20 - W
// If we are too close to the bottom, we need to move our label drawing position up
If (Y + H > G.Height) Then Y = Y - 20 - H
// Draw in the current composited chart image
B.Graphics.DrawPicture(LastPicture, 0, 0)
B.Mask.Graphics.DrawPicture(LastPicture.Mask, 0, 0)
// Draw the label graphic
G.ForeColor = &cCCCC00
G.FillRect(X, Y, W, H)
G.ForeColor = &c000000
G.DrawString(Value, X + 3, Y + 15)
// Update the composited chart image
Overlay = b
Me.Invalidate
NeedClear = True
End Sub
Sub Print()
Dim PS As New PrinterSetup
// Set landscape orientation if appropriate
PS.Landscape = Width > Height
// Initialize graphics region for printing
Dim G As Graphics = OpenPrinterDialog(PS)
// Bail out...
If (G = Nil) Then Return
// Render printed chart (use page size)
// NOTE: This uses a factor of 4x to up the resolution of the printed chart image (approximately 300 dpi)
'Dim P As Picture = RenderPicture(4, G.Width, G.Height)
'G.DrawPicture(P, 0, 0, G.Width, G.Height, 0, 0, G.Width * 4, G.Height * 4)
// Render printed chart (use control size)
// NOTE: This uses a factor of 4x to up the resolution of the printed chart image (approximately 300 dpi)
Dim P As Picture = RenderPicture(4, Width, Height)
G.DrawPicture(P, 0, 0, Width, Height, 0, 0, Width * 4, Height * 4)
End Sub
Sub Redraw()
// Method to directly trigger internal redraw
me.Invalidate
End Sub
Function RenderPicture(Factor As Double, Width As Integer, Height As Integer) As Picture
// Prepare ViewPort coordinates for chart rendering
ViewPort.validateViewPort
// Handle scaled redraw for printing
Dim C As CDBaseChartMBS = Render(ViewPort, Factor, Width, Height)
'If (C <> Nil) Then Return (C.makeChartPicture)
// Error check
If (C = Nil) Then Return (Nil)
dim p as Picture = C.makeChartPicture
Return p
End Function
Private Sub SendClickEvent()
Dim Index as integer
Dim Key, KeyValue As String
Dim XLabel As String
Dim XValue As String
Dim DataSet As String
Dim DataSetName As String
Dim Value As String
Dim Title As String
Dim Sector As String
Dim Label As String
// Error check
If (ImageMapHandler = Nil) Then Return
// Do key/value pair priming calls
Index = 0
Key = ImageMapHandler.getKey(Index)
KeyValue = ImageMapHandler.getValue(Index)
Do
// NOTE: This is not the complete supported list of parameters; Refer to ChartDirector documentation on 'Parameter Substitution and Formatting' for additional parameters
Select Case Key
Case "xlabel"
XLabel = KeyValue
Case "x"
XValue = KeyValue
Case "dataset"
DataSet = KeyValue
Case "datasetname"
DataSetName = KeyValue
Case "value"
Value = KeyValue
Case "title"
Title = KeyValue
Case "sector"
Sector = KeyValue
Case "label"
Label = KeyValue
End Select
Index = Index + 1
// Get next key/value pair
Key = ImageMapHandler.getKey(Index)
KeyValue = ImageMapHandler.getValue(Index)
Loop Until Key.Len = 0
// Trigger click event
ItemClicked(XLabel, Val(XValue), Val(DataSet), DataSetName, Val(Value), Title, Val(Sector), Label)
End Sub
Sub UpdateMouseCursor()
// call from a timer in your window to keep the mouse cursor change with pressing alt and shift keys.
// zoom allowed?
if not AllowZoom then Return
if isMouseDown then Return
dim x as integer = me.MouseX
dim y as integer = me.MouseY
// check if mouse is inside
if X<0 then Return
if Y<0 then Return
if X>me.Width then Return
if Y>me.Height then Return
// now update
If Keyboard.AsyncOptionKey Then
// Zoom In
MouseCursor = System.Cursors.MagnifyLarger
ElseIf Keyboard.AsyncShiftKey Then
// Zoom Out
MouseCursor = System.Cursors.MagnifySmaller
Else
Dim HotSpotID As Integer
// Check if over a hotspot; Nil check prevents spurious NilObjectExceptions
If (ImageMapHandler <> Nil) Then HotSpotID = ImageMapHandler.getHotSpot(X, Y)
If (HotSpotID > 0) Then
MouseCursor = System.Cursors.StandardPointer
ElseIf (AllowMove = True) Then
MouseCursor = System.Cursors.HandOpen
Else
MouseCursor = System.Cursors.StandardPointer
End If
End If
End Sub
Note "About Properties"
AllowMove and AllowZoom must be enabled if you want to zoom and move.
You need to use the viewport in your render code.
If Border is true, a black line is drawn around the chart.
If CleanGraphicsBeforeDrawing is true then the graphics object is cleared
before something is drawn
The OverlayPicture defines a picture which is drawn on top of the chart
as a watermark.
RenderWithTransparency will do redraws slower. The chart is rendered as
PNG with mask and for every redraw we refresh the whole control.
This may look bad on Windows.
ZoomInRatio and ZoomOutRatio are used for zooming.
This is how much we zoom on each click.
Note "Notes for Render Event"
Use the Width and Height you get and not the control's.
Use the Factor to multiply all values so you get it properly scaled for printing.
Use the ViewPort for zooming and moving.
Property AllowMove As Boolean
Property AllowZoom As Boolean
Property Border As Boolean
Property CleanGraphicsBeforeDrawing As Boolean
Property Private Current As CDBaseChartMBS
Property Private ImageMapHandler As CDImageMapHandlerMBS
Property Private LastPicture As Picture
Property Private MaxValue As Double
Property Private MinValue As Double
Property Private Mode As Integer
Property Private NeedClear As Boolean
Property Overlay As Picture
Property RectangleHeight As Integer
Property RectangleLeft As Integer
Property Private RectanglePicture As Picture
Property RectangleTop As Integer
Property RectangleWidth As Integer
Property Private StartX As Integer
Property Private StartX2 As Integer
Property Private StartY As Integer
Property Private StartY2 As Integer
Property Private ViewPort As CDViewPortManagerMBS
Property ZoomInRatio As Double = 1.25
Property ZoomOutRatio As Double = 0.75
Property Private isMouseDown As Boolean
End Class
Class ini Inherits Window
Control PushButton1 Inherits PushButton
ControlInstance PushButton1 Inherits PushButton
EventHandler Sub Action()
render
End EventHandler
End Control
Control xmin Inherits TextField
ControlInstance xmin Inherits TextField
EventHandler Function KeyDown(Key As String) As Boolean
If asc(Key) = 13 or asc(Key) = 3 then
render
Return true
End If
End EventHandler
End Control
Control xmax Inherits TextField
ControlInstance xmax Inherits TextField
EventHandler Function KeyDown(Key As String) As Boolean
If asc(Key) = 13 or asc(Key) = 3 then
render
Return true
End If
End EventHandler
End Control
Control ec0 Inherits TextField
ControlInstance ec0 Inherits TextField
EventHandler Function KeyDown(Key As String) As Boolean
If asc(Key) = 13 or asc(Key) = 3 then
render
Return true
End If
End EventHandler
End Control
Control StaticText1 Inherits Label
ControlInstance StaticText1 Inherits Label
End Control
Control RbScript1 Inherits RbScript
ControlInstance RbScript1 Inherits RbScript
EventHandler Sub CompilerError(line As Integer, errorNumber As Integer, errorMsg As String)
HasError = true
MsgBox "Syntax error. Please change formula."
End EventHandler
End Control
Control out Inherits ChartDirectorControl
ControlInstance out Inherits ChartDirectorControl
EventHandler Function Render(ViewPort As CDViewPortManagerMBS, Factor As Double, Width As Integer, Height As Integer) As CDBaseChartMBS
// Create a XYChart object of size ....
dim c as new CDXYChartMBS(width*factor, height*factor)
// Set the plotarea at (55, 65) and of size ...... pixels, with white
// background and a light grey border (0xc0c0c0). Turn on both horizontal and
// vertical grid lines with light grey color (0xc0c0c0)
call c.setPlotArea(75*factor, 55*factor, (width-150)*factor, (height-150)*factor, c.linearGradientColor(0, 55, 0, 335, &hf9fcff, &haaccff), -1, c.kTransparent, &hffffff).setGridColor(&hFF0000, &hFF0000)
call c.setClipping
// Add a legend box at (50, 30) (top of the chart) with horizontal layout. Use 12
// pts Times Bold Italic font. Set the background and border color to
// Transparent.
c.addLegend(50, 30, false, "timesbi.ttf", 12).setBackground(c.kTransparent)
// Add a title to the chart using 18 pts Times Bold Itatic font
call c.addTitle("y = " + ini.ec0.Text, "timesbi.ttf", 18)
// Add a title to the y axis using 12 pts Arial Bold Italic font
call c.yAxis.setTitle("Y", "arialbi.ttf", 12)
// Set the y axis line width to 3 pixels
c.yAxis.setWidth(3)
// Add a title to the x axis using 12 pts Arial Bold Italic font
call c.xAxis.setTitle("X", "arialbi.ttf", 12)
// Set the x axis line width to 3 pixels
c.xAxis.setWidth(3)
// Add a red (0xff3333) line layer using dataX0 and dataY0
dim layer1 as CDLineLayerMBS
layer1 = c.addLineLayer(ini.dataY0, &hff3333, "")
layer1.setXData(ini.dataX0)
// Set the line width to 3 pixels
layer1.setLineWidth(3)
Return c
End EventHandler
End Control
Control Timer1 Inherits Timer
ControlInstance Timer1 Inherits Timer
EventHandler Sub Action()
out.UpdateMouseCursor
End EventHandler
End Control
Control StaticText2 Inherits Label
ControlInstance StaticText2 Inherits Label
End Control
EventHandler Sub Open()
ec0.SetFocus
render
End EventHandler
Function PrintA1() As Boolean
out.Print
Return (True)
End Function
Sub render()
dim xminValue as Double = val(xmin.Text)
dim xmaxValue as Double = val(xmax.Text)
dim line as string
if ec0.Text = "" then
beep
Return
end if
//-------------------------------------------------------------------
//Pasamos lo que el usuario ha escrito en el ec0.Text al line invisible
line = "y = " + ec0.Text
//-------------------------------------------------------------------
//Ahota vamos a poner los asteriscos(signos por)
Dim r as New RegEx
Dim myMatch as RegEXMatch
// Replace 2x with 2*x
//Donde buscar lo que hay que cambiar
MyMatch = r.Search(line)
//Qué cambiar
r.SearchPattern="(\d+)([a-z])"
//Qué debe aparecer
r.ReplacementPattern="\1*\2"
//Todas las veces
r.Options.ReplaceAllMatches = True
//Donde poner el cambio
line = r.replace
Dim s as New RegEx
Dim myMatch1 as RegEXMatch
// replace (1)(2) with (1)*(2)
//Donde buscar lo que hay que cambiar
MyMatch1 = s.Search(line)
//Qué cambiar
s.SearchPattern="([)]+)([(])"
//Qué debe aparecer
s.ReplacementPattern="\1*\2"
//Todas las veces
s.Options.ReplaceAllMatches = True
//Donde poner el cambio
line = s.replace
// special variables
dim c as new ScriptContext
c.e = 2.7182818284
c.pi = 3.14159265
line = ReplaceAll(line, "π", "pi")
//--------------------------------------------------------------------
redim Datax0(-1)
redim Datay0(-1)
//Establecemos ini como contexto del RBScript
RbScript1.Context = c
//Decimos donde se encuentra el código del Script dentro de ini
RbScript1.Source = line
HasError = false
//Definimos lo que queremos hacer con el Rbscript
dim p as integer
dim d as Double = xmaxValue - xminValue
if d<1 then d = 1.0
for p = 0 to 500
dim x as Double = xminValue + (p/500.0) * d
c.x = x
Datax0.Append x
RbScript1.Run //Ejecuta el código del RBScript (TxtField1.Text)
if HasError then
beep
Return
end if
Datay0.append c.y //Añadimos el resultado en el array Datay0
next
//---------------------------------------------------
//------------------------------------------------------------------------
out.Redraw
//------------------------------------------------------------------------
End Sub
Property Datax0() As Double
Property Datay0() As Double
Property HasError As Boolean
Property e As Double
Property pi As Double
Property Protected x As double
Property Protected y As double
End Class
Class ScriptContext
Property e As Double
Property pi As Double
Property x As Double
Property y As Double
End Class
End Project
See also:
The items on this page are in the following plugins: MBS ChartDirector Plugin.