1086 lines
45 KiB
JavaScript
1086 lines
45 KiB
JavaScript
var map = null; // Our map instance
|
|
var marker_layer = null; // Our markers layer
|
|
var ZKL_Markers = new Array(); // The associative array with ZKL markers. Key is the ZKL serial#/DBID, value is an OpenLayers.Marker object.
|
|
var KML_layer = null; // Our KML layer
|
|
var vehyb = null;
|
|
var vestr = null;
|
|
var osm = null;
|
|
var bNeedRecenter = false; // Need a re-center of the map?
|
|
|
|
var DeviceTypesVisible = new Array(); // Array containing device type visibility (true/false)
|
|
var DevTypesToNames_transtbl = new Array(); // Array containing the mapping from device types (type_XX) to a name (string)
|
|
|
|
var mapviewcontrol; // reference to mapview control
|
|
var DebugEnabled = 0;
|
|
|
|
var IconLib = new Array(); // Array holding size of different icons
|
|
var TcpTimeout = 3000; // Stored at definitions.php
|
|
|
|
|
|
/*
|
|
* IE6 workaround
|
|
*/
|
|
if (typeof(is_IE6) != "undefined") {
|
|
OpenLayers.Util.alphaHack = function() { return false; }
|
|
}
|
|
|
|
|
|
/*
|
|
* A better typeof() function.
|
|
*/
|
|
function ol_TypeOf(value) {
|
|
// First check to see if the value is undefined.
|
|
if (value == undefined) {
|
|
return "undefined";
|
|
}
|
|
// Check for objects created with the "new" keyword.
|
|
if (value instanceof Object) {
|
|
// Check for a boolean object.
|
|
if (value instanceof Boolean) {
|
|
return "boolean";
|
|
// Check for a number object.
|
|
} else if (value instanceof Number) {
|
|
// Test whether it's a float or int.
|
|
if (/\./.test(value)) {
|
|
return "float";
|
|
} else {
|
|
return "int";
|
|
}
|
|
// Check whether it's a string object.
|
|
} else if (value instanceof String) {
|
|
return "string";
|
|
// Check whether it's an array object/array literal.
|
|
} else if (value instanceof Array) {
|
|
return "array";
|
|
// Check whether it's a date object.
|
|
} else if (value instanceof Date) {
|
|
return "date";
|
|
// Check whether it's a function object.
|
|
} else if(value instanceof Function) {
|
|
return "function";
|
|
// Check whether it's and object object/object literal.
|
|
} else if (value instanceof Object ) {
|
|
return "object";
|
|
}
|
|
// If these tests failed, check to see if we're
|
|
// dealing with a literal.
|
|
} else if (typeof value) {
|
|
// Here we're testing for null. Get this,
|
|
// JavaScript returns it as an object!
|
|
// So first we check for object, then for value.
|
|
if (typeof value == "object") {
|
|
if (typeof value == "object" && !value) {
|
|
return "null";
|
|
}
|
|
// If the value wasn't null, check if it is a literal.
|
|
} else {
|
|
// Check for a boolean literal.
|
|
if (typeof value == "boolean") {
|
|
return "boolean";
|
|
// Check for a number literal.
|
|
} else if (typeof value == "number") {
|
|
// Check if the number literal is a float or int.
|
|
if (/\./.test(value)) {
|
|
return "float";
|
|
} else {
|
|
return "int";
|
|
}
|
|
// Check if it's a string literal.
|
|
} else if (typeof value == "string") {
|
|
return "string";
|
|
}
|
|
}
|
|
// If it slipped through all these tests,
|
|
// we're dealing with something undetectable.
|
|
// Therefore return nothing.
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Debug function: dump some text to our browser window in the 'debugwindow' div.
|
|
*/
|
|
function DbgPrint(dbgtext) {
|
|
// Only show debuginfo debug mode active
|
|
if (DebugEnabled > 0) {
|
|
dbgtext = typeof(dbgtext) == 'string' ? dbgtext : toString(dbgtext);
|
|
try {
|
|
getElement("debugwindow").innerHTML += (dbgtext+"<br>");
|
|
}
|
|
catch (ex) { /* Silent exception */ }
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This callback is called when a popup needs closing.
|
|
* We find the correct marker, and destroy the appropriate popup.
|
|
*/
|
|
function ol_ClosePopupCallback() {
|
|
ZKL_Markers[this.PopupID].popup.hide();
|
|
}
|
|
|
|
/*
|
|
* Create a new popup for ZKL with serial number 'serialnr'.
|
|
* If one already existed, remove it and create a new one
|
|
*/
|
|
function ol_CreatePopup(serialnr) {
|
|
if (ZKL_Markers[serialnr]) {
|
|
var PopupHTML;
|
|
var IconType;
|
|
// Called with a valid serial?
|
|
if (typeof(ZKL_Markers[serialnr]) == 'undefined') {
|
|
DbgPrint ("ol_CreatePopup called with invalid serial "+serialnr);
|
|
return;
|
|
}
|
|
// Do we have user defined popup content for this popup? If so, use it.
|
|
if (typeof(ZKL_Markers[serialnr].s_popupHTML) != 'undefined') {
|
|
PopupHTML = ZKL_Markers[serialnr].s_popupHTML;
|
|
}
|
|
else {
|
|
|
|
// No user defined content specified. Create the popup content. First: spit out a nice header
|
|
PopupHTML = '<p class="popup_hdr">'+StatusTranslationTable['s_idcode']+" "+ZKL_Markers[serialnr]['s_idcode']+'</p>'+
|
|
'<table class="popup_bodytbl">';
|
|
|
|
// Get icon (ok/nok/error/etc.)
|
|
IconType = ZKL_Markers[serialnr]['s_icon'];
|
|
|
|
// Walk through all the status parameters, map them through a translation table, and put them in table rows
|
|
for (x in ZKL_Markers[serialnr]) {
|
|
// ZKL parameters start with an 's_'
|
|
if (x.substring(0,2) == 's_') {
|
|
// Do not render the serialnr; we already did that.
|
|
// Also, don't render parameters such as s_icon.
|
|
if (x != 's_serialnr' && x != 's_icon' && x != 's_idcode' && x != 's_devtype' && x != 's_icon_info' && x != 's_visible') {
|
|
if (ZKL_Markers[serialnr][x] != null) {
|
|
// No connection => text = popup color
|
|
var tdclass = (IconType == "error") ? "popup_cell_nocon" : "popup_cell_normal";
|
|
|
|
// Fetch the translations from the translation table.
|
|
// If we don't have a translation, use the value as-is.
|
|
var key = String((typeof(StatusTranslationTable[x]) != 'undefined') ? StatusTranslationTable[x] : x);
|
|
if( key.indexOf('%s') != -1 ) {
|
|
key = key.replace(/\%s/g, ZKL_Markers[serialnr]['nm_' + x.substring(2)]);
|
|
}
|
|
var val = ZKL_Markers[serialnr][x];
|
|
if (val.substring(0,1) == '!') {
|
|
// Normal display, or error-red display? If there is an exclamation mark, make it an error.
|
|
val = val.substring(1,val.length);
|
|
// No connection => text = popup color
|
|
tdclass = (IconType == "error") ? "popup_cell_nocon" : "popup_cell_error";
|
|
}
|
|
// Translate the text
|
|
val = String((typeof(StatusTranslationTable[val]) != 'undefined') ? StatusTranslationTable[val] : (val.substr(0, 1).toUpperCase() + val.substr(1)));
|
|
// And add it to the popup.
|
|
PopupHTML += ('<tr class="popup_row"><td class="'+tdclass+'">'+key+' </td><td class="'+tdclass+'">'+val+'</td></tr>');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Add the closing tags
|
|
PopupHTML += '</table>';
|
|
}
|
|
// Existing popup?
|
|
if (ZKL_Markers[serialnr].popup != null) {
|
|
// Popup already exists?
|
|
ZKL_Markers[serialnr].popup.lonlat = ZKL_Markers[serialnr].lonlat;
|
|
ZKL_Markers[serialnr].popup.setContentHTML(PopupHTML);
|
|
}
|
|
else {
|
|
// Create popup
|
|
ZKL_Markers[serialnr].popup = new OpenLayers.Popup.FramedCloud(serialnr,
|
|
ZKL_Markers[serialnr].lonlat,
|
|
null,
|
|
PopupHTML,
|
|
ZKL_Markers[serialnr].icon,
|
|
true,
|
|
ol_ClosePopupCallback
|
|
);
|
|
// Add the popup to the map!
|
|
marker_layer.map.addPopup(ZKL_Markers[serialnr].popup);
|
|
}
|
|
|
|
// Assign an ID so we can relate to this popup when an event occurs
|
|
ZKL_Markers[serialnr].popup.PopupID = serialnr;
|
|
// Disable autosizer and autopanner
|
|
ZKL_Markers[serialnr].popup.contentDisplayClass = 'popup';
|
|
ZKL_Markers[serialnr].popup.autoSize = true;
|
|
ZKL_Markers[serialnr].popup.panMapIfOutOfView = false;
|
|
ZKL_Markers[serialnr].popup.keepInMap = false;
|
|
// Show popup
|
|
ZKL_Markers[serialnr].popup.show();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The event handler for a click on a marker: display popup.
|
|
*/
|
|
function ol_MarkerClickEvent(evt) {
|
|
// Create popup
|
|
ol_CreatePopup(evt.object.s_serialnr);
|
|
|
|
// End this event
|
|
OpenLayers.Event.stop(evt);
|
|
}
|
|
|
|
/*
|
|
* The event handler for a mouseover on a marker: change cursor type
|
|
*/
|
|
function ol_MarkerMouseOverEvent(evt) {
|
|
// Adapt cursor
|
|
document.body.style.cursor='pointer';
|
|
|
|
// End of event
|
|
OpenLayers.Event.stop(evt);
|
|
}
|
|
|
|
/*
|
|
* The event handler for a mouse out on a marker: change cursor type
|
|
*/
|
|
function ol_MarkerMouseOutEvent(evt) {
|
|
// Adapt cursor
|
|
document.body.style.cursor='auto';
|
|
|
|
// End of event
|
|
OpenLayers.Event.stop(evt);
|
|
}
|
|
|
|
/*
|
|
* The event handler for a double click on a marker: zoom in.
|
|
*/
|
|
function ol_MarkerDblClickEvent(evt) {
|
|
// Set map center & zoom
|
|
ol_CenterItem(evt.object.s_serialnr);
|
|
|
|
// End this event
|
|
OpenLayers.Event.stop(evt);
|
|
}
|
|
|
|
/*
|
|
* Center the map around a marker with the given ID
|
|
*/
|
|
function ol_CenterItem(MarkerID) {
|
|
var index = 0;
|
|
var redraw = false;
|
|
|
|
if (ZKL_Markers[MarkerID]) {
|
|
if (ZKL_Markers[MarkerID].bIsUsed) {
|
|
// Recenter only when visible
|
|
if (!ZKL_Markers[MarkerID].bHidden) {
|
|
var NewCenter = new OpenLayers.LonLat(ZKL_Markers[MarkerID].ip_Lon, ZKL_Markers[MarkerID].ip_Lat);
|
|
map.setCenter(NewCenter.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()), map.numZoomLevels-1);
|
|
}
|
|
for (x in ZKL_Markers) {
|
|
// Reset 'tracking' status for all markers
|
|
if (ZKL_Markers[x].bIsUsed) {
|
|
ZKL_Markers[x].ip_bTracking = false;
|
|
}
|
|
// Define new devIndex
|
|
if (DeviceTypesVisible[ZKL_Markers[x].s_devtype] == true || ZKL_Markers[x].s_icon == "nok") {
|
|
// Index already visible?
|
|
if (x == MarkerID) {
|
|
if ((index < mapviewcontrol.devIndex) || ((index >= mapviewcontrol.devIndex) && (index - mapviewcontrol.devIndex) >= mapviewcontrol.devVisible)) {
|
|
if ((index + mapviewcontrol.devVisible) > mapviewcontrol.devMaxIndex) {
|
|
mapviewcontrol.devIndex = mapviewcontrol.devMaxIndex - mapviewcontrol.devVisible;
|
|
}
|
|
else {
|
|
mapviewcontrol.devIndex = index;
|
|
}
|
|
|
|
// Redraw mapview control
|
|
redraw = true;
|
|
}
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the mapview control
|
|
if (redraw) {
|
|
mapviewcontrol.forceRedraw();
|
|
}
|
|
else {
|
|
mapviewcontrol.updateDevices();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create or clone an icon.
|
|
* Pass the icon type (e.g. 'ok' for OK) and device type (e.g. type_0 for ZKL3000) to this function.
|
|
* If the icon is already loaded, we clone it. If not, we load a bitmap named <icon_id>.png and create the icon
|
|
*
|
|
* Return: OpenLayers.Icon object with the requested icon if it exists, or the default diamond-like OpenLayers icon
|
|
* when not.
|
|
*/
|
|
function ol_CreateIcon(icon_type, devtype) {
|
|
// Define output format
|
|
var output = 'png';
|
|
if (typeof(is_IE6) != "undefined") {
|
|
output = 'gif';
|
|
}
|
|
|
|
if (typeof(icon_type) == 'undefined') {
|
|
return;
|
|
}
|
|
|
|
if (typeof(devtype) == 'undefined') {
|
|
devtype = '0';
|
|
}
|
|
|
|
// remove a leading 'type_' from devtype, when applicable.
|
|
if (devtype.substring(0,5) == 'type_') {
|
|
devtype = devtype.substring(5,devtype.length);
|
|
}
|
|
|
|
// Build the icon ID
|
|
icon_id = '&dev_type=' + devtype + '&' + icon_type;
|
|
|
|
// Skip rtremark & idcode & warning
|
|
// This makes the icons less unique while the size is the same (so xmlhttp request less because of known image size)
|
|
|
|
// Find &idcode=<*>&
|
|
icon_id = icon_id.replace(/&idcode=.*&/gi, '&idcode&');
|
|
// Find &idcode=<*>EOL
|
|
icon_id = icon_id.replace(/&idcode=.*/gi, '&idcode');
|
|
|
|
// Find &rtremark=<*>&
|
|
icon_id = icon_id.replace(/&rtremark=.*&/gi, '&rtremark&');
|
|
// Find &rtremark=<*>EOL
|
|
icon_id = icon_id.replace(/&rtremark=.*/gi, '&rtremark');
|
|
|
|
// Find &warning=<*>&
|
|
icon_id = icon_id.replace(/&warning=.*&/gi, '&warning&');
|
|
// Find &warning=<*>EOL
|
|
icon_id = icon_id.replace(/&warning=.*/gi, '&warning');
|
|
|
|
// See if the icon was already loaded
|
|
if (typeof(IconLib[icon_id]) == 'undefined') {
|
|
DbgPrint ("Icon with ID "+icon_id+" is not yet available. Loading and creating...");
|
|
// load image width/height
|
|
var IconSizeCode = xmlhttp_data('include/db_icon.php', '', 0, '', '', '', '&device='+devtype+'&icon='+icon_type+'&action=jssize');
|
|
|
|
// Check if this is valid iconsize code for us
|
|
if (IconSizeCode.substring(0,15) == '//iconsize_v1.0') {
|
|
// eval() it. After this, we have a JS array named 'iconsize'
|
|
eval (IconSizeCode);
|
|
|
|
DbgPrint ("Icon size fetched from server ("+iconsize[0]+","+iconsize[1]+")\n");
|
|
}
|
|
else {
|
|
// Default
|
|
iconsize = new Array(40,20);
|
|
DbgPrint ("Icon size fetch failed. Assuming ("+iconsize[0]+","+iconsize[1]+")\n");
|
|
}
|
|
|
|
// Store values
|
|
IconLib[icon_id] = iconsize;
|
|
}
|
|
|
|
// Create new icon
|
|
var size = new OpenLayers.Size(IconLib[icon_id][0], IconLib[icon_id][1]);
|
|
var offset = new OpenLayers.Pixel(-Math.round(IconLib[icon_id][0]/2), -Math.round(IconLib[icon_id][1]/2));
|
|
|
|
// Debug info
|
|
DbgPrint ('include/db_icon.php?device='+devtype+'&icon='+icon_type+'&output='+output);
|
|
|
|
return new OpenLayers.Icon('include/db_icon.php?device='+devtype+'&icon='+icon_type+'&output='+output, size, offset);
|
|
}
|
|
|
|
|
|
/**
|
|
* Update the marker layer on the map view with the items in the object passed.
|
|
* This object should have the following format:
|
|
*
|
|
* ItemArray[0] --+
|
|
* +-- ItemInstance[0] --+
|
|
* | +-- position (required: postion on the map)
|
|
* | +-- s_serialnr (required: item's serial number)
|
|
* | +-- s_gps (optional: GPS position for display)
|
|
* | +-- s_icon (required: icon identifier)
|
|
* | +-- s_visible (required: icon visible)
|
|
* | +-- s_icon_info (required: icon identifier&idcode&rtremark)
|
|
* | +-- s_devtype (required: device type. e.g. zkl, trt, etc.)
|
|
* | +-- s_popupHTML (optional: if you want to generate your own popup HTML, put it here. This overrides the default popup renderer)
|
|
* | +-- s_optional1 (optional: parameter will be displayed in popup.
|
|
* | +-- s_optional2
|
|
* | +-- s_optionalX
|
|
* | +-- nm_serialnr (required: translated string "serial number")
|
|
* | .. (etc)
|
|
* | +-- nm_optionalX
|
|
* |
|
|
* +-- ItemInstance[1] --+
|
|
* | +-- s_serialnr
|
|
* | ..
|
|
* | +-- s_optionalX
|
|
* |
|
|
* +-- ItemInstance[n] --+
|
|
* +-- s_serialnr
|
|
* ..
|
|
* +-- s_optionalX
|
|
*
|
|
*
|
|
* In a future expansion, more entries in ItemArray will be allowed so movement paths of items
|
|
* can be displayed etc. But currently, only the data in ItemArray[0] is rendered to the map view
|
|
*
|
|
* Parameters can also indicate whether the value is OK or not OK. In the latter case the parameter will be shown in red.
|
|
* To indicate a parameter which is not OK, start the parameter value with an '!'.
|
|
* Example: ('s_batt1':'!Empty') would display a battery 1 status parameter in red.
|
|
*
|
|
* Note: Use common sense when using this feature. Obviously it doesn't make sense to make the serial numer 'invalid'. The
|
|
* code won't check it.
|
|
*/
|
|
function mapview_UpdateItems(ItemArray) {
|
|
// Get current date
|
|
var current = new Date();
|
|
var hidemessage = 1;
|
|
|
|
// We only use ItemArray[0] at this moment. Pull the information the quick and dirty way.
|
|
// Also, see if we have a valid serial and IDcode. We might get empty results from the server due to
|
|
// prematurely terminated server script etc.
|
|
CurrItem = new Array();
|
|
for (x in ItemArray[0]) {
|
|
var Serial = parseInt(ItemArray[0][x].s_serialnr);
|
|
DbgPrint ("Serial="+ItemArray[0][x].s_serialnr+"\n");
|
|
|
|
if ((Serial > 0) && (ItemArray[0][x].s_idcode.length > 0)) {
|
|
CurrItem.push(ItemArray[0][x]);
|
|
}
|
|
}
|
|
// First step: mark all markers as 'not used'. This allows us to throw away unused markers later on.
|
|
for (x in ZKL_Markers) {
|
|
if (ZKL_Markers[x]) {
|
|
ZKL_Markers[x].bIsUsed = false;
|
|
}
|
|
}
|
|
|
|
// Walk through all objects in CurrItem, and parse them
|
|
var bIsChanged, SerialNr;
|
|
var bHaveNew = false;
|
|
bMapControlUpdate = false;
|
|
bMapControlRedraw = false;
|
|
// Reset device type/name containers
|
|
// Walk over the incoming data
|
|
for (x in CurrItem) {
|
|
// The serial number is used to index the arrays.
|
|
SerialNr = CurrItem[x].s_serialnr;
|
|
|
|
// Create/update entry in devtype -> devname translation table.
|
|
DevTypesToNames_transtbl[CurrItem[x].s_devtype] = CurrItem[x].s_devname;
|
|
// Add device type to visibility-array if it does not exist yet
|
|
if (typeof(DeviceTypesVisible[CurrItem[x].s_devtype]) != "boolean") {
|
|
// default visibility is 'true' (visible).
|
|
DeviceTypesVisible[CurrItem[x].s_devtype] = true;
|
|
DbgPrint ("Added devtype "+CurrItem[x].s_devtype+" to visibility array\n");
|
|
}
|
|
|
|
// Store variables (visibility/icon info)
|
|
CurrItem[x].s_icon_info = CurrItem[x].s_icon;
|
|
var offset = CurrItem[x].s_icon.search("&idcode");
|
|
if (offset != -1) {
|
|
CurrItem[x].s_icon = CurrItem[x].s_icon.substring(0, offset);
|
|
}
|
|
offset = CurrItem[x].s_icon.search("&warning");
|
|
if (offset != -1) {
|
|
CurrItem[x].s_icon = CurrItem[x].s_icon.substring(0, offset);
|
|
}
|
|
|
|
CurrItem[x].s_visible = (DeviceTypesVisible[CurrItem[x].s_devtype] == true || CurrItem[x].s_icon == "nok") ? true : false;
|
|
|
|
// Extract GPS lat and lon coords. Remove starting '!' if applicable.
|
|
var stringLat;
|
|
var stringLon;
|
|
if(typeof(CurrItem[x].position) != "undefined") {
|
|
comma = CurrItem[x].position.indexOf(",");
|
|
stringLat = CurrItem[x].position.substr(0, comma);
|
|
stringLon = CurrItem[x].position.substr(comma + 1);
|
|
}
|
|
|
|
Lon = parseFloat(stringLon);
|
|
Lat = parseFloat(stringLat);
|
|
|
|
// Default coordinates when GPS is invalid!!
|
|
if (typeof(Lon)!="number" || typeof(Lat)!="number") {
|
|
DbgPrint ("mapview_UpdateItems ERROR: Invalid lat or lon (lon="+stringLon+" lat="+CurrItem[x].s_lat+")");
|
|
DbgPrint ("typeof(Lon)="+ol_TypeOf(Lon)+" typeof(Lat)="+ol_TypeOf(Lat));
|
|
// An error occurred. Place the device at DI headquarters to avoid JS errors
|
|
Lon = 5.163956;
|
|
Lat = 51.6087;
|
|
}
|
|
|
|
// Store these numbers for future use as internal parameter.
|
|
CurrItem[x].ip_Lon = Lon;
|
|
CurrItem[x].ip_Lat = Lat;
|
|
|
|
// Initial values
|
|
bIsChanged = false;
|
|
bNeedRecenter = false;
|
|
|
|
// See if a marker for this ZKL instance exists. Use the serialnr as the key.
|
|
// If not, create a marker and add it to the layer.
|
|
if (ZKL_Markers[SerialNr] == null) {
|
|
DbgPrint ('New ZKL with serial# '+SerialNr+' found. Adding to view');
|
|
// new marker position
|
|
var point = new OpenLayers.LonLat(Lon,Lat);
|
|
|
|
// Get point projection
|
|
point = point.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
|
|
|
|
// Create marker
|
|
var icon = ol_CreateIcon(CurrItem[x].s_icon_info,CurrItem[x].s_devtype);
|
|
ZKL_Markers[SerialNr] = new OpenLayers.Marker(point, icon.clone());
|
|
|
|
// Store original size
|
|
ZKL_Markers[SerialNr].originalSize = icon.size;
|
|
|
|
// Destroy icon
|
|
icon.destroy();
|
|
|
|
// Store visibility
|
|
ZKL_Markers[SerialNr].s_visible = false;
|
|
ZKL_Markers[SerialNr].bHidden = false;
|
|
|
|
// create popup holder
|
|
ZKL_Markers[SerialNr].popup = null;
|
|
|
|
// Add mouse events
|
|
ZKL_Markers[SerialNr].events.register("click", ZKL_Markers[SerialNr], ol_MarkerClickEvent);
|
|
ZKL_Markers[SerialNr].events.register("dblclick", ZKL_Markers[SerialNr], ol_MarkerDblClickEvent);
|
|
ZKL_Markers[SerialNr].events.register("mouseover", ZKL_Markers[SerialNr], ol_MarkerMouseOverEvent);
|
|
ZKL_Markers[SerialNr].events.register("mouseout", ZKL_Markers[SerialNr], ol_MarkerMouseOutEvent);
|
|
|
|
// Store lonlat/icon info (prevent update)
|
|
ZKL_Markers[SerialNr].lonlat = point;
|
|
ZKL_Markers[SerialNr].s_icon_info = CurrItem[x].s_icon_info;
|
|
|
|
// Add marker to marker map
|
|
marker_layer.addMarker(ZKL_Markers[SerialNr]);
|
|
|
|
// Indicate that we have added a new ZKL instance. This is used later for centering/zooming the map view
|
|
bHaveNew = true;
|
|
|
|
// New ZKL instance => update mapview control
|
|
bMapControlRedraw = true;
|
|
|
|
// Heartbeat unhandled
|
|
ZKL_Markers[SerialNr].hbhandled = 0;
|
|
ZKL_Markers[SerialNr].hbtimeout = new Date();
|
|
|
|
// Rest of init is done by the changed event
|
|
bIsChanged = true;
|
|
}
|
|
|
|
// Now walk over all the status items in the ZKL object, update them, see if they are changed
|
|
var CopyScript = ' ';
|
|
for (i in CurrItem[x]) {
|
|
// Extra check to see if this is indeed a valid status parameter
|
|
if (i.substring(0,2) == 's_' || i.substring(0,3) == 'ip_' || i.substring(0,3) == 'nm_') {
|
|
// Add this status parameter to the copy script
|
|
CopyScript += 'ZKL_Markers[SerialNr].'+i+'=CurrItem[x].'+i+';';
|
|
if (CurrItem[x][i] != ZKL_Markers[SerialNr][i]) {
|
|
DbgPrint('ZKL with serial number '+SerialNr+': parameter '+i+' has changed to '+CurrItem[x][i]);
|
|
// indicate that something has changed
|
|
bIsChanged = true;
|
|
// See if a change in this parameter needs to trigger a popup or re-center.
|
|
// We need a re-center when the icon changes from 'nonexistent' to something else'
|
|
// Mapcontrol redraw automatically updated by recenter
|
|
if (i=='s_icon' && CurrItem[x][i]!='nok' && ZKL_Markers[SerialNr][i]=='nok') {
|
|
DbgPrint ("Contact with "+SerialNr+" restored. Re-centering...");
|
|
bNeedRecenter = true;
|
|
}
|
|
// See if we need to update the mapcontrol
|
|
// Find changes in s_idcode and s_icon, visibility is handled by mapview_control itself
|
|
if ((i == 's_idcode') || (i == 's_icon')) {
|
|
bMapControlUpdate = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extra CopyScript additions to carry over information in the existing marker
|
|
CopyScript = CopyScript+'ZKL_Markers[SerialNr].ip_bTracking = '+ZKL_Markers[SerialNr].ip_bTracking;
|
|
|
|
// And, was there a change? or unhandled heartbeat check
|
|
if ((bIsChanged) || (ZKL_Markers[SerialNr].hbhandled == 0)) {
|
|
// (re)create the marker/position
|
|
var point = new OpenLayers.LonLat(CurrItem[x].ip_Lon,CurrItem[x].ip_Lat);
|
|
|
|
// Get point projection
|
|
point = point.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
|
|
|
|
// New icon?
|
|
if (CurrItem[x].s_icon_info != ZKL_Markers[SerialNr].s_icon_info) {
|
|
// Get new icon from library
|
|
var icon = ol_CreateIcon(CurrItem[x].s_icon_info, CurrItem[x].s_devtype);
|
|
ZKL_Markers[SerialNr].icon.setSize(icon.size);
|
|
ZKL_Markers[SerialNr].setUrl(icon.url);
|
|
ZKL_Markers[SerialNr].icon.offset = icon.offset;
|
|
|
|
// Store original size
|
|
ZKL_Markers[SerialNr].originalSize = icon.size;
|
|
|
|
// Destroy icon
|
|
icon.destroy();
|
|
}
|
|
|
|
// New coordinate?
|
|
if (point != ZKL_Markers[SerialNr].lonlat) {
|
|
ZKL_Markers[SerialNr].lonlat = point;
|
|
ZKL_Markers[SerialNr].icon.lonlat = point;
|
|
}
|
|
|
|
// Remove old data parameters
|
|
var RemoveKeys = new Array();
|
|
for (y in ZKL_Markers[SerialNr]) {
|
|
// ZKL parameters start with an 's_'
|
|
if (y.substring(0,2) == 's_') {
|
|
RemoveKeys.push(y);
|
|
}
|
|
}
|
|
|
|
for (y in RemoveKeys) {
|
|
delete(ZKL_Markers[SerialNr][RemoveKeys[y]]);
|
|
}
|
|
|
|
// Store marker info (Copy from CurrItem => ZKL_Markers)
|
|
eval(CopyScript);
|
|
|
|
// Waiting for heartbeat?
|
|
if ((ZKL_Markers[SerialNr].hbhandled == 1) || (ZKL_Markers[SerialNr].s_icon != 'error') || ((current.getTime() - ZKL_Markers[SerialNr].hbtimeout.getTime()) >= TcpTimeout)) {
|
|
// Set flag
|
|
ZKL_Markers[SerialNr].hbhandled = 1;
|
|
}
|
|
else {
|
|
// Still displaying message
|
|
hidemessage = 0;
|
|
}
|
|
|
|
// Set marker visibility
|
|
ZKL_Markers[SerialNr].display(CurrItem[x].s_visible && !ZKL_Markers[SerialNr].bHidden && ZKL_Markers[SerialNr].hbhandled);
|
|
|
|
// Hide popup
|
|
if (!CurrItem[x].s_visible || ZKL_Markers[SerialNr].bHidden) {
|
|
if (ZKL_Markers[SerialNr].popup != null) {
|
|
ZKL_Markers[SerialNr].popup.hide();
|
|
}
|
|
}
|
|
else {
|
|
// If there was a popup, recreate it
|
|
if (ZKL_Markers[SerialNr].popup != null) {
|
|
if (ZKL_Markers[SerialNr].popup.visible()) {
|
|
// Copy the parameter data into the marker and show?
|
|
ol_CreatePopup(SerialNr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the state of this marker to 'used'
|
|
ZKL_Markers[SerialNr].bIsUsed = true;
|
|
}
|
|
|
|
// Cleanup stage. All markers which are still 'not used' may be thrown away.
|
|
// Also, if we're tracking, set a flag.
|
|
for (x in ZKL_Markers) {
|
|
if (ZKL_Markers[x]) {
|
|
if (!ZKL_Markers[x].bIsUsed) {
|
|
// ZKL instance deleted => update mapview control
|
|
bMapControlRedraw = true;
|
|
|
|
// Try to remove popup
|
|
try {
|
|
marker_layer.map.removePopup(ZKL_Markers[x].popup);
|
|
ZKL_Markers[x].popup.destroy();
|
|
ZKL_Markers[x].popup = null;
|
|
}
|
|
catch (err) {}
|
|
DbgPrint ('Marker '+x+' is not in use anymore. Killing the marker..');
|
|
// Marker is not in use anymore.
|
|
// step 1: remove marker from the map
|
|
marker_layer.removeMarker(ZKL_Markers[x]);
|
|
// step 2: destroy the marker itself
|
|
ZKL_Markers[x].events.destroy();
|
|
ZKL_Markers[x].destroy();
|
|
// step 3: remove it from our array (BvH note: splice() went wrong; setting to null is a workaround)
|
|
delete(ZKL_Markers[x]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Re-sort array
|
|
if (bHaveNew) {
|
|
// Sort devices
|
|
var backup = ZKL_Markers;
|
|
var temp = new Array();
|
|
|
|
// Collect all idcodes
|
|
for (x in backup) {
|
|
temp.push(backup[x].s_idcode);
|
|
}
|
|
|
|
// Sort all devices
|
|
temp.sort();
|
|
|
|
// Clear array
|
|
ZKL_Markers = new Array();
|
|
|
|
// Refill array
|
|
for (y in temp) {
|
|
for (x in backup) {
|
|
if (temp[y] == backup[x].s_idcode) {
|
|
ZKL_Markers[x] = backup[x];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort device types
|
|
DevTypesToNames_transtbl = sortAssoc(DevTypesToNames_transtbl);
|
|
|
|
// Create backup
|
|
backup = DeviceTypesVisible;
|
|
temp = new Array();
|
|
|
|
// Clear array
|
|
DeviceTypesVisible = new Array();
|
|
|
|
// Refill marker array
|
|
for (y in DevTypesToNames_transtbl) {
|
|
for (x in backup) {
|
|
if (y == x) {
|
|
DeviceTypesVisible[y] = backup[x];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// When a ZKL intance was added to the list, calculate the extents of the ZKL instances and try
|
|
// to fit them neatly on the map. Also when changed from 'ok' to 'nok'
|
|
if (bHaveNew || bNeedRecenter) {
|
|
ol_RecenterMap();
|
|
}
|
|
else {
|
|
// No need to recenter, but some of the devices we're tracking may be off the map.
|
|
// Check this too.
|
|
ol_RecenterTracked();
|
|
}
|
|
|
|
// Update/redraw the mapview control
|
|
if (bMapControlRedraw) {
|
|
mapviewcontrol.forceRedraw();
|
|
}
|
|
else if (bMapControlUpdate) {
|
|
mapviewcontrol.updateDevices();
|
|
}
|
|
|
|
// Display message
|
|
if (hidemessage) {
|
|
HideWaitingMessage();
|
|
}
|
|
else {
|
|
ShowWaitingMessage();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Center & zoom map so that all devices are visible
|
|
*/
|
|
function ol_RecenterMap(Redraw) {
|
|
// Devices available?
|
|
var DevAvailable = false;
|
|
// The bounds of the tracked devices
|
|
var TrackedDevicesBounds = new OpenLayers.Bounds();
|
|
for (x in ZKL_Markers) {
|
|
if (ZKL_Markers[x]) {
|
|
// Markers visibible?
|
|
if (ZKL_Markers[x].s_visible && !ZKL_Markers[x].bHidden) {
|
|
// Device found
|
|
DevAvailable = true;
|
|
// Add this device to the bounding box around all tracking markers
|
|
var MarkerLonLat = new OpenLayers.LonLat(ZKL_Markers[x].ip_Lon,ZKL_Markers[x].ip_Lat);
|
|
TrackedDevicesBounds.extend(MarkerLonLat.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DevAvailable) {
|
|
// Recenter and zoom map in sich a way that all tracked markers are visible.
|
|
TrackedDevicesBounds.toBBOX();
|
|
map.zoomToExtent(TrackedDevicesBounds, false);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Center & zoom map so that all tracked devices are visible
|
|
*/
|
|
function ol_RecenterTracked() {
|
|
// Are there devices invisible?
|
|
var bDevicesInvisible = false;
|
|
// The bounds of the tracked devices
|
|
var TrackedDevicesBounds = new OpenLayers.Bounds();
|
|
for (x in ZKL_Markers) {
|
|
if (ZKL_Markers[x]) {
|
|
if (ZKL_Markers[x].bIsUsed && ZKL_Markers[x].ip_bTracking && ZKL_Markers[x].s_visible && !ZKL_Markers[x].bHidden) {
|
|
var MarkerLonLat = new OpenLayers.LonLat(ZKL_Markers[x].ip_Lon,ZKL_Markers[x].ip_Lat);
|
|
// Add this device to the bounding box around all tracking markers
|
|
TrackedDevicesBounds.extend(MarkerLonLat.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()));
|
|
// Find out if this device is actually invisible.
|
|
// (if none of the devices are invisible, we don't need to recenter/zoom map)
|
|
if (!ZKL_Markers[x].onScreen()) {
|
|
DbgPrint ("Device "+x+" is not visible. Adjusting zoom and center..");
|
|
bDevicesInvisible = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Are there actually devices invisible?
|
|
if (bDevicesInvisible) {
|
|
// Get old zoom level
|
|
var oldZoom = map.getZoom();
|
|
// Recenter and zoom map in sich a way that all tracked markers are visible.
|
|
TrackedDevicesBounds.toBBOX();
|
|
map.zoomToExtent(TrackedDevicesBounds, false);
|
|
// Get new zoom level
|
|
var newZoom = map.getZoom();
|
|
// Restore old zoom level?
|
|
if (oldZoom < newZoom) {
|
|
map.zoomTo(oldZoom);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redraw all the markers
|
|
*/
|
|
function ol_RedrawMarkers() {
|
|
try {
|
|
if (marker_layer != null) {
|
|
// Redraw marker layer
|
|
marker_layer.redraw();
|
|
|
|
// Redraw popup
|
|
for (x in ZKL_Markers) {
|
|
if ((x != null) && (typeof(ZKL_Markers[x]) == 'object') && (ZKL_Markers[x].popup != null)) {
|
|
try {
|
|
ZKL_Markers[x].popup.updatePosition();
|
|
}
|
|
catch (err) { /* Silent exception */ }
|
|
}
|
|
}
|
|
}
|
|
|
|
if (KML_layer != null) {
|
|
KML_layer.redraw();
|
|
}
|
|
}
|
|
catch(err) { /* Silent exception */ }
|
|
finally {
|
|
// Recursive
|
|
setTimeout('ol_RedrawMarkers();', 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialise OpenLayers mapping API
|
|
*/
|
|
function ol_init(Center, Zoom){
|
|
/// Create map objects
|
|
if (map == null) {
|
|
map = new OpenLayers.Map('map', { projection : new OpenLayers.Projection("EPSG:900913"),
|
|
displayProjection : new OpenLayers.Projection("EPSG:4326"),
|
|
maxExtent : new OpenLayers.Bounds(-20037508, -20037508,20037508, 20037508.34),
|
|
numZoomLevels : 18,
|
|
controls: [
|
|
new OpenLayers.Control.PanZoomBar(),
|
|
//new OpenLayers.Control.LayerSwitcher({'ascending':false}),
|
|
mapviewcontrol=new OpenLayers.Control.Mapview_Control(),
|
|
new OpenLayers.Control.ScaleLine(),
|
|
//new OpenLayers.Control.MousePosition(),
|
|
new OpenLayers.Control.MouseDefaults(),
|
|
new OpenLayers.Control.Navigation()
|
|
]
|
|
}
|
|
);
|
|
// Register "end-of-zoom" event (inflating icons)
|
|
//map.events.register("zoomend", null, ol_PanZoomEvent);
|
|
}
|
|
|
|
// Bing Hybrid base layer
|
|
if (vestr == null) {
|
|
vestr = new OpenLayers.Layer.VirtualEarth(StatusTranslationTable["streetmap"] + ' (BING)',
|
|
{
|
|
"sphericalMercator": true
|
|
});
|
|
map.addLayer(vestr);
|
|
}
|
|
|
|
// Open street layer
|
|
/* Removed due to SSL security error
|
|
if (osm == null) {
|
|
osm = new OpenLayers.Layer.OSM(StatusTranslationTable["streetmap"] + ' (OSM)');
|
|
map.addLayer(osm);
|
|
}
|
|
*/
|
|
// Bing Street map
|
|
if (vehyb == null) {
|
|
vehyb = new OpenLayers.Layer.VirtualEarth(StatusTranslationTable["satellitemap"],
|
|
{
|
|
'type': VEMapStyle.Hybrid, "sphericalMercator": true
|
|
});
|
|
map.addLayer(vehyb);
|
|
}
|
|
|
|
// Set the map center and zoom to a value where entire NL is visible.
|
|
var point = new OpenLayers.LonLat(5.11877, 52.09832);
|
|
map.setCenter(point.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()), 7);
|
|
|
|
// KML layer
|
|
//if (KML_layer == null) {
|
|
// // KML file exists?
|
|
// var kml = "rt.kml";
|
|
//
|
|
// if (xmlhttp_data('include/fetch_info.php','', 0, '', getURLParam('id'),'&file_exits=1&file=../' + kml, '', null) == '1') {
|
|
// KML_layer = new OpenLayers.Layer.Vector("KML", {
|
|
// projection: new OpenLayers.Projection("EPSG:4326"),
|
|
// strategies: [new OpenLayers.Strategy.Fixed()],
|
|
// protocol: new OpenLayers.Protocol.HTTP({
|
|
// url : kml,
|
|
// format : new OpenLayers.Format.KML({
|
|
// extractStyles : true,
|
|
// extractAttributes : true,
|
|
// extractTracks : true
|
|
// })
|
|
// })
|
|
// }
|
|
// );
|
|
// map.addLayer(KML_layer);
|
|
// }
|
|
//}
|
|
|
|
// Create the marker layer. Marker layer will be filled in later as a result of a successfull XMLHttpRequest.
|
|
if (marker_layer == null) {
|
|
marker_layer = new OpenLayers.Layer.Markers("DEV");
|
|
map.addLayer(marker_layer);
|
|
}
|
|
|
|
// Startup marker timer
|
|
setTimeout('ol_RedrawMarkers();',500);
|
|
}
|
|
|
|
/*
|
|
* Clean up markers/layers/map
|
|
*/
|
|
function ol_Cleanup() {
|
|
// Clean up markers
|
|
for (x in ZKL_Markers) {
|
|
// Try to remove popup
|
|
try {
|
|
marker_layer.map.removePopup(ZKL_Markers[x].popup);
|
|
ZKL_Markers[x].popup.destroy();
|
|
ZKL_Markers[x].popup = null;
|
|
}
|
|
catch (err) {}
|
|
// step 1: remove marker from the map
|
|
marker_layer.removeMarker(ZKL_Markers[x]);
|
|
// step 2: destroy the marker itself
|
|
ZKL_Markers[x].events.destroy();
|
|
ZKL_Markers[x].destroy();
|
|
// step 3: remove it from our array
|
|
delete(ZKL_Markers[x]);
|
|
}
|
|
|
|
// Clean up layers
|
|
if (map != null) {
|
|
if (vestr != null) {
|
|
// step 1: remove layer from the map
|
|
map.removeLayer(vestr, false);
|
|
// step 2: destroy the layer itself
|
|
vestr.destroy();
|
|
}
|
|
|
|
if (osm != null) {
|
|
// step 1: remove layer from the map
|
|
map.removeLayer(osm, false);
|
|
// step 2: destroy the layer itself
|
|
osm.destroy();
|
|
}
|
|
|
|
if (vehyb != null) {
|
|
// step 1: remove layer from the map
|
|
map.removeLayer(vehyb, false);
|
|
// step 2: destroy the layer itself
|
|
vehyb.destroy();
|
|
}
|
|
|
|
if (KML_layer != null) {
|
|
// step 1: remove layer from the map
|
|
map.removeLayer(KML_layer, false);
|
|
// step 2: destroy the layer itself
|
|
KML_layer.destroy();
|
|
}
|
|
}
|
|
|
|
// Cleanup map
|
|
if (map != null) {
|
|
map.destroy();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* End of zoom event, inflate markers
|
|
*/
|
|
function ol_PanZoomEvent() {
|
|
// Determine inflate value
|
|
var InflateStep = (0.5/map.numZoomLevels);
|
|
var Inflate = 0.5 + (InflateStep * (map.getZoom() + 1));
|
|
for (x in ZKL_Markers) {
|
|
if (ZKL_Markers[x]) {
|
|
// Inflate marker
|
|
ZKL_Markers[x].icon.setSize(new OpenLayers.Size(ZKL_Markers[x].originalSize.w * Inflate, ZKL_Markers[x].originalSize.h * Inflate));
|
|
ZKL_Markers[x].icon.offset = new OpenLayers.Pixel(-Math.round(ZKL_Markers[x].icon.size.w/2), -Math.round(ZKL_Markers[x].icon.size.h/2));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This functions swaps invisible/visible image and hides/shows marker
|
|
*/
|
|
function ol_HideItem(serialnr) {
|
|
// Swap image
|
|
if (getElement(serialnr + '_visible_image').src.search("invisible.gif") == -1) {
|
|
getElement(serialnr + '_visible_image').src = 'html/images/invisible.gif';
|
|
|
|
if (ZKL_Markers[serialnr]) {
|
|
// Set flag
|
|
ZKL_Markers[serialnr].bHidden = true;
|
|
// Hide marker & popup
|
|
ZKL_Markers[serialnr].display(false);
|
|
if (ZKL_Markers[serialnr].popup != null) {
|
|
ZKL_Markers[serialnr].popup.hide();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
getElement(serialnr + '_visible_image').src = 'html/images/visible.gif';
|
|
|
|
if (ZKL_Markers[serialnr]) {
|
|
// Clear flag
|
|
ZKL_Markers[serialnr].bHidden = false;
|
|
// Show marker
|
|
ZKL_Markers[serialnr].display(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Map view mouse handlers. We use it to redraw the markers to force correct behaviour with Google
|
|
*/
|
|
function mouseup() {
|
|
}
|
|
|
|
function mousedown() {
|
|
} |