/**
* @classdesc Class to test if json config file exists and then parse it.
* @constructor BKGWebMap.ParseConfig
* */
BKGWebMap.ParseConfig = function () {
this.exists = false;
this.json = null;
};
/**
* Tests if config JSON exists in Server
* @memberOf BKGWebMap.ParseConfig
* @param {boolean} configFile - Find if the configuration will be loaded from a file
* @param {null|string|object} configUrlOrJson - URL of JSON configuration file or object with configuration
* @param {function} callback - Callback to use JSON
* @returns {function}
*/
BKGWebMap.ParseConfig.prototype.LoadJSON = function (configFile, configUrlOrJson, callback) {
var _this = this;
// Neither JSON as parameter nor JSON file
if (!configFile && configUrlOrJson === null) {
_this.exists = false;
return callback();
}
// JSON as parameter
if (!configFile && configUrlOrJson !== null) {
_this.exists = true;
_this.json = configUrlOrJson;
return callback();
}
// JSON file
var xhr = new XMLHttpRequest();
xhr.open('GET', configUrlOrJson);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
var json = null;
if (xhr.status === 200) {
json = JSON.parse(xhr.responseText);
_this.exists = true;
_this.json = json;
} else if (xhr.status !== 200) {
_this.exists = false;
window.console.log(BKGWebMap.ERROR.jsonFile + configUrlOrJson);
}
return callback();
};
xhr.send();
};
/**
* Parse map target.
* @param {string} div - ID of map div.
* @param {boolean} setTarget - Boolean to check if div ID is defined in setTarget()
* @returns {string}
*/
BKGWebMap.ParseConfig.prototype.createConfigTarget = function (div, setTarget) {
var targetInJson = null;
if (BKGWebMap.Util.hasNestedProperty(this.json, 'map.div')) {
targetInJson = this.json.map.div;
}
// Overwrite div id only if is defined in JSON and setTarget() was not used
if (targetInJson && !setTarget) {
div = this.json.map.div;
}
return div;
};
/**
* Parse map view configuration.
* @param {object} defaultConfigView - Default view configuration.
* @param {object} userConfigView - View configuration defined in setView().
* @param {boolean} setView - Boolean to check if setView() is used.
* @returns {object}
*/
BKGWebMap.ParseConfig.prototype.createConfigView = function (defaultConfigView, userConfigView, setView) {
// Priority: Code -> JSON -> Defaults
// Key: name of property / Value: json path in dot notation
// Place projection as first key
var keysToParse = {
projection: 'map.projection',
extent: null,
resolution: 'map.resolution',
zoom: 'map.zoom',
center: 'map.center',
resolutions: 'map.resolutions',
// scales: 'map.scales',
minResolution: 'map.minResolution',
maxResolution: 'map.maxResolution',
minZoom: 'map.minZoom',
maxZoom: 'map.maxZoom'
};
var viewConfig = {};
var isKeyinCode = {};
var isKeyInJSON = {};
var projection = defaultConfigView.projection;
// Parse function for View parameters that are not possible to be defined in config JSON
function notDefinedInJSON(_this, keyInCode, paramName) {
var viewConfigValue;
if (setView && keyInCode) {
viewConfigValue = userConfigView[paramName];
} else {
switch (paramName) {
case 'extent':
// If user uses a different projection than the default
// without defining extent, do not use default extent.
// Use an extent of the right projection
if (viewConfig.projection !== defaultConfigView.projection) {
viewConfigValue = BKGWebMap.PROJECTIONS_EXTENTS[viewConfig.projection];
} else {
viewConfigValue = defaultConfigView.extent;
}
break;
default:
viewConfigValue = defaultConfigView[paramName];
}
}
return viewConfigValue;
}
// Parse function for View parameters that are possible to be defined in config JSON
function definedInJSON(_this, keyInCode, keyInJSON, paramName, jsonPath) {
var viewConfigValue;
var lon;
var lat;
if (setView && keyInCode) {
switch (paramName) {
case 'center':
lon = BKGWebMap.Util.getObjValueFromStringPath(userConfigView, ('center.lon'));
lat = BKGWebMap.Util.getObjValueFromStringPath(userConfigView, ('center.lat'));
if ((lon || lon === 0) && (lat || lat === 0)) {
viewConfigValue = [lon, lat];
}
break;
default:
viewConfigValue = userConfigView[paramName];
}
} else if (keyInJSON) {
if (BKGWebMap.Util.getObjValueFromStringPath(_this.json, jsonPath)) {
switch (paramName) {
case 'center':
lon = BKGWebMap.Util.getObjValueFromStringPath(_this.json, (jsonPath + '.lon'));
lat = BKGWebMap.Util.getObjValueFromStringPath(_this.json, (jsonPath + '.lat'));
if (lon && lat) {
viewConfigValue = [lon, lat];
}
break;
default:
viewConfigValue = BKGWebMap.Util.getObjValueFromStringPath(_this.json, jsonPath);
}
}
} else if (paramName === 'projection') {
return projection;
}
return viewConfigValue;
}
// OpenLayers: If we have resolution, the property zoom will not be used
function clearResolution(_this) {
var resolutionInCode = BKGWebMap.Util.hasNestedProperty(userConfigView, 'resolution');
var resolutionInJSON = BKGWebMap.Util.hasNestedProperty(_this.json, 'map.resolution');
var zoomInCode = BKGWebMap.Util.hasNestedProperty(userConfigView, 'zoom');
var zoomInJSON = BKGWebMap.Util.hasNestedProperty(_this.json, 'map.zoom');
// Code: zoom(Y), resolution(N)
// JSON: resolution(Y)
// Action: Remove resolution
if (setView && zoomInCode && !resolutionInCode && resolutionInJSON && _this.json.map.resolution) {
delete viewConfig.resolution;
}
// Code: zoom(N), resolution(N)
// JSON: zoom(Y), resolution(N)
// Action: Remove resolution
if (setView && !zoomInCode && !resolutionInCode && zoomInJSON && (!resolutionInJSON || !_this.json.map.resolution)) {
if (_this.json.map.zoom) {
delete viewConfig.resolution;
}
}
}
function clearResolutions() {
// If resolutions are not defined in setView() or in JSON,
// use default resolutions according to projection
if (!viewConfig.resolutions && viewConfig.projection) {
var projection = ol.proj.get(viewConfig.projection);
var units = projection.getUnits();
switch (units) {
case 'm':
viewConfig.resolutions = BKGWebMap.RESOLUTIONS;
break;
case 'degrees':
viewConfig.resolutions = BKGWebMap.RESOLUTIONS_DEGREE;
break;
default:
return;
}
}
// If minResolution and maxResolution OR minZoom and maxZoom
// are defined in setView() or in JSON, them remove resolutions
if ((viewConfig.minResolution && viewConfig.maxResolution) || (viewConfig.minZoom && viewConfig.maxZoom)) {
delete viewConfig.resolutions;
}
}
function addExtraKeys() {
// Add to View all other keys that are defined in setDiv().
// They will be automatically used, if they are legal OpenLayers options of ol.View().
if (setView) {
for (var param in userConfigView) {
if (!keysToParse[param]) {
viewConfig[param] = userConfigView[param];
}
}
}
}
for (var param in keysToParse) {
// Find if parameter is used in setView()
isKeyinCode[param] = BKGWebMap.Util.hasNestedProperty(userConfigView, param);
// Find if parameter is defined in config JSON
if (keysToParse[param]) {
isKeyInJSON[keysToParse[param]] = BKGWebMap.Util.hasNestedProperty(this.json, keysToParse[param]);
}
if (!keysToParse[param]) {
// Not possible to be defined in config JSON
viewConfig[param] = notDefinedInJSON(this, isKeyinCode[param], param);
} else {
// Possible to be defined in config JSON
viewConfig[param] = definedInJSON(this, isKeyinCode[param], isKeyInJSON[keysToParse[param]], param, keysToParse[param]);
if (viewConfig[param] === undefined) {
// Remove undefined properties
delete viewConfig[param];
}
}
}
// Resolve conflicts between resolution and zoom in setView() and in JSON
clearResolution(this);
// Resolve problems created by resolutions
clearResolutions();
// Add any other OpenLayers options parsed by setView()
addExtraKeys();
return viewConfig;
};
/**
* Create panel control
* @param {Object} map - OpenLayers map
* @param {Object|null} controlsConfig - Controls configuration defined by user
* @param {boolean} setControls - Boolean to check if setControls() is used
* @param {object} standardPositionControls - Object with standardPositionControls
* @returns {Object|boolean}
*/
BKGWebMap.ParseConfig.prototype.createControlPanel = function (map, controlsConfig, setControls, standardPositionControls) {
var controls = {};
if (this.exists && !setControls && Object.prototype.hasOwnProperty.call(this.json, 'options')) {
if (Object.prototype.hasOwnProperty.call(this.json, 'options') && (typeof this.json.options === 'object' && this.json.options.constructor === Object)) {
controls = this.json.options;
} else {
controls = BKGWebMap.CONTROLS;
}
} else if (setControls) {
controls = controlsConfig;
} else {
controls = BKGWebMap.CONTROLS;
}
// Find if we need panel
var createPanel = BKGWebMap.Util.shouldCreatePanel(controls);
if (createPanel) {
var panelPosition = controls.panelPosition;
var initialize = controls.initialize;
var Panel = BKGWebMap.Control.FACTORIES.panel();
var panelControl = new Panel(map, panelPosition, initialize, standardPositionControls);
// Add panel control
if (Object.keys(panelControl).length > 0) {
return panelControl;
}
}
return false;
};
/**
* Create controls
* @param {Object} map - OpenLayers map
* @param {Object|null} controlsConfig - Controls configuration defined by user
* @param {boolean} setControls - Boolean to check if setControls() is used
* @param {Object|boolean} panel - Panel object
* @param {object} standardPositionControls - Object with standardPositionControls
* @returns {Array}
*/
BKGWebMap.ParseConfig.prototype.createControls = function (map, controlsConfig, setControls, panel, standardPositionControls) {
var controls = {};
var controlsArray = [];
if (this.exists && !setControls && Object.prototype.hasOwnProperty.call(this.json, 'options')) {
if (Object.prototype.hasOwnProperty.call(this.json.options, 'tools') && (typeof this.json.options.tools === 'object' && this.json.options.tools.constructor === Object)) {
for (var tool in this.json.options.tools) {
controls[tool] = this.json.options.tools[tool];
}
} else {
controls = BKGWebMap.CONTROLS.tools;
}
} else if (setControls && Object.prototype.hasOwnProperty.call(controlsConfig, 'tools')) {
controls = controlsConfig.tools;
} else {
controls = BKGWebMap.CONTROLS.tools;
}
// Filter controls and define order in which they will be generated
var controlsList = [
'geoSearch',
'searchCoordinates',
'copyCoordinates',
'showAttributes',
'legend',
'layerSwitcher',
'customLayers',
'zoom',
'scalebar',
'copyright',
'showCoordinates',
'staticLinks',
'staticWindows',
'fullScreen',
'measure',
'edit',
'share',
'overviewMap',
'timeSlider'
];
var SingleControlClass;
var singleControl;
for (var i = 0; i < controlsList.length; i++) {
if (controls[controlsList[i]] && ((typeof controls[controlsList[i]] === 'object' && controls[controlsList[i]].constructor === Object))) {
SingleControlClass = BKGWebMap.Control.FACTORIES[controlsList[i]]();
singleControl = new SingleControlClass(map, controlsList[i], controls[controlsList[i]], panel, standardPositionControls);
// Remove extra classes from FullScreen control DIV and button (to prevent div getting the button style)
if (singleControl instanceof ol.control.FullScreen && !singleControl.inactive) {
singleControl.element.classList.remove('bkgwebmap-mapbutton');
singleControl.element.children[0].classList.remove('bkgwebmap-standardpositioncontrol');
singleControl.element.children[0].classList.remove('bkgwebmap-standardpositioncontrolleft');
singleControl.element.children[0].classList.remove('bkgwebmap-standardpositioncontrolright');
}
// Add controls
if (Object.keys(singleControl).length > 0 && !singleControl.inactive) {
controlsArray.push(singleControl);
BKGWebMap.Controls[controlsList[i]] = singleControl;
}
} else if (controls[controlsList[i]] && controls[controlsList[i]] instanceof Array) {
var multipleControlsClass = {};
var multipleControls = {};
for (var k = 0; k < controls[controlsList[i]].length; k++) {
multipleControlsClass[k] = BKGWebMap.Control.FACTORIES[controlsList[i]](k);
multipleControls[k] = new multipleControlsClass[k](map, controlsList[i], controls[controlsList[i]][k], panel, standardPositionControls);
// Add controls
if (Object.keys(multipleControls[k]).length > 0 && !multipleControls[k].inactive) {
controlsArray.push(multipleControls[k]);
BKGWebMap.Controls[controlsList[i] + k] = multipleControls[k];
}
}
}
}
return controlsArray;
};
/**
* Parse styles
* @param {array} stylesArray - Styles configuration defined by user
* @param {boolean} defineStyles - Boolean to check if defineStyles() is used
* @returns {Object}
*/
BKGWebMap.ParseConfig.prototype.createConfigStyles = function (stylesArray, defineStyles) {
var styles;
if (this.exists && !defineStyles && Object.prototype.hasOwnProperty.call(this.json, 'styles')) {
styles = BKGWebMap.Style.createStyles(this.json.styles);
} else {
styles = BKGWebMap.Style.createStyles(stylesArray);
}
return styles;
};
/**
* Parse layers configuration
* @param {object} map - Map object
* @param {object} defaultConfigLayers - Default layers configuration
* @param {object|array} userConfigLayers - Layers configuration defined by user
* @param {boolean} setLayers - Boolean to check if setLayers() is used.
* @param {function} callback - Callback function
* @returns {function}
*/
BKGWebMap.ParseConfig.prototype.createConfigLayers = function (map, defaultConfigLayers, userConfigLayers, styles, setLayers, callback) {
var _this = this;
var layers = {
baseLayers: [],
overlays: []
};
// No JSON, no setLayers(): use defaults
if (!this.exists && !setLayers) {
userConfigLayers = defaultConfigLayers;
}
// Only JSON: use JSON only if key 'layers' is available
if (this.exists && !setLayers && Object.prototype.hasOwnProperty.call(this.json, 'layers')) {
userConfigLayers = this.json.layers;
} else if (this.exists && !setLayers && !Object.prototype.hasOwnProperty.call(this.json, 'layers')) {
userConfigLayers = defaultConfigLayers;
// ERROR: layersInJson
window.console.log(BKGWebMap.ERROR.missingLayersJson);
}
// Only setLayers or JSON and setLayers(): use setLayers()
// If array with ol.layer class, use them as base layers
if (setLayers && userConfigLayers instanceof Array) {
userConfigLayers = {
baseLayers: userConfigLayers
};
}
this.createLayer = function (_this, map, config, layerGroup, styles, bkg, createLayerCallback) {
var typesList = ['WMS', 'WMTS', 'WFS', 'MARKER', 'CSV', 'XLS', 'GPS', 'BKG', 'GROUP', 'VECTOR', 'NONE'];
if (config instanceof ol.layer.Base) {
// ol.layer class
return createLayerCallback(config);
} else if (!Object.prototype.hasOwnProperty.call(config, 'type')) {
// false json without layer 'type' key
window.console.log(BKGWebMap.ERROR.missingTypeLayersJson);
return createLayerCallback(undefined);
} else if (typesList.indexOf(config.type) === -1) {
// false json with illegal layer type
window.console.log(BKGWebMap.ERROR.wrongTypeLayersJson + config.type);
return createLayerCallback(undefined);
}
if (layerGroup === 'baseLayers') {
config.isBaseLayer = true;
} else if (layerGroup === 'overlays') {
config.isBaseLayer = false;
}
BKGWebMap.Layer.FACTORIES[config.type](_this, map, config, styles, bkg, function (layer) {
return createLayerCallback(layer);
});
};
// Create instances of ol.layer
// Find how many layers we need to load (baselayers and overlays)
var sumLayerListLength = 0;
if (Object.prototype.hasOwnProperty.call(userConfigLayers, 'baseLayers')) {
sumLayerListLength += userConfigLayers.baseLayers.length;
}
if (Object.prototype.hasOwnProperty.call(userConfigLayers, 'overlays')) {
sumLayerListLength += userConfigLayers.overlays.length;
}
// The requests for the layers can be asynchronous
// (e.g. when we first make a getCapabilities before loading a WMTS)
// To preserve the original layer order defined by user, we implement a counter
var counter = 0;
for (var layerGroup in layers) {
if (Object.prototype.hasOwnProperty.call(userConfigLayers, layerGroup)) {
var layerGroupLength = userConfigLayers[layerGroup].length;
for (var i = 0; i < layerGroupLength; i++) {
(function () {
var k = i;
var _layerGroup = layerGroup;
_this.createLayer(_this, map, userConfigLayers[_layerGroup][k], layerGroup, styles, false, function (singleLayer) {
counter++;
// Do not use false json. There is no problem with an undefined layer. OL does not make any request.
if (singleLayer === undefined) {
if (counter >= sumLayerListLength) {
return callback(layers);
}
return;
}
layers[_layerGroup][k] = singleLayer;
// Return layers array only if we have loaded all layers
if (counter >= sumLayerListLength) {
return callback(layers);
}
});
}());
}
}
}
};
/**
* Options for generating and using UUID for secure BKG services
* @param {Object} securityConfig - Security parameters
* @param {boolean} setSecurity - If setSecurity() was used in code
* @param {function} callback - Callback function
* @returns {function}
*/
BKGWebMap.ParseConfig.prototype.getSecurityOptions = function (map, securityConfig, setSecurity, callback) {
var security;
if (this.exists && !setSecurity && Object.prototype.hasOwnProperty.call(this.json, 'options')) {
if (Object.prototype.hasOwnProperty.call(this.json.options, 'security') && (typeof this.json.options.security === 'object' && this.json.options.security.constructor === Object)) {
security = this.json.options.security;
} else {
security = BKGWebMap.SECURITY;
}
} else if (setSecurity) {
security = securityConfig;
} else {
security = BKGWebMap.SECURITY;
}
// Check if control should be created
var addCookieTest = BKGWebMap.CONTROLS.tools.cookieCheck.active;
if (typeof security.cookieCheck === 'boolean') {
if (security.cookieCheck === false) {
BKGWebMap.CONTROLS.tools.cookieCheck.doNotActivate = true;
}
addCookieTest = security.cookieCheck;
}
if (addCookieTest) {
var CookieCheckClass = BKGWebMap.Control.FACTORIES.cookieCheck();
var cookieCheck = new CookieCheckClass(map, 'cookieCheck', {}, null);
map.addControl(cookieCheck);
BKGWebMap.Controls.cookieCheck = cookieCheck;
cookieCheck.activateCookieTest();
}
// Polyfill String.prototype.startsWith() for IE11
if (!String.prototype.startsWith) {
String.prototype.startsWith = function (search, pos) {
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
};
}
if (!security.UUID && (security.appID && security.appDomain)) {
BKGWebMap.Util.getSessionToken(security.appID, security.appDomain, function (sessionID) {
if (sessionID.startsWith('sess-')) {
security.UUID = sessionID;
}
return callback(security);
});
} else {
return callback(security);
}
};