adaguc-webmapjs
Version:
Interactive maps library, capable of parsing a OGC WMS getcapabilities and display geographical layers
815 lines (735 loc) • 25.3 kB
JavaScript
// ============================================================================
// Name : WMJSTools
// Author : MaartenPlieger (plieger at knmi.nl)
// Version : 3.2.0 (September 2018)
// Description : WMJSTools provides a set of useful JS functions
// ============================================================================
/*
Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
Copyright (C) 2011 by Royal Netherlands Meteorological Institute (KNMI)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// ============================================================================
// Name : tools
// Author : MaartenPlieger (plieger at knmi.nl)
// Version : 0.5 (September 2010)
// Description : All kinds of small usable functions
// ============================================================================
/**
* Checks if variable is defined or not
* @param variable The variable to check
* @returns true if variable is indeed defined, otherwise false.
*/
export const isDefined = (variable) => {
if (typeof variable === 'undefined') {
return false;
}
return true;
};
/**
* Checks if a variable is null or not
* @param variable The variable to check
* @returns true if variable is indeed null, otherwise false.
*/
export const isNull = (variable) => {
if (variable === null) {
return true;
}
return false;
};
/**
* Converts a variable to an array. If the variable is not an array it will be pushed to
* as the first entry in a new array. If the variable is already an array, nothing will be done.
* @param array The variable to convert
* @returns Always an array
*/
export const toArray = (array) => {
if (!array) return [];
if (array.length) {
return array;
} else {
var newArray = [];
newArray[0] = array;
return newArray;
}
};
/**
* Function which checks wether URL contains a ? token. If not, it is assumed that this token was not provided by the user,
* manually add the token later.
* @param url The URL to check
* @return the fixed URL
*/
export const WMJScheckURL = function (url) {
if (!isDefined(url)) return '?';
url = url.trim();
if (url.indexOf('?') === -1) {
url += '?';
}
return url;
};
/**
* A normal unordered set, e.g. a list containing no duplicates.
*/
var WMJSSet = function () {};
WMJSSet.prototype.add = function (o) { this[o] = true; };
WMJSSet.prototype.remove = function (o) { delete this[o]; };
/**
* Splits a url into key value pairs.
*/
export class WMJSKVP {
constructor (query) {
this.kvplist = [];
this.kvplist = this._parse(query);
return this.kvplist;
}
_parse (query) {
var kvplist = [];
var splittedKVP = query.split('&');
if (splittedKVP) {
for (var kvpkey in splittedKVP) {
var kvp = splittedKVP[kvpkey];
var kvps = kvp.split('=');
if (kvps.length === 2) {
var key = kvps[0];
var value = kvps[1];
if (!(kvplist[key] instanceof Array))kvplist[key] = [];
kvplist[key].push(value);
}
}
}
return kvplist;
}
getKeys () {
var keys = new WMJSSet();
for (let key in this.kvplist) {
keys.add(key);
}
return keys;
}
getValues (key) {
return this.kvplist[key];
}
getKeyValues () {
return this.kvplist;
}
};
export const preventdefaultEvent = (e) => {
var event = e || window.event;
if (event.preventDefault) { // Firefox
event.preventDefault();
} else { // IE
event.returnValue = false;
}
};
export const attachEvent = (obj, evType, fn) => {
if (!obj) return;
// Attach event that works on all browsers
if (evType == 'mousewheel') {
function wheel (event, handler) {
var delta = 0;
if (!event) { /* For IE. */
event = window.event;
window.event.cancelBubble = true;
window.event.returnValue = false;
}
if (event.wheelDelta) { /* IE/Opera. */
delta = event.wheelDelta / 120;
} else if (event.detail) { /** Mozilla case. */
/** In Mozilla, sign of delta is different than in IE.
* Also, delta is multiple of 3.
*/
delta = -event.detail / 3;
}
/** If delta is nonzero, handle it.
* Basically, delta is now positive if wheel was scrolled up,
* and negative, if wheel was scrolled down.
*/
if (delta) { handler(delta); }
/** Prevent default actions caused by mouse wheel.
* That might be ugly, but we handle scrolls somehow
* anyway, so don't bother here..
*/
if (event.preventDefault) { event.preventDefault(); }
event.returnValue = false;
}
if (obj.addEventListener) { obj.addEventListener('DOMMouseScroll', function (e) { wheel(e, fn); }, false); }
obj.onmousewheel = document.onmousewheel = function (e) { wheel(e, fn); };
return;
}
if (browser.isNS) {
obj.addEventListener(evType, fn, true);
} else {
obj.attachEvent(('on' + evType), fn);
if (window.event == undefined) return;
window.event.cancelBubble = true;
window.event.returnValue = false;
}
};
export const deleteEvent = (obj, eventId, funct) => {
var flag = true; if (browser.isOP) { flag = false; }
if (obj.removeEventListener) {
obj.removeEventListener(eventId, funct, flag);
} else if (obj.detachEvent) {
obj.detachEvent(eventId, funct);
obj.detachEvent('on' + eventId, funct);
}
};
export const getMouseXCoordinate = (event) => {
let myX;
if (browser.isNS) {
myX = event.clientX + window.scrollX;
} else {
myX = window.event.clientX + document.documentElement.scrollLeft +
document.body.scrollLeft;
}
return myX;
};
export const getMouseYCoordinate = (event) => {
let myY;
if (browser.isNS) {
myY = event.clientY + window.scrollY;
} else {
myY = window.event.clientY + document.documentElement.scrollTop +
document.body.scrollTop;
}
return myY;
};
var findElementPos = function (obj) {
var el = obj;
var curleft = curtop = 0;
while (obj) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
return [curleft, curtop, parseInt(el.style.width + curleft), parseInt(el.style.height + curtop)];
};
function Browser () {
var ua, s, i;
this.isIE = false;
this.isNS = false;
this.isOP = false;
this.isKonqueror = false;
this.name = navigator.appName;
this.version = null;
ua = navigator.userAgent;
if ((navigator.userAgent).indexOf('Opera') != -1) {
this.isOP = true;
} else
if (navigator.appName == 'Netscape' || navigator.appName == 'Konqueror') {
this.isNS = true;
this.isKonqueror = true;
} else
if ((navigator.appName).indexOf('Microsoft') != -1) {
this.isIE = true;
}
}
var browser = new Browser();
function IsNumeric (sText) {
var ValidChars = '0123456789.';
var IsNumber = true;
var Char;
for (i = 0; i < sText.length && IsNumber == true; i++) {
Char = sText.charAt(i);
if (ValidChars.indexOf(Char) == -1) {
IsNumber = false;
}
}
return IsNumber;
}
function dump (arr, level, path) {
var dumped_text = '';
if (!path)path = '';
if (!level) level = 0;
var level_padding = path;
if (typeof (arr) === 'object') { // Array/Hashes/Objects
for (var item in arr) {
var value = arr[item];
var newpath = path;
if (IsNumeric(item)) {
item = '[' + item + ']';
newpath = path.substr(0, path.length - 1) + item;
} else {
newpath = path + item;
}
if (typeof (value) === 'object') { // If it is an array,
// dumped_text += newpath + "=object<br>\n";
dumped_text += dump(value, level + 1, newpath + '.');
} else {
dumped_text += newpath + '="' + value + '"<br>\n';
}
}
} else { // Stings/Chars/Numbers etc.
dumped_text = '===>' + arr + '<===(' + typeof (arr) + ')';
}
return dumped_text;
}
var Url = {
// public method for url encoding
encode : function (string) {
return escape(this._utf8_encode(string));
},
// public method for url decoding
decode : function (string) {
alert('Deprecated function !!! WMJSTools line 325 with [' + string + ']');
return this._utf8_decode(unescape(string));
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g, '\n');
var utftext = '';
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = '';
var i = 0;
var c = c1 = c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
// ============================================================================
// Name : HTTP_RequestFunctions.js
// Author : MaartenPlieger (plieger at knmi.nl)
// Version : 0.5 (September 2010)
// Description : Functions to make HTTP requests
// ============================================================================
function createXHR () {
try { return new XMLHttpRequest(); } catch (e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (e) {}
try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {}
try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {}
return false;
}
function MakeJSONRequest (fname, callbackfunction, errorfunction, pointer, useredirect) {
if (fname.indexOf('?') == -1) {
fname += '?';
} else {
fname += '&';
}
fname += 'rand=' + Math.random();
function requestError (errorMessage) {
if (errorfunction)errorfunction(errorMessage, pointer);
else callbackfunction(undefined, pointer);
}
function redirRequest () {
// Let try an alternative way: redirect using PHP
if (useredirect == false) {
fname = requestProxy + 'REQUEST=' + URLEncode(fname);
MakeJSONRequest(fname, callbackfunction, errorfunction, pointer, true);
} else {
requestError('status(' + xhr.status + ') to ' + fname);
}
}
if (!useredirect)useredirect = false;
try {
var xhr = createXHR();
xhr.open('GET', fname, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
try {
var data = eval('(' + xhr.responseText + ')');
} catch (err) {
requestError("Invalid JSON: '" + xhr.responseText + "'");
return;
}
if (data == undefined) {
requestError('request returned no data:' + fname);
} else {
callbackfunction(data, pointer);
}
} else {
redirRequest();
}
}
};
xhr.send(null);
} catch (err) {
redirRequest();
}
}
export const MakeHTTPRequest = (fname, callbackfunction, errorfunction, pointer, useredirect, requestProxy) => {
if (fname.indexOf('?') === -1) {
fname += '?';
} else {
fname += '&';
}
fname += 'rand=' + Math.random();
function requestError (errorMessage) {
if (errorfunction)errorfunction(errorMessage, pointer);
else callbackfunction(undefined, pointer);
}
function redirRequest () {
// Let try an alternative way: redirect using PHP
if (useredirect === false) {
// alert(fname);
fname = requestProxy + 'REQUEST=' + URLEncode(fname);
// alert(fname);
MakeHTTPRequest(fname, callbackfunction, errorfunction, pointer, true, requestProxy);
} else {
requestError('status(' + xhr.status + ') to ' + fname);
}
}
if (!useredirect)useredirect = false;
try {
var xhr = createXHR();
xhr.open('GET', fname, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
var data = xhr.responseText;
} catch (err) {
requestError('Exception occured:' + err);
return;
}
if (data === undefined || data === '') {
requestError('request returned no data');
} else {
callbackfunction(data, pointer);
}
} else {
redirRequest();
}
}
};
xhr.send(null);
} catch (err) {
redirRequest();
}
};
export const URLDecode = (encodedURL) => {
if (!isDefined(encodedURL)) return '';
encodedURL = encodedURL.replaceAll('+', ' ');
encodedURL = encodedURL.replaceAll('%2B', '+');
encodedURL = encodedURL.replaceAll('%20', ' ');
encodedURL = encodedURL.replaceAll('%5E', '^');
encodedURL = encodedURL.replaceAll('%26', '&');
encodedURL = encodedURL.replaceAll('%3F', '?');
encodedURL = encodedURL.replaceAll('%3E', '>');
encodedURL = encodedURL.replaceAll('%3C', '<');
encodedURL = encodedURL.replaceAll('%5C', '\\');
encodedURL = encodedURL.replaceAll('%2F', '/');
encodedURL = encodedURL.replaceAll('%25', '%');
encodedURL = encodedURL.replaceAll('%3A', ':');
encodedURL = encodedURL.replaceAll('%27', "'");
encodedURL = encodedURL.replaceAll('%24', '$');
return encodedURL;
};
// Encodes plain text to URL encoding
export const URLEncode = (plaintext) => {
if (!plaintext) return plaintext;
if (plaintext === undefined) return plaintext;
if (plaintext === '') return plaintext;
if (typeof (plaintext) !== 'string') return plaintext;
var SAFECHARS = '0123456789' + // Numeric
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + // Alphabetic
'abcdefghijklmnopqrstuvwxyz' +
"%-_.!~*'()"; // RFC2396 Mark characters
var HEX = '0123456789ABCDEF';
plaintext = plaintext.replace(/%/g, '%25');
plaintext = plaintext.replace(/\+/g, '%2B');
plaintext = plaintext.replace(/ /g, '%20');
plaintext = plaintext.replace(/\^/g, '%5E');
plaintext = plaintext.replace(/&/g, '%26');
plaintext = plaintext.replace(/\?/g, '%3F');
plaintext = plaintext.replace(/>/g, '%3E');
plaintext = plaintext.replace(/</g, '%3C');
plaintext = plaintext.replace(/\\/g, '%5C');
var encoded = '';
for (var i = 0; i < plaintext.length; i++) {
var ch = plaintext.charAt(i);
if (ch === ' ') {
encoded += '%20'; // x-www-urlencoded, rather than %20
} else if (SAFECHARS.indexOf(ch) !== -1) {
encoded += ch;
} else {
var charCode = ch.charCodeAt(0);
if (charCode > 255) {
alert("Unicode Character '" +
ch +
"' cannot be encoded using standard URL encoding.\n" +
'(URL encoding only supports 8-bit characters.)\n' +
'A space (+) will be substituted.');
encoded += '+';
} else {
encoded += '%';
encoded += HEX.charAt((charCode >> 4) & 0xF);
encoded += HEX.charAt(charCode & 0xF);
}
}
}
return encoded;
};
// Replaces all instances of the given substring.
String.prototype.replaceAll = function (
strTarget, // The substring you want to replace
strSubString // The string you want to replace in.
) {
var strText = this;
var intIndexOfMatch = strText.indexOf(strTarget);
// Keep looping while an instance of the target string
// still exists in the string.
while (intIndexOfMatch != -1) {
// Relace out the current instance.
strText = strText.replace(strTarget, strSubString);
// Get the index of any next matching substring.
intIndexOfMatch = strText.indexOf(strTarget);
}
// Return the updated string with ALL the target strings
// replaced out with the new substring.
return (strText);
};
// Trims the spaces from the string
String.prototype.trim = function () {
var value = this;
value = value.replace(/^\s+/, '');
value = value.replace(/\s+$/, '');
return value;
};
function checkValidInputTokens (stringToCheck) {
var filter = /^([a-zA-Z'_:~%?\$,\.\0-9 \-=/&])+$/;
if (filter.test(stringToCheck)) {
var t = URLDecode(stringToCheck);
if (filter.test(t)) {
return true;
}
}
return false;
};
// Read a page's GET URL variables and return them as an associative array (From Roshambo's code snippets)
export const getUrlVars = () => {
var vars = []; var hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
hash[1] = URLDecode(hash[1]);
// vars.push({hash[0]:hash[1]});
if (checkValidInputTokens(hash[0]) == false || checkValidInputTokens(hash[1]) == false) {
} else {
vars[hash[0]] = hash[1] + '';
}
}
return vars;
};
// Read a page's GET URL variables and return them as an associative array (From Roshambo's code snippets)
function getUrlVarsFromHashTag () {
var vars = []; var hash;
var splitloc = window.location.hash.indexOf('#');
if (window.location.hash[splitloc + 1] == '?')splitloc++;
var hashString = window.location.hash.slice(splitloc + 1);
var hashes = hashString.split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
hash[1] = URLDecode(hash[1]);
// vars.push({hash[0]:hash[1]});
if (checkValidInputTokens(hash[0]) == false || checkValidInputTokens(hash[1]) == false) {
} else {
vars[hash[0]] = hash[1] + '';
}
}
return vars;
}
// Splits a URL in a location part and separate Key Value Pairs (kvp).
export const composeUrlObjectFromURL = (url) => {
var vars = [];
if (!isDefined(url)) {
return vars;
}
var location = '';
var hashes = [];
var urlParts = url.split('?');
if (urlParts.length > 1) {
location = urlParts[0];
hashes = urlParts[1].split('&');
} else {
hashes = urlParts[0].split('&');
}
for (var i = 0; i < hashes.length; i++) {
let hash = hashes[i].split('=');
if (isDefined(hash[1])) {
hash[1] = URLDecode(hash[1]);
if (checkValidInputTokens(hash[0]) == false || checkValidInputTokens(hash[1]) == false) {
} else {
if (isDefined(hash[1])) {
if (hash[1].length > 0) {
vars[hash[0].toLowerCase()] = hash[1] + '';
}
}
}
} else {
hash = hashes[i].split('%3D');
if (isDefined(hash[1])) {
hash[1] = URLDecode(hash[1]);
if (checkValidInputTokens(hash[0]) == false || checkValidInputTokens(hash[1]) == false) {
} else {
if (isDefined(hash[1])) {
if (hash[1].length > 0) {
vars[hash[0].toLowerCase()] = hash[1] + '';
}
}
}
}
}
}
if (hashes[0].indexOf('=') == -1) {
// if(checkValidInputTokens(hashes[0])){
// location = hashes[0];
// }
}
return { location:location, kvp:vars };
};
// Check for hash tag changes.
var currentLocationHash = '';
var hashTagCheckerInUse = false;
var hashTagTimerIsRunning = false;
var _checkIfHashTagChanged = function (callback) {
var identifier = window.location.hash; // gets everything after the hashtag i.e. #home
if (currentLocationHash != identifier && identifier.length > 0) {
currentLocationHash = identifier;
if (window.location.href.indexOf('#') != -1) {
var hashLocation = (window.location.href.split('#')[1]); // Firefox automatically urldecodes the hashtag, so use href instead.
hashLocation = hashLocation.replaceAll('%27', "'"); // Firefox automatically encodes ' tokens into %27 for some reason. We can safely decode.
let urlVars = getUrlVarsFromHashTag();
if (isDefined(urlVars.clearhash)) {
if (urlVars.clearhash == '1') {
window.location.hash = '';
currentLocationHash = '';
}
}
// alert(hashLocation);
// alert(identifier+"\n"+window.location.href);
callback(hashLocation, urlVars);
}
}
if (hashTagTimerIsRunning === true) return;
hashTagTimerIsRunning = true;
setTimeout(function () {
hashTagTimerIsRunning = false;
_checkIfHashTagChanged(callback);
}, 500);
};
export const checkIfHashTagChanged = (callback) => {
if (!isDefined(callback)) return;
if (hashTagCheckerInUse == true) {
alert('checkIfHashTagChanged is in use');
return;
}
hashTagCheckerInUse = true;
_checkIfHashTagChanged(callback);
};
var decodeBase64 = function (s) {
var e = {}; var i; var b = 0; var c; var x; var l = 0; var a; var r = ''; var w = String.fromCharCode; var L = s.length;
var A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
for (i = 0; i < 64; i++) { e[A.charAt(i)] = i; }
for (x = 0; x < L; x++) {
c = e[s.charAt(x)]; b = (b << 6) + c; l += 6;
while (l >= 8) { ((a = (b >>> (l -= 8)) & 0xff) || (x < (L - 2))) && (r += w(a)); }
}
return r;
};
export const addMouseWheelEvent = (element, mouseWheelHandler) => {
if (!element) return;
/* https://developer.mozilla.org/en-US/docs/Web/Events/wheel#Browser_compatibility */
if (!window.addWheelListener) {
var prefix = ''; var _addEventListener; var support;
// detect event model
if (window.addEventListener) {
_addEventListener = 'addEventListener';
} else {
_addEventListener = 'attachEvent';
prefix = 'on';
}
// detect available wheel event
support = 'onwheel' in document.createElement('div') ? 'wheel' // Modern browsers support "wheel"
: document.onmousewheel !== undefined ? 'mousewheel' // Webkit and IE support at least "mousewheel"
: 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
window.addWheelListener = function (elem, callback, useCapture) {
_addWheelListener(elem, support, callback, useCapture);
// handle MozMousePixelScroll in older Firefox
if (support == 'DOMMouseScroll') {
_addWheelListener(elem, 'MozMousePixelScroll', callback, useCapture);
}
};
function _addWheelListener (elem, eventName, callback, useCapture) {
elem[ _addEventListener ](prefix + eventName, support == 'wheel' ? callback : function (originalEvent) {
!originalEvent && (originalEvent = window.event);
// create a normalized event object
var event = {
// keep a ref to the original event object
originalEvent: originalEvent,
target: originalEvent.target || originalEvent.srcElement,
type: 'wheel',
deltaMode: originalEvent.type == 'MozMousePixelScroll' ? 0 : 1,
deltaX: 0,
deltaY: 0,
deltaZ: 0,
preventDefault: function () {
originalEvent.preventDefault
? originalEvent.preventDefault()
: originalEvent.returnValue = false;
}
};
// calculate deltaY (and deltaX) according to the event
if (support == 'mousewheel') {
event.deltaY = -1 / 40 * originalEvent.wheelDelta;
// Webkit also support wheelDeltaX
originalEvent.wheelDeltaX && (event.deltaX = -1 / 40 * originalEvent.wheelDeltaX);
} else {
event.deltaY = originalEvent.deltaY || originalEvent.detail;
}
// it's time to fire the callback
return callback(event);
}, useCapture || false);
}
}
window.addWheelListener(element, mouseWheelHandler);
};
export const removeMouseWheelEvent = (element, mouseWheelHandler) => {
console.warn('TODO: Implement removeMouseWheelEvent in WMJSTools.js');
};