Onesait platform has a very powerful and flexible dashboard system for data representation. In this tutorial, you will create a dashboard that allows you to see the high customization degree, the power of connection and interaction with the data and the development speed .
To do this once inside the onesait platform, go to the Display> Dashboard Management menu, where you can create a new dashboard.
Dashboard creation and initial configuration:
To create a dashboard, go to its creation page and fill in the basic fields of identification, description, image, whether it is public or not, category and subcategory. The dashboard has a number of properties that will allow you to configure its operation. These are:
Para crear un dashboard, iremos a su página de creación y rellenaremos los campos básicos de identificación, descripción, imagen, si es público o no, categoría y subcategoría. El dashboard tiene una serie de propiedades que nos permitirán configurar su funcionamiento, estas son:
- Initial Dashboard Style (type):
Allows you to choose an initial dashboard style that configures not only its style and behavior, but also a number of JavaScript and CSS libraries that can be loaded at the dashboard's start. These initial styles can be pre-created in the general management of the console by Administrator users, to have a library of dashboard types where you can choose the style and the initial libraries that the dashboard will load. This management (initial dashboard styles) has been recently added to the onesait functionalities:
- Global Styles, Libraries and Scripts:
Allows you to load here a number of JS and CSS files to be used later in the dashboard. These are designed to load third-party plugins or UX styles according to each project, or JavaScript controllers with the logic of certain template gadgets to structure, organize and optimize the code in the dashboards. These files and settings are just what can be previously saved in dashboard style management, which we have talked about in the initial Dashboard style.
In this dashboard that you are going to create, youwill use a series of JS libraries and styles to use in several components such as the horizontal slider, the progress bars or the Datatable table. These files are the libraries of these plugins and their styles:
Permite cargar aquí una serie de archivos JS, CSS para poder ser luego utilizados en el dashboard, pensado para cargar plugins de terceros o estilos de UX acorde a cada proyecto, o controladores JavaScript con la lógica de ciertos gadgets template para estructurar, organizar y optimizar el código de los dashboards. Estos archivos y configuración es justamente lo que puede guardarse previamente en la gestión de estilos de dashboard, de la que hemos hablado en el estilo inicial del Dashboard.
En este dashboard que vamos a crear vamos a usar una serie de librerías JS y estilos para usar en varios componentes como el slider horizontal, o las barras de progreso, o la tabla Datatable, estos archivos son las librerías de estos plugins y los estilos de los mismos:
<meta http-equiv="Cache-control" content="public"> <!-- common styles --> <link href="https://lab.onesaitplatform.com/web/enel/assets/app/css/style.bundle.css" rel="stylesheet" type="text/css" /> <link href="https://lab.onesaitplatform.com/web/enel/assets/vendors/base/vendors.bundle.css" rel="stylesheet" type="text/css" /> <link href="https://lab.onesaitplatform.com/web/enel/assets/app/css/style.override.css" rel="stylesheet" type="text/css" /> <link href="https://lab.onesaitplatform.com/web/enel/assets/vendors/base/soho.css" rel="stylesheet" type="text/css" /> <link href="https://lab.onesaitplatform.com/web/enel/assets/app/css/jquery-confirm.min.css" rel="stylesheet" type="text/css" /> <link href="https://lab.onesaitplatform.com/web/enel/assets/vendors/datatables/datatables.bundle.css" rel="stylesheet" type="text/css" /> <!-- custom gadget template styles --> <link href="https://lab.onesaitplatform.com/web/enel/assets/app/css/gadgetTemplate.css" rel="stylesheet" type="text/css" />
Next, you will also load the additional JavaScript files for the plugins you will use:
<!-- common scripts --> <script src="https://lab.onesaitplatform.com/web/enel/assets/vendors/base/vendors.bundle.js"></script> <script src="https://lab.onesaitplatform.com/web/enel/assets/app/js/scripts.bundle.js"></script> <script src="https://lab.onesaitplatform.com/web/enel/assets/app/js/jquery-confirm.min.js"></script> <script src="https://lab.onesaitplatform.com/web/enel/assets/vendors/datatables/datatables.bundle.js"></script> <script src="https://cdn.jsdelivr.net/gh/wmh/jquery-scrollbox@1.4.2/jquery.scrollbox.min.js"></script> <!-- Gadget template controller --> <script src="https://lab.onesaitplatform.com/web/enel/assets/app/js/ENEL_Controller.js"></script> <!-- additional angular directives --> <script defer="defer" src="https://unpkg.com/angularjs-gauge@2.2.0/dist/angularjs-gauge.min.js"></script>
Finally, still in this section of the dashboard configuration, you will enter a code to dynamically load AngularJS directives. This is very useful, since a part of the Dashboads engine is implemented on Angular:
<script> // DYNAMIC LOADING OF ANGULAR DIRECTIVES window.addEventListener('DOMContentLoaded', function() { window.setTimeout( function(){ angular.element(document.getElementsByTagName('body')[0]).injector().loadNewModules(['angularjs-gauge']) },0 ); }); </script>
Dashboard Construction:
When building a dashboard, you must bear in mind several things: the dashboard's structure or layout and the components that you will include, which will be described in the dashboard's WIREFRAME. The other key element when building a dashboard is data. Data will give life to the dashboard's visual components and you must know what data they are, either DATASOURCES or API, and what filters or behaviors they have with each other, which will be describe in the dashboard's DATA COMMUNICATION.
Wireframe:
Just like in the Web design, a layout or an initial design is made to have a clear structure of the page. A dashboard is exactly the same, you need to know what information is going to be represented and how to define the spaces, the dashboard structure and the components that you'll need. Let's see these examples in the dashboard that you are going to build:
With this information, you can get an idea of the structure by knowing the proportions the zones will have, then, through the gadget wireframe, you get an idea of what visualization elements you are going to place in each zone to represent the information, and finally, to help the programmers and the dashboard's programming, you can also see the plugins that you will be using in each of the zones. Whether you are going to build a dashboard of a single gadget template with all these programmed elements, or you are going to use N gadgets distributed throughout the different zones, these functional design elements are always a reference, allowing to save a lot of time and above all maintainability of the same dashboard.
The resulting dashboard will look like this, although we still have to see how the data will be connected, and how gadgets interact with each other to filter the information:
Data Communication:
Once you have a clear idea about the dashboard structure (layout) and the visual elements (gadgets) that you are going to use to represent the information, you clearly need the Data to be represented. There are two ways to bring data from the platform to the dashboard: API (REST) and Datasources. Usually, due to power, data transformation and query optimization, we will use Datasources (advanced SQL query via webSocket with configuration, transformation, paging and filtering capabilities).
Just as it is important to be clear about the visual structure, it is equally or more important to know what data you are going to need, how is this data structured, and most importantly, how they are orchestrated with each other. That is to say, usually you are going to load 1 or several gadgets with their datasources, and you are also going to load multiple datasources in other gadgets templates. The important thing is also to know how the gadgets filter each other, giving life and power to the Dashboard. Let's see below the data schemas of this Dashboard:
With this information, you can quickly see the correlation between zones, gadgets and data sources (DS Datasources) directly with the first image. The second and third image show something that happens a lot in dashboards and that, in the case of multi-datasources, happens: Multiple data loading processes depending on the interaction with its components. In this example you can see that you have 4 datasources, 1 for each zone, and two loading processes, 1 the initial one, which is called "All" and initially loads the Datasource of Zone 1 DS_Planta and is triggered with the arrival of data from of the 2nd Datasource, DS_Centrales, that in turn triggers the load of the 3rd and 4th Datasources DS_Production and DS_Aeros, since they depend on the Plant, and the plant in turn depends on the Plant. The code that allows this fantastic interaction is:
// load datasources filtering by central console.log('LOAD DATASOURCE DS_CENTRALES: ' + filter); // vm.getDataFromDataSource('DATASOURCE_ID', CALLBACK FUNCTION TO TX DATA, [{FILTERS}...{}]) vm.getDataFromDataSource('DS_UNITS_CENTRALES', vm.callbackCentral, [{field:'CENTRAL',op:'=',exp: filter}]);
In this way, in the code of a gadget template, you can load a Datasource programmatically. Remember that if you only need one, you can link it to the gadget directly from its edition; but in this case you will want to load several ones. The best way to do this is as follows: Create a function with all possible cases "All", "Central", ... as a load dispatcher, depending on the filters sent either between gadgets, or between the value sending function, vm.sendValue() or the filter sending function vm.sendFilter() filters. They will receive these filter values and act by launching the synchronized load of all or some of the necessary datasources.
From there, using the callBack functions that the datasources loading system possesses, you will process the information or simply update it directly in the display gadgets.
/** Datasources loader */ vm.loadDatasources = function(category, filter){ //... // FILTER DISPATCHER switch(category){ case "month": // load datasources filter by month and year console.log('LOAD DATASOURCES BY MONTH'); break; case "central": console.log('LOAD DATASOURCES BY CENTRAL: ' + filter); vm.getDataFromDataSource('DS_CENTRALES', vm.DS_CentralesCallBack, [{field:'CENTRAL',op:'=',exp: filter}]); vm.getDataFromDataSource('DS_AEROS', vm.DS_AerosCallBack, [{field:'CENTRAL',op:'=',exp: filter}]); break; case "graph": // load datasources of production graph with selected interval, adding month and year, and central too, console.log('LOAD DATASOURCES BY MONTH,CENTRAL AND GRAPH...'); break; case "aero": // load aero datasources filter by month and year and central console.log('LOAD DATASOURCES BY MONTH,CENTRAL AND AERO...'); break; case "all": // initial loading of datasources console.log('LOAD DATASOURCES ALL , INIT CASE'); vm.getDataFromDataSource('DS_PLANTA', vm.DS_PlantaCallBack, [{field:'PLANTA',op:'=',exp:filter}]); break; } //... // See one CallBack function. /** Datasource DS_Planta callback Function */ vm.DS_PlantaCallBack = function( data ){ // set data vm.indicators = JSON.parse(data); // variable directamente enlaza con la visualización console.log('Indicators data: ' + vm.indicators); // load the related datasources, AEROS and PRODUCTION depends on central data. // for AEROS, we filter by PLANT and from central selection we can filter both production and aeros. vm.getDataFromDataSource('DS_AEROS', vm.DS_AerosCallBack ,[{field:'CENTRAL',op:'=',exp: vm.centrals[0].CENTRAL}]); // set current Central vm.currentCentral = vm.centrals[0].CENTRAL; vm.currentCentralName = vm.centrals[0].NOMBRE_CENTRAL; // for production we mount initially last 24hours for the first Central Available let now = moment().toISOString(); let last24h = moment(now).subtract(24, 'hour').toISOString(); vm.getDataFromDataSource('DS_PRODUCCION', vm.DS_ProduccionCallBack, [{field:'CENTRAL',op:'=',exp:vm.centrals[0].CENTRAL},{field: 'FECHA', op: '>=' , exp: "TIMESTAMP('"+ last24h +"')"},{field: 'FECHA', op: '<=' , exp: "TIMESTAMP('"+ now +"')"}]); // do animations setTimeout(function(){ ENEL_Controller.animateCounters('','countIndicators'); ENEL_Controller.animateProgressBars('','progressIndicators'); }, 50) };
Finally, program each of the cases. That is why it's important having the connection and filtering schemes of gadgets; and with that you can get all the interaction between components and the optimized loading of their data.