LiveCode Widgets: Modifying the Line Chart

by Monte Goulding on September 15, 2016 2 comments

Last week we looked at how to use the Line Chart Widget. This week I am going to show you how to modify this widget. I have included a link to the code on GitHub at the end of this blog post.

Having spent most of my time lately immersed in mergExt externals, the LiveCode engine and the IDE, I haven’t had as much time as I’d like to delve into LiveCode Builder and Widgets. Until now…

The showLines

I had identified a few weeks ago that the line chart widget is so very close to a scatter plot that it hurts, so my first port of call was to add a showLines property. It turns out it was relatively easy to do. I first implemented a property definition along with documentation. Here I needed to force the Property Inspector to use the Basic action because otherwise the inspector would put it on the table section, because the field showLines property appears there:


/**
Summary: Whether chart lines are displayed

Syntax:
set the showLines of  to { true | false }
get the showLines of 

Value (boolean): True if lines should be shown; false otherwise

Description:
If true, the graph widget will draw graph lines on the graph.

Related: markerStyles (property)

*/
property showLines get mLinesShow set SetLineVisibility
metadata showLines.default is "true"
metadata showLines.label is "Show graph lines"
metadata showLines.section is "Basic"

I added an instance variable:


private variable mLinesShow as Boolean

Initialise in the OnCreate handler:


put true into mLinesShow

I added showLines to the OnSave handler:


put mLinesShow into rProperties["showLines"]

Then to the OnLoad handler:


if "showLines" is among the keys of pProperties then
   SetLineVisibility(pProperties["showLines"])
end if

I implemented the property setter:


public handler SetLineVisibility(in pShowLines as Boolean) returns nothing
   put pShowLines into mLinesShow
   redraw all
end handler

Then in the drawGraph handler I just ensured mLinesShow was true before drawing the lines:


if mLinesShow is true then
   if tPointIndex is 1 then
       move to tPoint on tPath
   else
       line to tPoint on tPath
   end if
end if

...

if mLinesShow is true then
   stroke tPath on this canvas
end if

The markerStyles

Now that showLines was implemented the next logical step was to add a way to set the marker styles for each point on the chart. I wanted to be able to both have a chart with lines but no markers and different markers for each line. I realised that the showLines and the markerStyles needed to work together to ensure that there were always either lines or markers and possibly both. There was already an instance variable, mVerticesShow, that governed the visibility of the markers but was always true. I decided not to expose that to script, but to use it to govern whether no makers should be shown at all. In this way we can set the markerStyles to empty and therefore not show any markers, or set one style for each data series.

Again the first thing I did was implement the property definition and documentation. Here I needed to set the editor type so the inspector used a large field with a scrollbar:


/**
Summary: Set the marker style for each data series

Syntax:
set the markerStyles of  to {  | empty }
get the markerStyles of 

Value(String): A line-delimited list of the marker styles for each line
on the graph

Description:
The  are the marker styles of each line in the graph
widget.

If set to empty then no markers will be shown and
showLines will be set to true. Available marker styles may be one of:

- "filled circle"
- "filled square"
- "filled diamond"
- "circle"
- "square"
- "diamond"

By default the markerStyles will repeat in the above order.

Related: showLines (property)
*/
property markerStyles get GetMarkerStyles set SetMarkerStyles
metadata markerStyles.default is "filled circlenfilled squarenfilled diamond"
metadata markerStyles.editor is "com.livecode.pi.text"
metadata markerStyles.label is "Marker styles"

Add an instance variable:


private variable mMarkerStyles as List

Initialise in the OnCreate handler:


put [] into mMarkerStyles

I added markerStyles and showMarkers to the OnSave handler:


put mVerticesShow into rProperties["showMarkers"]
put mMarkerStyles into rProperties["markerStyles"]

Then in the OnLoad handler we set the markers:


if "showMarkers" is among the keys of pProperties then
   put pProperties["showMarkers"] into mVerticesShow
end if
if "markerStyles" is among the keys of pProperties then
   put pProperties["markerStyles"] into mMarkerStyles
end if
EnsureMarkerStyles()

I implemented the property getter, setter and a function to ensure the markers are initialised correctly:


public handler GetMarkerStyles() returns String
   if mMarkerStyles is [] then
      return ""
   end if
	
   variable tMarkerStyles as String
   combine mMarkerStyles with newline into tMarkerStyles
   return tMarkerStyles
end handler

public handler SetMarkerStyles(in pMarkerStyles as String) returns nothing
   if pMarkerStyles is "" then
      put true into mLinesShow
      put [] into mMarkerStyles
      put false into mVerticesShow
   else
      split pMarkerStyles by newline into mMarkerStyles
      put true into mVerticesShow
      EnsureMarkerStyles()
   end if
   redraw all
end handler

public handler EnsureMarkerStyles() returns nothing
   if mVerticesShow and the number of elements in mMarkerStyles < the number of elements in mData then
      variable tStyles as List
      put ["filled circle", "filled square", "filled diamond", "circle", "square", "diamond"] into tStyles
		
      variable tCount as Integer
      repeat with tCount from the number of elements in mMarkerStyles + 1 up to the number of elements in mData
         push tStyles[tCount mod 6 + 1] onto back of mMarkerStyles
      end repeat
   end if
end handler

I added EnsureMarkerStyles() to the setData property to make sure that there will always be enough marker styles for the number of series in the widget.

Then in the drawGraph handler I created the different paths based on the required marker style for each line:


// Draw vertices
if mVerticesShow is true then
   if mMarkerStyles[tGraphLine - 1] contains "circle" then
      put circle path centered at point [0,0] with radius 3 into tMarkerPath
   else
      put rectangle path of rectangle [-3,-3,3,3] into tMarkerPath
   end if
					
   if mMarkerStyles[tGraphLine - 1] contains "diamond" then
      rotate tMarkerPath by 45
   end if
					
   translate tMarkerPath by [tPointX, tPointY]
   add tMarkerPath to tPathVertices
end if

...
		
if mVerticesShow is true then
   if mMarkerStyles[tGraphLine - 1] contains "filled" then
      fill tPathVertices on this canvas
   else
      stroke tPath on this canvas
   end if
end if

The End Result

You can view the code on GitHub here

plot

Monte GouldingLiveCode Widgets: Modifying the Line Chart

Related Posts

Take a look at these posts

2 comments

Join the conversation
  • Paul Malloy - September 15, 2016 reply

    Pardon a rookie question—
    Where can I find the documentation for the various LineChart commands, such as set markerStyle? I cannot see any when I search…

    panos - September 16, 2016 reply

    Hi Paul,
    Just open the Dictionary, and from the “Choose API:” dropdown menu choose “Line Graph”. This contains all the Line graph related entries

Join the conversation

*