In order to get the application working correctly, the document body
needs 4 main elements:
div
element to display the Maptable
element to display the Data Tablescript
element to include the Google Maps Libraryscript
element for all of the code needed to fetch and process data.
The first 2 elements need to have a unique id
for the JavaScript selectors to point to the correct
elements.
The table
element should have both the thead
and tbody
sections that will be populated through the code.
The first script
element that include the Google Maps Library will require an API key to from the Google
Developer Console. You can find more information about Google Maps API Keys here.
The last script
element is where all of the code will go to fetch and process the data from IIR API. For
the sake of this demo, the script will be included in the main HTML document.
<html> <head> <title>IIR API Demo</title> </head> <body> <div id="demo-map"></div> <table id="demo-table"> <thead></thead> <tbody></tbody> </table> <script src="https://maps.googleapis.com/maps/api/js?key=[YOUR_API_KEY]"></script> <script> // The magic goes here </script> </body> </html>
The Google map function will draw the map in the element with the id demo-map
with the
defined center and zoom properties that result in a global view. You can find complete documentation of the Google Maps
Initialization here.
var map = new google.maps.Map(document.getElementById('demo-map'), { center: { lat: 26.422, lng: -14.921 }, zoom: 1, zoomControl: true, mapTypeControl: false, scaleControl: false, streetViewControl: false, rotateControl: false, fullscreenControl: false, }); var table = document.getElementById('demo-table');
To make a successful API call, the following 3 items are required:
bearer token
to authorize the API callAPI endpoint
of a specific data setquery parameters
to identify a subset of the data
The bearer token
is required for all API calls. It is passed with the headers: Authorization
prameter. To generate or learn more about IIR Bearer tokens, take a look at the documentation here.
This example is going to query the offlineevents/summary
endpoint to get a list of summarized offline events based on the query parameters
sent to the endpoint.
The query parameters
for NGL Fractionator Shutdowns include the following four:
eventKind=S
eventStatusDesc=Ongoing
unitTypeID=00203
industryCode=04
fetch()
is used to make a POST
request to the defined offlineEventsURL
endpoint.
When the fetch()
completes its call, it returns a response
to the .then()
method
which will convert the response
to JSON
and pass it to the next method.
The last .then()
method in the chain then calls displayTableData()
first to display the offline events table data.
Also, the next method processPlantData()
would then be used to retrieve plant data while looping through offlinve event records. (see
3. Process Plant Data)
// API variables var bearerToken = 'YOUR_BEARER_TOKEN', offlineEventsUrl = 'https://apitest.industrialinfo.com/idb/v2/offlineevents/summary?', offlineQueryParameters = 'eventKind=S&eventStatusDesc=Ongoing&unitTypeId=00203&industryCode=04'; function getOfflineEventData () { //Use ES6 Fetch API fetch(offlineEventsURL + offlineQueryParameters, { method: 'POST', headers: { Authorization: 'Bearer ' + bearerToken, }, 'Content-Type': 'application/json', }) .then((response) => { return response.json() }) .then((json) => { displayTableData(json.offlineEvents); processPlantData(json.offlineEvents); //see 3.1 Making the Second API Call }) }
Now that the data has returned from the first fetch
call, the resulting JSON has 2 main sections:
The top level summary has information such as the totla result count, the returned result count, and the offset (used for pagination).
For this example, the list of data is all that will be used. Each API endpoint will have a different parameter for the returned data set.
Since Offline Events was requested, the parameter is offlineEvents
.
In the code provided, a new variable
is added to identify the Data Table element and a new function
called displayTableData
is added to process the data and display
in the table. It expects 1 parameter to be supplied: data
This function adds a table row (tr
) with table header cells (th
) to the inside of the empty thead
of the table element.
Then, the function loops through the JSON data using forEach
and adds table rows (tr
) with
table data cells (td
) to the inside of the empty tbody
of the table element.
The tbody
loop uses template literals
to access the information in each object
of the returned dataset, eg: ${event.unitName}
.
{ "limit": 100, "offset": 0, "resultCount": 3, "totalCount": 3, "offlineEvents": [ { "eventType": "Unplanned", "unitId": 2084883, "unitName": "Mont Belvieu MB-3L", "plantId": 3078786, "offlineCapacity": { "productId": "010098", "productDesc": "Mechanical Output", "unitCapacity": 10, "capacityOffline": 10, "uom": "MW" }, .... }, {...}, {...} ]
function displayTableData(data) { // add table head row table.tHead.innerHTML = ` <tr> <th>Unit Name</th> <th>Unit ID</th> <th>Offline Capacity</th> <th>Event Type</th> </tr>`; // add table body rows table.tBodies[0].innerHTML = ''; //loop through each offline event record data.forEach((event) => { table.tBodies[0].innerHTML += ` <tr> <td>${event.unitName}</td> <td>${event.unitId}</td> <td>${event.offlineCapacity.capacityOffline} ${event.offlineCapacity.uom}</td> <td>${event.eventType}</td> </tr>`; }); }
Same as the first API call, the following 3 items are required: the bearer token
, an
API endpoint
and a set of query parameters
Two new functions
are added. The first one, extractPlantIDs()
, is used to create an array of unique plant IDs
based on a the data set provided to it. The second one, processPlantData()
, preforms similar to the processOfflineEventData()
function above.
extractPlantIDs(data)
would build a url parameter string for plantId such as "plantId=3026102&plantId=1007868&plantId=1027431&plantId=3038621" and then joined with plantDetailsUrl
.
// API variables var plantDetailsUrl = 'https://apitest.industrialinfo.com/idb/v2/plants/detail?'; function extractPlantIDs(data) { return [ ...new Set( data.map((result) => { return result.plantId }) ), ] } function processPlantData (data) { var plantIdQueryString = 'plantId=' + data.join('&plantId=') fetch(plantDetailsURL + plantIdQueryString, { method: 'POST', headers: { Authorization: 'Bearer ' + bearerToken, }, 'Content-Type': 'application/json', }) .then((response) => { return response.json() }) .then((json) => { displayPlantData(json.plants); }); }
The final step of this example is to process and display the returned plant data on the map.
With this latest API endpoint, notice that the parameter for the returned data set has changed.
Since Plants was requested, the parameter is now plants
.
In the code provided, a new function called displayPlantData
is added to process the data and display
the markers. It expects 1 parameter to be supplied: data
The displayPlantData()
function loops through the returned plant data using forEach
and creates
a Google Maps Marker on the map with an accompanying InfoWindow bound together with a click listener
.
Follow these links for more information on Google Maps Markers
and InfoWindows.
The displayPlantData()
function gets called at the end of the final .then()
method of
processPlantData()
function to keep the order of operations intact.
{ "limit": 50, "offset": 0, "resultCount": 1, "totalCount": 1, "plants": [ { "plantId": 1000012, "plantName": "Houston Sulfuric Acid", "plantStatusDesc": "Operational", "longitude": -95.26879, "latitude": 29.720048, ... } ] }
function displayPlantData (data) { data.forEach((plant) => { var marker = new google.maps.Marker({ position: { lat: plant.latitude, lng: plant.longitude }, map: map, title: plant.plantName }); var infowindow = new google.maps.InfoWindow({ content: plant.plantName }); marker.addListener('click', () => { infowindow.open(map, marker); }); }); }
<html> <head> <title>IIR API Demo</title> </head> <body> <div id="demo-map"></div> <table id="demo-table"> <thead></thead> <tbody></tbody> </table> <script src="https://maps.googleapis.com/maps/api/js?key=[YOUR_API_KEY]"></script> <script> // API variables var bearerToken = 'YOUR_BEARER_TOKEN'; var offlineEventsUrl = 'https://api.industrialinfo.com/idb/v2/offlineevents/summary?'; var offlineQueryParameters = 'eventKind=S&eventStatusDesc=Ongoing&unitTypeId=00203&industryCode=04'; var plantDetailsUrl = 'https://api.industrialinfo.com/idb/v2/plants/detail?'; // UI variables var map = new google.maps.Map(document.getElementById('demo-map'), { center: { lat: 26.422, lng: -14.921 }, zoom: 1, zoomControl: true, mapTypeControl: false, scaleControl: false, streetViewControl: false, rotateControl: false, fullscreenControl: false, }); var table = document.getElementById('demo-table'); function processOfflineEventData() { fetch(offlineEventsURL, { method: 'POST', headers: { Authorization: 'Bearer ' + bearerToken, }, 'Content-Type': 'application/json', }) .then((response) => { return response.json() }) .then((json) => { displayTableData(json.offlineEvents) processPlantData(extractPlantIDs(json.offlineEvents)) }) } function displayTableData(data) { // add table head row table.tHead.innerHTML = ` <tr> <th>Unit Name</th> <th>Unit ID</th> <th>Offline Capacity</th> <th>Event Type</th> </tr>`; // add table body rows table.tBodies[0].innerHTML = ''; data.forEach((event) => { table.tBodies[0].innerHTML += ` <tr> <td>${event.unitName}</td> <td>${event.unitId}</td> <td>${event.offlineCapacity.capacityOffline} ${event.offlineCapacity.uom}</td> <td>${event.eventType}</td> </tr>`; }); } function extractPlantIDs(data) { return [ ...new Set( data.map((result) => { return result.plantId }) ), ] } function processPlantData(data) { var plantIdQueryString = 'plantId=' + data.join('&plantId='); fetch(plantDetailsURL + plantIdQueryString, { method: 'POST', headers: { Authorization: 'Bearer ' + bearerToken, }, 'Content-Type': 'application/json', }) .then((response) => { return response.json() }) .then((json) => { displayMapData(json.plants) }) } function displayMapData(data) { data.forEach((plant) => { var marker = new google.maps.Marker({ position: { lat: plant.latitude, lng: plant.longitude }, map: map, title: plant.plantName, }); var infowindow = new google.maps.InfoWindow({ content: plant.plantName, }); marker.addListener('click', () => { infowindow.open(map, marker) }) }) } processOfflineEventData(); </script> </body> </html>