Integrating 3rd Party Libraries

Explains how to integrate 3rd Party Libraries into View Widgets.

How to use High Charts in View Widgets

The 'demo project' has a sample vscode project for integrating High Charts libraries into the View Widgets.

  1. Create a new VS Code project with all the pre-requisites
  2. Install the below required in the development machine
    1. 📘

      Node - Node

    2. 📘

      Npm - Make sure npm is installed in the system - npm

    3. 📘

      Make sure that Type Script compiler is installed Type Script Compiler

  3. Develop a new custom widget as mentioned in the link Developing Widgets
  4. Install High Charts node module in the VS code project High Charts npm install and make sure that installation is successful
  5. In the VS code project create a new folder named 'common'
  6. And create a new file 'highcharts.mdw.json' and refer the highcharts.js file path from the High Charts installation location
    {
       "Name": "High Charts",
       "Category": "3rd party libraries",
       "Class": "[highcharts]",
       "Sources": ["$/../lib/Highcharts-10.3.3/code/highcharts.js"],
    	"IsBrowsable": false
    }
  7. Create a new file 'common.mdw.json' and add required dependencies as below.
{
   "Name": "Demo Project",
   "Category": "Demo Project",
   "Class": "[demo project sources]",
	"Dependencies": ["$/highcharts.mdw.json"],
   "Sources": ["$/../dist/main.js"],
	"IsBrowsable": false
}
  1. Now create a typescript for HighCharts common functionality in typescript. Please check the below code for the same. Export this below code as a type script module and use it in the widget code.

    import { cClassBase } from "client/classbase";
    import { JS } from "client/common";
    import { IManualEvent } from "client/events";
    import { cDateTime } from "client/time";
    
    // It was not trivial (enough) to obtain Highcharts typings (d.ts)
    // - so these were created to help with TypeScript
    
    /** Highcharts types for convenience */
    export interface IHighcharts
    {
    	chart(element_id: string, configuration: IHighchartsConfig): TChart;
    }
    /** Highcharts configuration options */
    export interface IHighchartsConfig
    {
    	chart: {
    		type: string
    	},
    	title: {
    		text: string
    	},
    	xAxis: {
    	},
    	yAxis: {
    		title: {
    			text: string
    		}
    	},
    	series: IHighchartsSerie[]
    }
    /** Highcharts series item */
    export interface IHighchartsSerie
    {
    	name: string,
    	data: unknown[],
    	time: unknown[],
    	status: string[]
    }
    /** TODO: the return type */
    type TChart = unknown;
    
    
    //Helper for checking the Highcharts availability
    class HighchartsProvider extends cClassBase
    {
    	private highcharts: IHighcharts;
    	constructor()
    	{
    		super();
    		//Unfortunately Highcharts is "lazy" to load
    		const check = () =>
    		{
    			//This checker polls until the global "Highcharts" can be found and triggers the Ready event
    			const highcharts = JS.API("Highcharts");
    			if(highcharts)
    			{
    				this.highcharts = highcharts as IHighcharts;
    				this.Ready.Fire(this.highcharts);
    			}
    			else setTimeout(check, 100);
    		}
    		check();
    	}
    	/**Highcharts loaded*/
    	public Ready: IManualEvent<IHighcharts> = this.Events.AddManual("Ready");
    }
    /**Handle for waiting for highcharts to load */
    export const HighchartsLoaded: HighchartsProvider = new HighchartsProvider();
    
  2. Now import the above module in the custom widget development code and render the data. Below example explains the usage of the above type script module. The variable 'seriesData' is of type called 'IHighchartsSerie[]' which was created in the earlier created module.

    private renderChart(element: HTMLElement, seriesData: IHighchartsSerie[]) {
            if (seriesData) {
                HighchartsLoaded.Ready.Then((Highcharts: IHighcharts) => {
                    // Create a unique id for the chart (it seems multiple renders work better with each having unique id)
                    const container_id: string = "highcharts_5";
    
                    // Create a container in the widget parent element for the chart
                    // See main.css for highchart_container CSS class
                    element.innerHTML = `<div class='highchart_container' id='${container_id}'>`;
                    try {
                        // Create a Highcharts chart
                        // NOTE: Perhaps it is not necessary to always create a new chart!
                        // (It may be possible to use the same chart object and re-configure it)
                        const chart = Highcharts.chart(container_id, {
                            chart: {
                                type: this.chartType.toLowerCase()
                            },
                            title: {
                                text: this.equipmentClassName + "_" + this.instanceName
                            },
                            xAxis: {
                                // x:Date(),
                                // type: 'datetime',
                                //categories: this.categories // (produced in fetchData)
                            },
                            yAxis: {
                                title: {
                                    text: "Values" // Use YAxisTitle property value
                                }
                            },
                            series: seriesData // (produced in fetchData)
                        });
                    }
                    catch (err: unknown) {// Sometimes Highcharts crashes for some unknown reason
                        console.error(err);
                    }
                });
            }
            else {
                console.log("Can not render the chart as chart data is not fetched");
            }
        }