B4J Tutorial [ABMaterial] Alternative lightweight charts

Discussion in 'B4J Tutorials' started by alwaysbusy, Nov 12, 2017.

  1. alwaysbusy

    alwaysbusy Expert Licensed User

    The official charts library of ABMaterial is Chartist, but because of its many features it is also a rather slow rendering js/css library and not always that easy to implement. @Mashiane has created a nice ABMCustomComponent wrapper for the JQPlot plugin and there are many examples in the forum on how to implement Google Charts in ABM, like this post from @Harris.

    So why yet another one? Well the main focus on this wrapper is being fast AND easy to implement. Of course this also means less tunable features but I have found that maybe for 95% of our needs having some basic stuff like a tooltip and being clickable is actually enough.

    I came accross the Frappé charts javascript library. It has tooltips, some interactions and animations. And it is bloody fast! :)

    I only had to make a couple of CSS changes to make it ABM compatible and the ABMCustomComponent wrapper was very easy to write.

    Usage:

    Create your chart variables in Class_globals:
    Code:
    Dim FrappeChart1 As FrappeChart
    Dim FrappeChart2 As FrappeChart
    Dim FrappeChart3 As FrappeChart
    Dim FrappeChart4 As FrappeChart
    Dim FrappeChart5 As FrappeChart
    Dim FrappeChart6 As FrappeChart
    Dim FrappeChart7 As FrappeChart
    In Page_Connect(), make your charts (you immidately can see the simplicity of the code):
    Code:
    FrappeChart1.Initialize(page"FrappeChart1""bar""My Awesome Chart"250)
    FrappeChart1.FrappeLabels.AddAll(
    Array As String("12am-3am""3am-6am""6am-9am""9am-12pm","12pm-3pm""3pm-6pm""6pm-9pm""9pm-12am"))
    FrappeChart1.AddDataSet(
    "Some data""light-blue"Array As Int(2540303585217, -4), Array As String())
    FrappeChart1.AddDataSet(
    "Another set""violet"Array As Int(2550, -101518322714), Array As String())
    FrappeChart1.AddDataSet(
    "Yet Another""blue"Array As Int(1520, -3, -155812, -1737), Array As String())
    page.Cell(1,1).AddComponent(FrappeChart1.ABMComp)
       
    FrappeChart2.Initialize(
    page"FrappeChart2""line""My Awesome Chart"250)
    FrappeChart2.FrappeLabels.AddAll(
    Array As String("12am-3am""3am-6am""6am-9am""9am-12pm","12pm-3pm""3pm-6pm""6pm-9pm""9pm-12am"))
    FrappeChart2.AddDataSet(
    "Some data""light-blue"Array As Int(2540303585217, -4), Array As String())
    FrappeChart2.AddDataSet(
    "Another set""violet"Array As Int(2550, -101518322714), Array As String())
    FrappeChart2.AddDataSet(
    "Yet Another""blue"Array As Int(1520, -3, -155812, -1737), Array As String())
    page.Cell(1,1).AddComponent(FrappeChart2.ABMComp)
       
    FrappeChart3.Initialize(
    page"FrappeChart3""scatter""My Awesome Chart"250)
    FrappeChart3.FrappeLabels.AddAll(
    Array As String("12am-3am""3am-6am""6am-9am""9am-12pm","12pm-3pm""3pm-6pm""6pm-9pm""9pm-12am"))
    FrappeChart3.AddDataSet(
    "Some data""light-blue"Array As Int(2540303585217, -4), Array As String())
    FrappeChart3.AddDataSet(
    "Another set""violet"Array As Int(2550, -101518322714), Array As String())
    FrappeChart3.AddDataSet(
    "Yet Another""blue"Array As Int(1520, -3, -155812, -1737), Array As String())
    page.Cell(1,1).AddComponent(FrappeChart3.ABMComp)
         
    FrappeChart4.Initialize(
    page"FrappeChart4""pie""My Awesome Chart"250)
    FrappeChart4.FrappeLabels.AddAll(
    Array As String("12am-3am""3am-6am""6am-9am""9am-12pm","12pm-3pm""3pm-6pm""6pm-9pm""9pm-12am"))
    FrappeChart4.AddDataSet(
    "Some data""light-blue"Array As Int(2540303585217, -4), Array As String())
    FrappeChart4.AddDataSet(
    "Another set""violet"Array As Int(2550, -101518322714), Array As String())
    FrappeChart4.AddDataSet(
    "Yet Another""blue"Array As Int(1520, -3, -155812, -1737), Array As String())
    page.Cell(1,1).AddComponent(FrappeChart4.ABMComp)
       
    FrappeChart5.Initialize(
    page"FrappeChart5""percentage""My Awesome Chart"250)
    FrappeChart5.FrappeLabels.AddAll(
    Array As String("12am-3am""3am-6am""6am-9am""9am-12pm","12pm-3pm""3pm-6pm""6pm-9pm""9pm-12am"))
    FrappeChart5.AddDataSet(
    "Some data""light-blue"Array As Int(2540303585217, -4), Array As String())
    FrappeChart5.AddDataSet(
    "Another set""violet"Array As Int(2550, -101518322714), Array As String())
    FrappeChart5.AddDataSet(
    "Yet Another""blue"Array As Int(1520, -3, -155812, -1737), Array As String())
    page.Cell(1,1).AddComponent(FrappeChart5.ABMComp)
       
    FrappeChart6.Initialize(
    page"FrappeChart6""bar""My Awesome Chart"250)
    FrappeChart6.FrappeLabels.AddAll(
    Array As String("Sun""Mon""Tue""Wed""Thu""Fri""Sat"))
    FrappeChart6.AddDataSet(
    "Some data""purple"Array As Int(2540303585217), Array As String())
    FrappeChart6.AddDataSet(
    "Another set""orange"Array As Int(2550, -1015183227), Array As String())
    FrappeChart6.FrappeShowSums = 
    True
    FrappeChart6.FrappeShowAverages = 
    True
    page.Cell(1,1).AddComponent(FrappeChart6.ABMComp)
       
    FrappeChart7.Initialize(
    page"FrappeChart7""bar""My Awesome Chart"300)
    FrappeChart7.FrappeLabels.AddAll(
    Array As String("Ganymede""Callisto""Io""Europa"))
    FrappeChart7.AddDataSet(
    "Distances""grey"Array As Int(1070.4121882.709421.700671.034), Array As String("1.070.412km""1.882.709km""421.700km""671.034km"))
    FrappeChart7.FrappeIsNavigable = 
    True
    FrappeChart7.FrappeRaiseEventOnClick = 
    True
    page.Cell(2,1).AddComponent(FrappeChart7.ABMComp)
    An example of the Click event on Chart7:
    Code:
    Sub FrappeChart7_Clicked(index As Int)
       
    Dim img As ABMImage = page.Component("img")
       
    Dim lbl As ABMLabel = page.Component("lbl")
       
    Select Case index
         
    Case 0
           img.Source = 
    "../images/ganymede.jpg"
           lbl.Text = 
    "{B}Ganymede{/B}{BR}{BR}Semi-major-axis: 1070412 km{BR}{BR}Mass: 14819000 x 10^16 kg{BR}Diameter: 5262.4 km"
         
    Case 1
           img.Source = 
    "../images/callisto.jpg"
           lbl.Text = 
    "{B}Callisto{/B}{BR}{BR}Semi-major-axis: 1882709 km{BR}{BR}Mass: 10759000 x 10^16 kg{BR}Diameter: 4820.6 km"
         
    Case 2
           img.Source = 
    "../images/io.jpg"
           lbl.Text = 
    "{B}Io{/B}{BR}{BR}Semi-major-axis: 421700 km{BR}{BR}Mass: 8931900 x 10^16 kg{BR}Diameter: 3637.4 km"
         
    Case 3
           img.Source = 
    "../images/europa.jpg"
           lbl.Text = 
    "{B}Europa{/B}{BR}{BR}Semi-major-axis: 671034 km{BR}{BR}Mass: 4800000 x 10^16 kg{BR}Diameter: 3121.6 km"
       
    End Select
       img.Refresh
       lbl.Refresh
    End Sub
    This is the result:

    [​IMG]

    [​IMG]

    [​IMG]

    Attached are the FrappeChart.bas and the frappe-charts.min.iife.js files. Copy the .js file to the /www/js/custom/ folder and import the .bas file.
     

    Attached Files:

  2. Anser

    Anser Well-Known Member Licensed User

    In the Template project, inside the folder /www/js/custom there is already a file with the name frappe-charts.min.iife.403.js So I believe that I don not have to copy the frappe-charts.min.iife.js file that is available inside the zip folder in the above post

    I just have to include the FrappeChart.bas in my project. Right ?

    May be because this thread/post was created before the release of ABMaterial ver 4.03

    I could net get it running. On the page instead of the graph it is just showing a text
    var _tabservice-frappechart2;

    I followed what has been described in the first post of this thread to create a Frappe Chart

    Solved : The following line should be included in the BuildPage()
    page.AddExtraJavaScriptFile("../../js/custom/frappe-charts.min.iife.403.js")
     
    Last edited: Mar 21, 2018
    joulongleu likes this.
  3. Mashiane

    Mashiane Expert Licensed User

    So I'm exploring... plotting chart from a db 1 series at a time...
    FrappeBE.png

    Code:
    Dim fcbudgetexpenditure As FrappeChart
        fcbudgetexpenditure.Initialize(
    page"fcbudgetexpenditure""bar""Total Budget vs Total Expenditure (Millions)"500)
        fcbudgetexpenditure.frappexaxismode = 
    "span"
        fcbudgetexpenditure.frappeyaxismode = 
    "span"
        fcbudgetexpenditure.frappeisseries = 
    True
        fcbudgetexpenditure.frapperaiseeventonclick = 
    False
        fcbudgetexpenditure.frappeisnavigable = 
    True
        fcbudgetexpenditure.frappeshowsums = 
    False
        fcbudgetexpenditure.frappeshowaverages = 
    False
        fcbudgetexpenditure.frappelineshowdots = 
    True
        fcbudgetexpenditure.frappelineheatline = 
    False
        fcbudgetexpenditure.frappelineregionfill = 
    False
        fcbudgetexpenditure.valuesoverpoints = 
    True
        
    Dim jSQL As SQL = ABMShared.SQLGet
        
    Dim lbls As List: lbls.Initialize
        lbls.add(
    "Budget")
        fcbudgetexpenditure.FrappeLabels.AddAll(lbls)
        
    Dim recs As List = ABMShared.Execute2List(jSQL,"select Round(SUM(budget)/1000000,0) As a from projects",Null,0)
        fcbudgetexpenditure.AddDataSet(
    "Budget""blue", recs, Array As String())
        
    Dim recs As List = ABMShared.Execute2List(jSQL,"select Round(SUM(expenditure)/1000000,0) As b from projects",Null,0)
        fcbudgetexpenditure.AddDataSet(
    "Expenditure""red", recs, Array As String())
        ABMShared.SQLClose(jSQL)
        
    page.Cell(2,1).AddComponent(fcbudgetexpenditure.ABMComp)
    One thing though, I have to call 1 query against the db, extracting both a & b using executemaps, parse that map and return each single dataset, then add to the chart.

    Lesson: Only add 1 label for grouping datasets
     
    Last edited: Jun 15, 2018
    joulongleu likes this.
  4. Mashiane

    Mashiane Expert Licensed User

    Drawing datasets from different queries: continued..

    So here I wanted a bar chart to show total projects vs completed projects, using same approach above, I tweaked my queries.. one counts all the projects and one counts only projects with actual progress = 100%.

    Code:
    fccompletedprojects.Initialize(page"fccompletedprojects""bar""Total Projects vs Completed Projects"500)
        fccompletedprojects.frappexaxismode = 
    "span"
        fccompletedprojects.frappeyaxismode = 
    "span"
        fccompletedprojects.frappeisseries = 
    True
        fccompletedprojects.frapperaiseeventonclick = 
    False
        fccompletedprojects.frappeisnavigable = 
    True
        fccompletedprojects.frappeshowsums = 
    False
        fccompletedprojects.frappeshowaverages = 
    False
        fccompletedprojects.frappelineshowdots = 
    True
        fccompletedprojects.frappelineheatline = 
    False
        fccompletedprojects.frappelineregionfill = 
    False
        fccompletedprojects.valuesoverpoints = 
    True
        
    Dim jSQL As SQL = ABMShared.SQLGet
        
    Dim lbls As List: lbls.Initialize
        lbls.add(
    "Total Projects vs Completed Projects")
        fccompletedprojects.FrappeLabels.AddAll(lbls)
        
    Dim recsa As List = ABMShared.Execute2List(jSQL,"select Round(COUNT(id),0) As a from projects",Null,0)
        fccompletedprojects.AddDataSet(
    "Total""blue", recsa, Array As String())
        
    Dim recsb As List = ABMShared.Execute2List(jSQL,"select count(id) as b from projects where actualprogress = 100",Null,0)
        fccompletedprojects.AddDataSet(
    "Completed""red", recsb, Array As String())
        ABMShared.SQLClose(jSQL)
    TotalvsComplete.png
     
    joulongleu likes this.
  5. Mashiane

    Mashiane Expert Licensed User

    Loading both x and y axis from a DB

    FrappeDB.png

    I just need to figure out how to set the x axis to work with angles here, but the demo here is about reading both the x axis and y axis values from the db and then plotting this on the frappe chart...

    1. We need to pass lists for labels, and each of the datasets.
    2. We run an execute maps to return 'a' and 'b' i.e. xy data from our recordsets using executemaps
    3. We use the x i.e. clientnames as labels to plot these for the x axis
    4. We use the a
    Code:
    fcprojectsbyclient.Initialize(page"fcprojectsbyclient""bar""Projects per Client"500)
        fcprojectsbyclient.frappexaxismode = 
    "span"
        fcprojectsbyclient.frappeyaxismode = 
    "span"
        fcprojectsbyclient.frappeisseries = 
    True
        fcprojectsbyclient.frapperaiseeventonclick = 
    False
        fcprojectsbyclient.frappeisnavigable = 
    True
        fcprojectsbyclient.frappeshowsums = 
    False
        fcprojectsbyclient.frappeshowaverages = 
    False
        fcprojectsbyclient.frappelineshowdots = 
    True
        fcprojectsbyclient.frappelineheatline = 
    False
        fcprojectsbyclient.frappelineregionfill = 
    False
        fcprojectsbyclient.valuesoverpoints = 
    True
        
    Dim jSQL As SQL = ABMShared.SQLGet
        
    Dim recs As List = ABMShared.SQLExecuteMaps(jSQL, "select count(projects.id) as a,clients.clientname as x from projects inner join clients on clients.id = projects.clientid group by clients.clientname"Null)
        
    'extract the x axis values
        Dim xaxis As List = ABMShared.MapProperty2List(recs,"x")
        fcprojectsbyclient.FrappeLabels.AddAll(xaxis)
        
    'Draw each series
        Dim recsa As List = ABMShared.MapProperty2List(recs,"a")
        fcprojectsbyclient.AddDataSet(
    "Projects""blue", recsa, Array As String())
        ABMShared.SQLClose(jSQL)
        
    page.Cell(4,1).AddComponent(fcprojectsbyclient.ABMComp)
    There is code here to loop through each of the maps from ExecuteMaps and extract the provided property, in this case x and then a and return these are lists that are passed to the chart components for both the x axis and y axis values.

    Code:
    'extract map properties to a list
    Sub MapProperty2List(om As List,prop As StringAs List
        
    Dim lst As List: lst.initialize
        
    Dim mtot As Int = om.Size - 1
        
    Dim mcnt As Int = 0
        
    For mcnt = 0 To mtot
            
    Dim omm As Map = om.Get(mcnt)
            
    Dim strvalue As String = GetDefault(omm,prop,"")
            lst.Add(strvalue)
        
    Next
        
    Return lst
    End Sub
    Sub GetDefault(m As Map, prop As String, def As StringAs String
        prop = prop.tolowercase
        
    Return m.getdefault(prop,def)
    End Sub
     
    joulongleu likes this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice