Bayesean Blog - Desktop, Mobile and IOT Developer Blog


Delphi FMX Dashboard using Chart.JS

Posted on 8th Jan 2018 in Bootstrap 4, CSS


FMXdashboard12.png

Background

This is an update to this blog and includes a source code update from Bootstrap 3 to Bootstrap 4.  The older Bootstrap 3 code is still available for download.

When creating a clean Dashboard for your Application, as a developer your requirements would meet the following:

  • Be responsive.
  • Be professional with a clean look and feel.
  • To be gesture interactive.

Chart.js library provides all of this and can be incorporated into your Delphi FMX or VCL App for quick results. The Chart.js JavaScript library is an easy to use graph library which is responsive and gesture interactive in nature making for a professional result.

Dashboard.gif

IDE

Tokyo 10.2.3 is used, this should be backwards compatible to Berlin 10.1 version as it makes use of the newer updated browser which includes using the newish  ‘EvaluateJavaScript ‘ method.

Requirements

Standard FMX Library used and or the VCL Library.

ChartJS  Library.

Bootstrap 4  Uses the container-fluid class (the older code uses bootstrap 3).

Difficulty level:  An understanding of HTML, CSS and JavaScript will help.

Method

The TWebBrowser component serves as the Dashboard container for the Chart.JS library objects.

A HTML form (index.html) is added to the project.  The onshow event loads the html file into the browser. The Html file uses standard html code to call the external CSS and JavaScript files directly without any further developer intervention required and contains the html chart id’s to where the JavaScript will position the charts with the HTML.

So why not call the CSS or JS from the App without using HTML forms directly? Simply because it will not render the CSS or JS in the Web Browser due to how the Delphi Web Browser (wrapper) is wired. 

Including the JavaScript various charts script within your Application is the best way so as to:-

  • process fresh JavaScript script with a browser refresh.
    • Otherwise keeping the primary data in the html form and then updating the charts with fresh data by calling ‘Evaluatejavascript’, will result in the data being overlaid resulting in the two charts randomly showing incorrect information on gesture.
    • To fix this behaviour, we first need to clear the original data and refresh the browser with new data and it is easier to have different sets of data directly in your application.
  • make it easier to parse database information directly to the script.
    • For this Demo, this will be simulated by using two buttons to update the information instead of a receiving fresh data.

How does the Demo Work

The ‘Oncreate’ method will load the html file directly into the web browser.

Using the ‘OnShow’ method, the TTimer component is called to delay loading the JavaScript code by 200 milliseconds or else an error will be experienced.

//The timer interval is set to 200 milliseconds
procedure TForm4.Timer1Timer(Sender: TObject);
begin
   timer1.enabled:= false;
    webbrowserstart;
end;

Calling the procedure webbrowserstart will load the JavaScript Donut and Bar-chart  to be positioned at the html map ID’s in the index.html by using the JavaScript document.getElementById() function. The Delphi  Evaluatetojavascript call is made and the browser is updated with the Javascript code. The browser is immediately refreshed with two charts.

These are the id’s found in the index.html file and is wrapped in the Bootstrap Container-Fluid Class making the form responsive.

<canvas id="doughnut-chart" width="200" height="200"></canvas>
</div>
<div class="col-xs-6 ">
<canvas id="mixed-chart" width="200" height="200"></canvas>

To simulate the data, chart  background colors and the labels a procedure for each chart is created.

The webbrowserstart  procedure  calls the GetDoughnutDetail() and the Get MixedchartDetail() and the Delphi variables are added to the Javascript variables. This largely simulates the Database.

Lets see the code below…

procedure TForm4.GetdoughnutDetail(var clabels,cbackgroundcolor,cdata:string);
begin
 clabels:= '["Upstairs", "Outside", "Bedroom3", "Garage", "Dining Room"],';
cbackgroundColor:= '["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"], ';
cdata:='[89,300,5,10,100]';
end;

procedure TForm4.GetmixedchartDetail(var mlabels, mdata1, mdata2,
  mabackgroundcolor, madata, mbbackgroundcolor2, mbdata: string);
begin
  mlabels:= ' ["Bedroom", "Bathroom", "Study","Lounge"], ';
  mdata1:=  '[250,140,270,100],';
  mdata2:=  '[830,520,620,380],';
  mabackgroundcolor:= '';
  madata:=  '';
  mbbackgroundcolor2:=  '';
  mbdata:=     '';
 end;

 

procedure TForm4.webbrowserstart;
var
clabels,cbackgroundcolor,cdata,mlabels, mdata1, mdata2,mdata3,mdata4 :string;
updategraph:string;
begin
 clabels:= '["Upstairs", "Outside", "Bedroom3", "Garage", "Dining Room"],';
 cbackgroundColor:= '["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"], ';
 cdata:='[890,200,500,100,1000]';
 mlabels:= ' ["Dining Room", "Bedroom", "Garage","Stoep"], ';
 mdata1:=  '[200,140,70,1000],';
 mdata2:=  '[800,720,1220,3800],';

updategraph :=
'new Chart(document.getElementById("doughnut-chart"), {'
+'    type: "doughnut",'
+'    data: {'
+'      labels: '+clabels
+'      datasets: ['
+'        { '
 +'         label: "Rooms",'
 +'         backgroundColor:' +cbackgroundcolor
 +'         data: ' +cdata
 +'       } '
+'      ]  '
 +'   },  '
 +'   options: {   '
 +'     legend: { display: false },  '
 +'     title: {   '
 +'       display: "True",  '
 +'       text: "Total Assets Value"   '
 +'     }  '
 +'   }  '
+'});'

+'new Chart(document.getElementById("mixed-chart"), {  '
 +'   type: "bar",              '
 +'  data: {                    '
 +'     labels: '+ mlabels
+'      datasets: [{            '
+'          label: "Purchased",   '
+'          type: "line",        '
+'          borderColor: "#8e5ea2",   '
+'          data: '+mdata1
+'          fill: false   '
+'        }, {       '
+'          label: "Disposed",    '
+'          type: "line",        '
+'          borderColor: "#3e95cd",    '
+'          data:' +mdata2
+'         fill: false   '
+'        }, {         '
+'          label: "Purchased",  '
+'          type: "bar",        '
 +'         backgroundColor: "rgba(0,120,5,0.2)", '
 +'         data: '+mdata1
+'        }, {                       '
+'          label: "Disposed",       '
+'          type: "bar",         '
+'          backgroundColor: "rgba(0,30,220,0.2)", '
+'          backgroundColorHover: "#3e95cd",    '
+'         data: '+ mdata2
+'        }           '
+'      ]           '
+'    },            '
+'    options: {     '
 +'     title: {     '
+'        display: true, '
+'        text: "Purchased & Disposed Assets"  '
+'      },       '
+'      legend: { display: false }  '
+'    }     '
+'});   '
  ;
  WebBrowser1.EvaluateJavaScript(updategraph);
end;

Whilst this demo only used two Buttons to simulate changing data, calling fast changing data would be easily implemented by replacing the buttons with a single timer that would refresh the Web Browser Dashboard in real-time.

On each button call, the browser is refreshed by reloading the index.html form then a 200 millisecond delay followed by a call to load the JavaScript into the browser.

As can be seen showing how the browser views the Chart objects, they are automatically responsive in nature. So compiling to Android and Windows requires no changes on your part and as the Dashboard code is rendered in the browser component, this in affect makes your application lighter and faster by nature. By using a JavaScript library can create really great looking charts and with a little tweaking you can have a very professional looking responsive Dashboard.

This app will compile to Android (tested) and IOS. Follow the procedure to compile and deploy the App to your device.

Feel free to download the full source for this demo.

Licence MIT

 

Download Code

 Happy Coding


Dan      Commented   2 years ago Reply

Hi, helpful tutorial. Set me in the right direction. What about a countdown in seconds. Your does not seem to work with real time.

admin      Replied    Moderator   2 years agoReply


Yes you are correct. It was designed to delay the download with a count down. Herewith is some code for a 20 second countdown with integrated Bootstrap progress- bar... <pre> <div class = "hidden" id="countdown"> </div> <script type="text/javascript">  window.onload = function() { var countdownElement = document.getElementById('countdown'), seconds = 20, second = 0, interval; interval = setInterval(function() { var varinfo =''; countdownElement.firstChild.data = 'You can start your download in ' + (seconds - second) + ' seconds'; varinfo = 'You can start your download in ' + (seconds - second) + ' seconds'; width = (100 /seconds) *(seconds -(seconds-second)); document.getElementById("progress-bar").style.width=width+"%"; document.getElementById("progress-bar").innerHTML =varinfo ; if (second >= seconds) { $("#myId").removeClass("hidden"); $("#myimg").removeClass("hidden"); var varinfo2 = " Click Download Button to Download the File"; document.getElementById("progress-bar").innerHTML =varinfo2; clearinterval(Id); clearInterval(interval); } second++; }, 1000); } </script> </pre>

admin      Replied    Moderator   2 years agoReply


The code is not easily readable - copy and paste in your editor and it should clean up. I will create a small blog on this and provide the full code for download as I am sure others would like to know how to do this.

Add a Comment

9+5

Recent News

Delphi Delimited String to Fields
Delphi A Professional VCL DBGrid Part Four
Delphi A Professional VCL DBGrid Part Three
Delphi A Professional VCL DBGrid Part Two
Delphi A Professional VCL DBGrid Part One
Delphi VCL Buttons in DBGrid
Two Helper Apps for Delphi LibUSB
Delphi Libusb Library Introduction

Categories

Bootstrap 4
Delphi VCL
Delphi FMX
Ajax
Bootstrap 3
CSS
XE4>Delphi > XE4
Delphi < XE4
PHP

Archives

August 2019

Delphi Delimited String to Fields

June 2019

Delphi A Professional VCL DBGrid Part Four

May 2019

Delphi A Professional VCL DBGrid Part Three

April 2019

Delphi A Professional VCL DBGrid Part Two

March 2019

Delphi A Professional VCL DBGrid Part One

November 2018

Delphi VCL Buttons in DBGrid

October 2018

Two Helper Apps for Delphi LibUSB

September 2018

Delphi Libusb Library Introduction

August 2018

Delphi Object directly to a Json string in a REST Client
Delphi using Environment Variables in your App

July 2018

Delphi FMX Leaflet Plotter using OSM Maps

June 2018

C2PAS32 Convertor Application
C to Delphi Open Source Convertors Shootout
Delphi command-line programs with DOSCommand

May 2018

Delphi PDF Embedded viewer with PDF.js

March 2018

Delphi FMX - Changing TCharacter to TCharHelper
Make Your Delphi App POP using Javascript!

January 2018

Delphi FMX Dashboard using Chart.JS
Delphi FMX Form Docking

December 2017

PHP Slim REST Server & Delphi Auth Part 5

November 2017

Delphi FMX REST Client App Part 4

October 2017

Delphi VCL REST Pricing Client App Part 3

September 2017

Delphi REST VCL Client Basic Auth Part 2B

August 2017

Delphi REST Client Part 2A
PHP PDO REST Server Part 1

July 2017

PHP REST Server and Delphi Client Intro

June 2017

Delphi SQLite Encryptor-Decryptor Tool
Updating Applications Manifest using Delphi

May 2017

Create a Visual IP Address Geolocation with PHP

March 2017

PHP Downloader using Countdown timer
PHP File Downloader from a Inbox Selection

February 2017

Javascript Image-File Uploader with ThumbViewer

January 2017

Morris Charts and PHP-PDO

December 2016

CSS to create a functional Toggle Button