ETA Dashboard
ETA Widget Code
Create a dashboard widget
<div class="container-fluid p-0">
<div class="row">
<div class="col-md-12">
<div class="mapdata" id="googleMapLocation" style="width:100%"></div>
</div>
<div class="col-md-12 mt-2">
<h5 class="pull-left">Total Records: <span class="totalCount"></span></h5>
<select class="form-control form-control-sm pull-right" id="geoFilter" placeholder="Select Geofence" onchange="loadGeoList()" style="width:200px;"></select>
<table id="geofenceTable" class="table table-bordered" cellspacing="0">
</table>
</div>
</div>
</div>
/********************************************
Pre Defined variables to access in the widget
********************************************/
// API_BASE_PATH - to get boodskap api base path
// DOMAIN_KEY - to get domain key
// API_KEY - to get api key
// API_TOKEN - to get api token
// MESSAGE_ID - to get message id
// DEVICE_ID - to get device id
// ASSET_ID - to get asset id
// RECORD_ID - to get record id
// WIDGET_ID - to get current widget id
// USER_ID - to get user id (In public share this will be empty)
var initialLng = 51.507351;
var initialLat = -0.127758;
var ZOOM_LEVEL = 5;
var DATE_TIME_FORMAT = 'MM/DD/YYYY hh:mm:ss A';
var record_size = 1000;
var AUTO_REFRESH_INTERVAL = 10; //Seconds
var DEVICE_ID_FIELD ='member';
var GEOFECNE_ID_FIELD ='destination';
var ETA_FIELD ='eta';
var LAT_FIELD ='latitude';
var LON_FIELD ='longitude';
var DISTANCE_FIELD ='distance';
var SORTING_FIELD = 'distance';
var SORTING_FIELD_INDEX = 4;
var drawingManager = null;
var geofenceTable = null;
var infowindow = null;
var locationMap = null;
var markerObj = null;
var infoWindow = null;
var geofence_list = [];
$(document).ready(function () {
getGoogleApiKey()
$("#googleMapLocation").css('height',$(window).height()/2)
});
// function loadGoefenceList() {
// var queryParams={
// "query": {
// "bool": {
// "must": [{
// "match": {
// "domainKey": DOMAIN_KEY
// }
// }]
// }
// },
// "size":record_size
// }
// var searchQuery = {
// "extraPath": "",
// "query": JSON.stringify(queryParams),
// "params": [],
// "type": "GEOFENCE"
// };
// searchByQuery(searchQuery, function (status, data) {
// if (status) {
// var result = searchQueryFormatter(data);
// //
// if (result.total > 0) {
// var resultData = result.data.data;
// } else {
// }
// } else {
// }
// });
// }
var allmarker = [];
function loadGoogleMap(resultdata) {
var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';
locationMap = new google.maps.Map(document.getElementById('googleMapLocation'), {
center: new google.maps.LatLng(initialLat,initialLng),
zoom: ZOOM_LEVEL,
});
var colorList = ['yellow','blue','red','green','orange','gray','purple','white','black','brown']
for(var j=0;j<resultdata.length;j++){
marker = new google.maps.Marker({
position: new google.maps.LatLng(resultdata[j][LAT_FIELD], resultdata[j][LON_FIELD]),
icon: 'http://labs.google.com/ridefinder/images/mm_20_'+colorList[j]+'.png',
map : locationMap
});
marker.setMap(locationMap);
locationMap.panTo(new google.maps.LatLng(resultdata[j][LAT_FIELD], resultdata[j][LON_FIELD]));
locationMap.setZoom(10)
const contentString =
'<div id="content">' +
'<div id="siteNotice">' +
"</div>" +
'<h5 id="firstHeading" class="firstHeading"><small>Estimate Time of Arrival (ETA)</small><br> '+moment(resultdata[j]).format(DATE_TIME_FORMAT)+'</h1>' +
'<div id="bodyContent">' +
"<p><small>Device Id</small><br>"+resultdata[j][DEVICE_ID_FIELD]+"</p>" +
"<p><small>Geofence Id</small><br>"+resultdata[j][GEOFECNE_ID_FIELD]+"</p>" +
"</div>" +
"</div>";
const infowindow = new google.maps.InfoWindow({
content: contentString,
});
marker.addListener("click", () => {
infowindow.open({
anchor: marker,
locationMap,
shouldFocus: false,
});
});
}
}
function searchByQuery(data, cbk) {
$.ajax({
url: API_BASE_PATH + "/elastic/search/query/" + API_TOKEN,
data: JSON.stringify(data),
contentType: "application/json",
type: 'POST',
success: function (data) {
//called when successful
cbk(true, data);
},
error: function (e) {
//called when there is an error
cbk(false, e);
}
});
}
// searchqueryformatter----------
function searchQueryFormatter(data) {
var resultObj = {
total: 0,
data: {},
aggregations: {}
};
if (data.httpCode === 200) {
var arrayData = JSON.parse(data.result);
var totalRecords = arrayData.hits.total.value;
var records = arrayData.hits.hits;
var aggregations = arrayData.aggregations ? arrayData.aggregations : {};
for (var i = 0; i < records.length; i++) {
records[i]['_source']['_id'] = records[i]['_id'];
}
resultObj = {
"total": totalRecords,
"data": {
"recordsTotal": totalRecords,
"recordsFiltered": totalRecords,
"data": _.pluck(records, '_source')
},
aggregations: aggregations
};
return resultObj;
} else {
return resultObj;
}
}
// api dynamic-------------------
function getGoogleApiKey(datas) {
$.ajax({
url: API_BASE_PATH + "/domain/property/get/" + API_TOKEN+"/google.map.key",
// ata: JSON.stringify(data),
contentType: "application/json",
type: 'GET',
success: function (data) {
//called when successful
var key=JSON.parse(data.value)
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src", "https://maps.googleapis.com/maps/api/js?key="+key.apiKey+"&callback=loadGeoList&libraries=drawing&v=weekly");
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
$("#geoFilter").html('<option value="">All Geofences</option>')
},
error: function (e) {
//called when there is an error
console.log(false, e);
}
});
}
function loadGeoList(){
const self = this;
if (geofenceTable) {
geofenceTable.destroy();
$("#geofenceTable").html("");
}
var fields = [
{
mData: DEVICE_ID_FIELD,
sTitle: 'Device Id',
orderable: false,
mRender: function(data, type, row) {
return data;
}
},
{
mData: GEOFECNE_ID_FIELD,
sTitle: 'Geofence Id',
orderable: false,
mRender: function(data, type, row) {
return data;
}
},
{
mData: LAT_FIELD,
sTitle: 'Latitude',
orderable: false,
mRender: function(data, type, row) {
var str ='<span class="">'+data+'</span>'
return str;
}
},
{
mData: LON_FIELD,
sTitle: 'Longitude',
orderable: false,
mRender: function(data, type, row) {
var str ='<span class="">'+data+'</span>'
return str;
}
},
{
mData: ETA_FIELD,
sTitle: 'ETA',
orderable: true,
mRender: function(data, type, row) {
return moment(data).format(DATE_TIME_FORMAT);
}
},
{
mData: DISTANCE_FIELD,
sTitle: 'Distance in KMs',
orderable: true,
mRender: function(data, type, row) {
return data/1000;
}
},
{
mData: SORTING_FIELD,
sTitle: 'Last Updated Time',
mRender: function(data, type, row) {
return moment(data).format(DATE_TIME_FORMAT);
}
}
];
var domainKeyJson = { "match": { "domainKey": DOMAIN_KEY } };
var queryParams = {
query: {
"bool": {
"must": [],
}
},
sort: [],
aggs:{
"geo":{
"terms":{
"field":GEOFECNE_ID_FIELD,
"size":100
}
}
}
};
var tableOption = {
"language": {
"processing": '<i class="fa fa-spinner fa-spin"></i> Processing',
"sLengthMenu": "Show _MENU_ records",
"info": "Showing _START_ to _END_ of _TOTAL_ records",
"infoFiltered": ""
},
responsive: true,
paging: true,
searching: false,
aaSorting: [
[SORTING_FIELD_INDEX, 'desc']
],
"ordering": true,
iDisplayLength: 5,
lengthMenu: [
[5, 10],
[5, 10]
],
aoColumns: fields,
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": API_BASE_PATH + '/elastic/search/query/' + API_TOKEN ,
"fnServerData": function(sSource, aoData, fnCallback, oSettings) {
var keyName = fields[oSettings.aaSorting[0][0]]
var sortingJson = {};
sortingJson[keyName['mData']] = { "order": oSettings.aaSorting[0][1] };
queryParams.sort = [sortingJson];
queryParams.query['bool']['must'] = [];
queryParams.query["bool"]["should"] = [];
delete queryParams.query["bool"]["minimum_should_match"];
queryParams['size'] = oSettings._iDisplayLength;
queryParams['from'] = oSettings._iDisplayStart;
var searchText = oSettings.oPreviousSearch.sSearch;
queryParams.query['bool']['must'].push(domainKeyJson);
if($("#geoFilter").val()){
queryParams.query.bool.must.push({match:{geofenceid:$("#geoFilter").val()}})
}
var ajaxObj = {
"method": "GET",
"extraPath": "",
"query": JSON.stringify(queryParams),
"params": [],
"specId":RECORD_ID,
"type": "RECORD"
};
oSettings.jqXHR = $.ajax({
"dataType": 'json',
"contentType": 'application/json',
"type": "POST",
"url": sSource,
"data": JSON.stringify(ajaxObj),
success: function (data) {
var fullObj = searchQueryFormatter(data);
var aggsObj = fullObj.aggregations.geo.buckets;
if($("#geoFilter").val() == ""){
for(var i =0;i<aggsObj.length;i++){
$("#geoFilter").append('<option value="'+aggsObj[i].key+'">'+aggsObj[i].key +' ('+aggsObj[i].doc_count+')</option>')
}
}
var resultData = fullObj.data;
geofence_list =resultData.data;
loadGoogleMap(resultData.data)
$('.totalCount').html(fullObj.total)
resultData['draw'] = oSettings.iDraw;
fnCallback(resultData);
}
});
}
};
geofenceTable = $("#geofenceTable").DataTable(tableOption);
}
// setInterval(function(){
// loadGeoList()
// }, AUTO_REFRESH_INTERVAL*1000);
.dataTable td{
font-size: 12px;
}
.dataTable th{
font-size: 13px;
font-weight: 500 !important;
color: #fff !important;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc {
background : none;
}
.dataTables_processing{
background: #fff !important;
/*height : 50px !important;*/
box-shadow: 1px 1px 4px #ccc;
}
.table_processing{
}
table.dataTable thead .sorting:after, table.dataTable thead .sorting_asc:after, table.dataTable thead .sorting_desc:after, table.dataTable thead .sorting_asc_disabled:after, table.dataTable thead .sorting_desc_disabled:after {
position: absolute;
bottom: 8px;
right: 8px;
display: block;
opacity: 0.5;
}
table.dataTable thead .sorting:after, table.dataTable thead .sorting_asc:after, table.dataTable thead .sorting_asc_disabled:after, table.dataTable thead .sorting_desc:after, table.dataTable thead .sorting_desc_disabled:after {
font-family: 'FontAwesome' !important;
font-weight: 900;
font-style: normal;
font-variant: normal;
text-rendering: auto;
}
table.dataTable thead .sorting_asc:after {
content: '\f0dd'!important;
}
table.dataTable thead .sorting_desc:after {
content: "\e156";
}
table.dataTable thead .sorting:after, table.dataTable thead .sorting_asc:after, table.dataTable thead .sorting_desc:after, table.dataTable thead .sorting_asc_disabled:after, table.dataTable thead .sorting_desc_disabled:after {
position: absolute;
/*bottom: 8px;*/
/*right: 8px;*/
display: block;
opacity: 0.5;
}
table.dataTable thead .sorting_desc:after {
content: '\f0de'!important;
}
table.dataTable thead .sorting:after {
content: '\f0dc'!important;
}
table thead tr{
background-color: #6d6d6d !important;
color: #fff !important;
}
.pagination .page-item.disabled>.page-link{
border: 0.001rem solid #e1e2e4 !important;
/*margin: 0 !important;*/
border-radius: 0 !important;
box-shadow: none;
background-color: #ffffff;
color: #424242;
opacity: 1;
text-transform: capitalize;
}
body div.dataTables_wrapper div.dataTables_paginate ul.pagination {
/*margin: 9px 0;*/
display: inline-block;
}
div.dataTables_wrapper div.dataTables_info {
/*margin: 8px 0;*/
}
div.dataTables_wrapper div.dataTables_paginate{
margin: 0 !important;
}
.paging_simple_numbers .pagination .paginate_button.active a, .paging_simple_numbers .pagination .paginate_button:hover a{
background-color: #6d6d6d !important;
border-radius: 0 !important;
/*margin: 0 !important;*/
box-shadow: none !important;
border-color: #6d6d6d !important;
}
div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child {
padding-left: 0;
margin: auto;
}
.unsort::before {
content: none !important;
}
.unsort::after {
content: none !important;
}
.table-bordered thead td, .table-bordered thead th{
/*border-bottom-width: 0px !important;*/
}
div.dataTables_wrapper div.dataTables_filter input{
border: 1px solid #e9ecef;
border-radius: 4px;
/*height: 34px;*/
/*width: 220px;*/
}
select.custom-select.custom-select-sm.form-control.form-control-sm {
border: 1px solid #dddddd !important;
background-color: #ffffff !important;
/*height: 34px !important;*/
border-radius: 4px;
}
table.table-bordered.dataTable tbody th, table.table-bordered.dataTable tbody td:focus{
outline: none !important;
}
.pagination > li > a{
border-radius : 0 !important;
}
div.dataTables_wrapper div.dataTables_paginate .pagination > li > a:hover{
margin: 0;
}
.dataTables_wrapper .dataTables_length {
float: left;
}
::-webkit-scrollbar {
width: 5px;
height:5px;
}
.over{
overflow:auto;
height:auto;
width:auto;
}
Sample Output
Updated over 3 years ago