UNPKG

adaguc-webmapjs

Version:

Interactive maps library, capable of parsing a OGC WMS getcapabilities and display geographical layers

1,303 lines (1,205 loc) 133 kB
/* * Name : WMJSMap.js * Author : MaartenPlieger (plieger at knmi.nl) * Version : 3.2.0 (September 2018) * Description : This is a basic interface for portrayal of OGC WMS services * Copyright KNMI */ /* 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. */ import WMJSImageStore from './WMJSImageStore.js'; import { isDefined, preventdefaultEvent, URLEncode, toArray, deleteEvent, attachEvent, WMJScheckURL, MakeHTTPRequest, getMouseXCoordinate, getMouseYCoordinate, addMouseWheelEvent, removeMouseWheelEvent } from './WMJSTools.js'; import WMJSBBOX from './WMJSBBOX.js'; import WMJSProjection from './WMJSProjection.js'; import WMJSListener from './WMJSListener.js'; import WMJSTimer from './WMJSTimer.js'; import WMJSDebouncer from './WMJSDebouncer.js'; import WMJSCanvasBuffer from './WMJSCanvasBuffer.js'; import WMJSAnimate from './WMJSAnimate.js'; import WMJSTileRenderer from './WMJSTileRenderer.js'; import WMJSDrawMarker from './WMJSDrawMarker.js'; import I18n from './I18n/lang.en.js'; import { jquery, proj4, moment } from './WMJSExternalDependencies.js'; import WMJSDialog from './WMJSDialog.js'; import { WMJSDateOutSideRange, WMJSDateTooEarlyString, WMJSDateTooLateString, WMSVersion, WMJSProj4Defs } from './WMJSConstants.js'; // var Hammer = require(['hammerjs']); var pjson = require('../package.json'); let enableConsoleDebugging = false; let enableConsoleErrors = true; /** * Set base URL of several sources used wihtin webmapjs */ let debug = (message) => { if (enableConsoleDebugging) { console.log(message); } }; let error = (message) => { if (enableConsoleErrors) { console.log('WebMapJS warning: ', message); } }; /* Global vars */ let WebMapJSMapNo = 0; let WebMapJSMapInstanceIds = []; /* Global image stores */ let maxAnimationSteps = 72; var legendImageStore = new WMJSImageStore(maxAnimationSteps * 6, 'wmjslegendbuffer'); var getMapImageStore = new WMJSImageStore(maxAnimationSteps * 6, 'wmjsimagebuffer'); var bgMapImageStore = new WMJSImageStore(360, 'wmjsimagebuffer', { randomizer:false }); /* GetFeature info handling */ class GetFeatureInfoObject { constructor (layer, data) { this.layer = layer; this.data = data; } }; /** /** * WMJSMap class */ export default class WMJSMap { constructor (_element, _xml2jsonrequestURL) { this.WebMapJSMapVersion = '3.0'; if (pjson && pjson.version) this.WebMapJSMapVersion = pjson.version; this.base = './'; this.noimage = undefined; this.showDialog = true; this.loadingImageSrc = undefined; this.WMSControlsImageSrc = undefined; this.mainElement = _element; this.baseDiv = undefined; this.mainTimeSlider = undefined; this.srs = undefined; this.resizeBBOX = new WMJSBBOX(); this.defaultBBOX = new WMJSBBOX(); this.width = 2; this.height = 2; this.layers = []; this.busy = 0; this.mapdimensions = [];// Array of Dimension; this.baseLayers = ''; this.numBaseLayers = 0; this._map = this; this.renderer = 'WMJSCanvasBuffer'; this.layersBusy = 0; this.mapBusy = false; this.hasGeneratedId = false; this.divZoomBox = document.createElement('div'); this.divBoundingBox = document.createElement('div'); this.divDimInfo = document.createElement('div'); this.divMapPin = { displayMapPin: true }; this._displayLegendInMap = true; this.messageDiv = undefined; this.timeoffsetContainerDiv = undefined; this.timeoffsetDiv = undefined; this.bbox = new WMJSBBOX(); // Boundingbox that will be used for map loading this.updateBBOX = new WMJSBBOX(); // Boundingbox to move map without loading anything this.loadedBBOX = new WMJSBBOX(); // Boundingbox that is used for current map this.loadingBBOX = new WMJSBBOX(); // Boundingbox that is used when map is loading this.drawnBBOX = new WMJSBBOX(); // Boundingbox that is used when map is drawn this.updateSRS = ''; this.divBuffer = []; this.isDestroyed = false; this.mapHeader = { height:0, fill:{ color:'#EEE', opacity:0.4 }, hover:{ color:'#017daf', opacity:0.9 }, selected:{ color:'#017daf', opacity:1.0 }, hoverSelected:{ color:'#017daf', opacity:1.0 }, cursorSet:false, prevCursor:'default', hovering:false }; this.currentCursor = 'default'; this.mapIsActivated = false; this.isMapHeaderEnabled = false; this.showScaleBarInMap = true; this.showInfoInMap = true; this.mouseHoverAnimationBox = false; this.callBack = new WMJSListener(); this.initialized = 0; this.newSwapBuffer = 0; this.currentSwapBuffer = 1; this.suspendDrawing = false; this.activeLayer = undefined; /* Undo: */ this.MaxUndos = 3; this.NrOfUndos = 0; this.UndoPointer = 0; this.DoUndo = 0; this.DoRedo = 0; this.NrRedos = 0; this.NrUndos = 0; this.WMJSProjection_undo = new Array(this.MaxUndos); this.WMJSProjection_tempundo = new Array(this.MaxUndos); for (let j = 0; j < this.MaxUndos; j++) { this.WMJSProjection_undo[j] = new WMJSProjection(); this.WMJSProjection_tempundo[j] = new WMJSProjection(); } this.inlineGetFeatureInfo = true; this.setBaseURL('./'); /* Contains the event values for when the mouse was pressed down (used for checking the shiftKey); */ this.gfiDialogList = []; this.legendBusy = false; this.setTimeOffsetValue = ''; this.setMessageValue = ''; this.canvasErrors = []; this.resizeWidth = -1; this.resizeHeight = -1; this._resizeTimerBusy = false; this._resizeTimer = new WMJSTimer(); this.zoomBeforeLoadBBOX = undefined; this.srsBeforeLoadBBOX = undefined; this.drawTimer = new WMJSDebouncer(); this.drawTimerBusy = false; this.drawTimerPending = false; this.drawTimerAnimationList = undefined; this.wmjsAnimate = undefined; this.loadingDivTimer = new WMJSTimer(); this.mouseWheelBusy = 0; this.flyZoomToBBOXTimerStart = 1; this.flyZoomToBBOXTimerSteps = 5; this.flyZoomToBBOXTimerLoop = undefined; this.flyZoomToBBOXTimer = new WMJSDebouncer(); this.flyZoomToBBOXScaler = 0; this.flyZoomToBBOXCurrent = new WMJSBBOX(); this.flyZoomToBBOXFly = new WMJSBBOX(); this.flyZoomToBBOXNew = new WMJSBBOX(); this.flyZoomToBBOXContinueNew = new WMJSBBOX(); this.flyZoomToBBOXTimerFuncBusy = 0; this.flyZoomToBBOXTimerFuncBusyAndContinue = 0; this.mouseWheelEventBBOXCurrent = new WMJSBBOX(); this.mouseWheelEventBBOXNew = new WMJSBBOX(); this.pinchStart1 = undefined; this.pinchStart2 = undefined; this.pinchBox = undefined; this.mouseX = 0; this.mouseY = 0; this.mouseDownX = -10000; this.mouseDownY = -10000; this.mouseUpX = 10000; this.mouseUpY = 10000; this.mouseDragging = 0; this.controlsBusy = false; this.mouseDownPressed = 0; this.elementPosition = undefined; this.mapMode = 'pan'; /* pan,zoom,zoomout,info */ this.numGetFeatureInfoRequests = 0; this.getFeatureInfoResult = []; this.numGetPointInfoRequests = 0; this.getPointInfoResult = []; this.getPointInfoBusy = false; this.requestProxy = undefined; // TODO this.oldMapMode = undefined; this.InValidMouseAction = 0; this.resizingBBOXCursor = false; this.resizingBBOXEnabled = false; this.mouseGeoCoordXY = undefined; this.mouseUpdateCoordinates = undefined; this.mapPanning = 0; this.mapPanStartGeoCoords = undefined; this.mapZooming = 0; this.proj4 = {}; /* proj4 remembers current projection */ this.proj4.srs = 'empty'; this.proj4.projection = undefined; this.longlat = 'EPSG:4326'; if (proj4) proj4.defs(WMJSProj4Defs); this.knmiGeoNamesURL = undefined; this.geoNamesURL = undefined; this.defaultUsernameSearch = 'adaguc'; this.setDebugFunction = (debugFunction) => { debug = debugFunction; }; this.setErrorFunction = (errorFunction) => { error = errorFunction; }; /* Binds */ this.setBaseURL = this.setBaseURL.bind(this); this.showDialogs = this.showDialogs.bind(this); this.setXML2JSONURL = this.setXML2JSONURL.bind(this); this.setWMJSTileRendererTileSettings = this.setWMJSTileRendererTileSettings.bind(this); this.getLegendStore = this.getLegendStore.bind(this); this.makeComponentId = this.makeComponentId.bind(this); this.enableInlineGetFeatureInfo = this.enableInlineGetFeatureInfo.bind(this); this.dialogClosed = this.dialogClosed.bind(this); this.closeAllGFIDialogs = this.closeAllGFIDialogs.bind(this); this.onLegendCallbackFunction = this.onLegendCallbackFunction.bind(this); this.loadLegendInline = this.loadLegendInline.bind(this); this.setMessage = this.setMessage.bind(this); this.setTimeOffset = this.setTimeOffset.bind(this); this.init = this.init.bind(this); this.rebuildMapDimensions = this.rebuildMapDimensions.bind(this); this.getLayerByServiceAndName = this.getLayerByServiceAndName.bind(this); this.getLayers = this.getLayers.bind(this); this.setLayer = this.setLayer.bind(this); this.setActive = this.setActive.bind(this); this.setActiveLayer = this.setActiveLayer.bind(this); this.calculateNumBaseLayers = this.calculateNumBaseLayers.bind(this); this.enableLayer = this.enableLayer.bind(this); this.disableLayer = this.disableLayer.bind(this); this.toggleLayer = this.toggleLayer.bind(this); this.displayLayer = this.displayLayer.bind(this); this._getLayerIndex = this._getLayerIndex.bind(this); this.removeAllLayers = this.removeAllLayers.bind(this); this.deleteLayer = this.deleteLayer.bind(this); this.moveLayerDown = this.moveLayerDown.bind(this); this.swapLayers = this.swapLayers.bind(this); this.moveLayerUp = this.moveLayerUp.bind(this); this.addLayer = this.addLayer.bind(this); this.getActiveLayer = this.getActiveLayer.bind(this); this.setProjection = this.setProjection.bind(this); this.getBBOX = this.getBBOX.bind(this); this.getProjection = this.getProjection.bind(this); this.getSize = this.getSize.bind(this); this.getWidth = this.getWidth.bind(this); this.getHeight = this.getHeight.bind(this); this.repositionLegendGraphic = this.repositionLegendGraphic.bind(this); this.setSize = this.setSize.bind(this); this._setSize = this._setSize.bind(this); this.getBBOXandProjString = this.getBBOXandProjString.bind(this); this.isTouchDevice = this.isTouchDevice.bind(this); this.getDimensionRequestString = this.getDimensionRequestString.bind(this); this.dateToISO8601 = this.dateToISO8601.bind(this); this.buildWMSGetMapRequest = this.buildWMSGetMapRequest.bind(this); this.abort = this.abort.bind(this); this.isBusy = this.isBusy.bind(this); this._makeInfoHTML = this._makeInfoHTML.bind(this); this.getLegendGraphicURLForLayer = this.getLegendGraphicURLForLayer.bind(this); this.showScaleBar = this.showScaleBar.bind(this); this.hideScaleBar = this.hideScaleBar.bind(this); this.getMaxNumberOfAnimations = this.getMaxNumberOfAnimations.bind(this); this.drawLastTimes = this.drawLastTimes.bind(this); this.drawAutomatic = this.drawAutomatic.bind(this); this.display = this.display.bind(this); this.draw = this.draw.bind(this); this._draw = this._draw.bind(this); this._drawAndLoad = this._drawAndLoad.bind(this); this._drawReady = this._drawReady.bind(this); this._onLayersReadyCallbackFunction = this._onLayersReadyCallbackFunction.bind(this); this._onMapReadyCallbackFunction = this._onMapReadyCallbackFunction.bind(this); this._onResumeSuspendCallbackFunction = this._onResumeSuspendCallbackFunction.bind(this); this._animFrameRedraw = this._animFrameRedraw.bind(this); this.getWMSRequests = this.getWMSRequests.bind(this); this.prefetch = this.prefetch.bind(this); this.getImageStore = this.getImageStore.bind(this); this.isThisRequestLoaded = this.isThisRequestLoaded.bind(this); this._pdraw = this._pdraw.bind(this); this._updateBoundingBox = this._updateBoundingBox.bind(this); this.flipBuffers = this.flipBuffers.bind(this); this.getBackBufferCanvasContext = this.getBackBufferCanvasContext.bind(this); this.getFrontBufferCanvasContext = this.getFrontBufferCanvasContext.bind(this); this.redrawBuffer = this.redrawBuffer.bind(this); this.addBaseLayers = this.addBaseLayers.bind(this); this.setBaseLayers = this.setBaseLayers.bind(this); this.getBaseLayers = this.getBaseLayers.bind(this); this.getNumLayers = this.getNumLayers.bind(this); this.getBaseElement = this.getBaseElement.bind(this); this.flyZoomToBBOXTimerFunc = this.flyZoomToBBOXTimerFunc.bind(this); this.flyZoomToBBOXStop = this.flyZoomToBBOXStop.bind(this); this.flyZoomToBBOXStartZoom = this.flyZoomToBBOXStartZoom.bind(this); this.mouseWheelEvent = this.mouseWheelEvent.bind(this); this.pinchStart = this.pinchStart.bind(this); this.pinchMove = this.pinchMove.bind(this); this.pinchEnd = this.pinchEnd.bind(this); this.destroy = this.destroy.bind(this); this.detachEvents = this.detachEvents.bind(this); this.attachEvents = this.attachEvents.bind(this); this._getCorrectWMSDimName = this._getCorrectWMSDimName.bind(this); this._getMapDimURL = this._getMapDimURL.bind(this); this._buildLayerDims = this._buildLayerDims.bind(this); this.getMapMode = this.getMapMode.bind(this); this.getWMSMetaDataRequestURL = this.getWMSMetaDataRequestURL.bind(this); this.getPointInfoRequestURL = this.getPointInfoRequestURL.bind(this); this.getWMSGetFeatureInfoRequestURL = this.getWMSGetFeatureInfoRequestURL.bind(this); this.featureInfoRequestReady = this.featureInfoRequestReady.bind(this); this.newGetPointInfo = this.newGetPointInfo.bind(this); this.getPointInfo = this.getPointInfo.bind(this); this.newGetFeatureInfo = this.newGetFeatureInfo.bind(this); this.getFeatureInfo = this.getFeatureInfo.bind(this); this.getGetFeatureInfoObjectAsHTML = this.getGetFeatureInfoObjectAsHTML.bind(this); this.getMapPinXY = this.getMapPinXY.bind(this); this.positionMapPinByLatLon = this.positionMapPinByLatLon.bind(this); this.repositionMapPin = this.repositionMapPin.bind(this); this.setMapPin = this.setMapPin.bind(this); this.isMapPinVisible = this.isMapPinVisible.bind(this); this.showMapPin = this.showMapPin.bind(this); this.hideMapPin = this.hideMapPin.bind(this); this.setMapModeGetInfo = this.setMapModeGetInfo.bind(this); this.setMapModeZoomBoxIn = this.setMapModeZoomBoxIn.bind(this); this.setMapModeZoomOut = this.setMapModeZoomOut.bind(this); this.setMapModePan = this.setMapModePan.bind(this); this.setMapModePoint = this.setMapModePoint.bind(this); this.setMapModeNone = this.setMapModeNone.bind(this); this.getMouseCoordinatesForDocument = this.getMouseCoordinatesForDocument.bind(this); this.getMouseCoordinatesForElement = this.getMouseCoordinatesForElement.bind(this); this.mouseDown = this.mouseDown.bind(this); this._checkInvalidMouseAction = this._checkInvalidMouseAction.bind(this); this.updateMouseCursorCoordinates = this.updateMouseCursorCoordinates.bind(this); this.mouseDownEvent = this.mouseDownEvent.bind(this); this.mouseMoveEvent = this.mouseMoveEvent.bind(this); this.mouseUpEvent = this.mouseUpEvent.bind(this); this.mouseMove = this.mouseMove.bind(this); this.mouseUp = this.mouseUp.bind(this); this._mouseDragStart = this._mouseDragStart.bind(this); this.mouseDrag = this.mouseDrag.bind(this); this.mouseDragEnd = this.mouseDragEnd.bind(this); this._mapPanStart = this._mapPanStart.bind(this); this._mapPan = this._mapPan.bind(this); this._mapPanEnd = this._mapPanEnd.bind(this); this._mapZoomStart = this._mapZoomStart.bind(this); this._mapZoom = this._mapZoom.bind(this); this._mapZoomEnd = this._mapZoomEnd.bind(this); this.setCursor = this.setCursor.bind(this); this.getId = this.getId.bind(this); this.zoomTo = this.zoomTo.bind(this); this.pixelCoordinatesToXY = this.pixelCoordinatesToXY.bind(this); this.getGeoCoordFromPixelCoord = this.getGeoCoordFromPixelCoord.bind(this); this.getProj4 = this.getProj4.bind(this); this.getPixelCoordFromLatLong = this.getPixelCoordFromLatLong.bind(this); this.WCJSSearchRequest = this.WCJSSearchRequest.bind(this); this.WCJSSearchRequestGeoNames = this.WCJSSearchRequestGeoNames.bind(this); this.calculateBoundingBoxAndZoom = this.calculateBoundingBoxAndZoom.bind(this); this.getLatLongFromPixelCoord = this.getLatLongFromPixelCoord.bind(this); this.getPixelCoordFromGeoCoord = this.getPixelCoordFromGeoCoord.bind(this); this.addListener = this.addListener.bind(this); this.removeListener = this.removeListener.bind(this); this.getListener = this.getListener.bind(this); this.suspendEvent = this.suspendEvent.bind(this); this.resumeEvent = this.resumeEvent.bind(this); this.getDimensionList = this.getDimensionList.bind(this); this.getDimension = this.getDimension.bind(this); this.setDimension = this.setDimension.bind(this); this.setLayerOpacity = this.setLayerOpacity.bind(this); this.zoomToLayer = this.zoomToLayer.bind(this); this.setPreviousExtent = this.setPreviousExtent.bind(this); this.setNextExtent = this.setNextExtent.bind(this); this.setBBOX = this.setBBOX.bind(this); this.zoomOut = this.zoomOut.bind(this); this.zoomIn = this.zoomIn.bind(this); this.searchForLocation = this.searchForLocation.bind(this); this.displayLegendInMap = this.displayLegendInMap.bind(this); this.showBoundingBox = this.showBoundingBox.bind(this); this.hideBoundingBox = this.hideBoundingBox.bind(this); this.clearImageStore = this.clearImageStore.bind(this); this._adagucBeforeDraw = this._adagucBeforeDraw.bind(this); this._adagucBeforeCanvasDisplay = this._adagucBeforeCanvasDisplay.bind(this); this.displayScaleBarInMap = this.displayScaleBarInMap.bind(this); if (!jquery) { console.warn('WMJSMap: jquery is not defined, assuming unit test is running'); return; } this.loadingDiv = jquery('<div class="WMJSDivBuffer-loading"/>', {}); this.init(); }; setBaseURL (_baseURL) { this.base = _baseURL; this.noimage = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; this.loadingImageSrc = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; this.WMSControlsImageSrc = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; }; showDialogs (shouldShow) { this.showDialog = shouldShow; }; setXML2JSONURL (_xml2jsonrequest) { this.xml2jsonrequest = _xml2jsonrequest; }; setWMJSTileRendererTileSettings (_WMJSTileRendererTileSettings) { this.tileRenderSettings = _WMJSTileRendererTileSettings; }; getLegendStore () { return legendImageStore; }; /** * Function which make a component ID which is unique over several WebMapJS instances * @param the desired id * @return the unique id */ makeComponentId (id) { let availableId = 'WebMapJSMapNo_' + WebMapJSMapNo; if (!this.mainElement.id) { for (const testDestroyed in WebMapJSMapInstanceIds) { if (WebMapJSMapInstanceIds[testDestroyed] === false) { availableId = testDestroyed; this.hasGeneratedId = true; break; } } this.mainElement.id = availableId; WebMapJSMapInstanceIds[this.mainElement.id] = true; } if (this.hasGeneratedId === false) { this.hasGeneratedId = true; WebMapJSMapNo++; } return this.mainElement.id + '_' + id; }; enableInlineGetFeatureInfo (trueOrFalse) { this.inlineGetFeatureInfo = trueOrFalse; }; dialogClosed (dialog) { for (let j = 0; j < this.gfiDialogList.length; j++) { if (this.gfiDialogList[j] === dialog) { this.gfiDialogList.splice(j, 1); j--; } } }; closeAllGFIDialogs () { new WMJSDialog().closeAllDialogs(this.gfiDialogList); }; onLegendCallbackFunction () { if (enableConsoleDebugging)console.log('onlegendready called'); this.loadLegendInline(); }; /* Load legend inline of the map */ loadLegendInline (somethingchanged) { // try { // if (isDefined(somethingchanged) === false) { // somethingchanged = false; // } // if (this.legendBusy === true && isDefined(this.onLegendCallbackFunction)) { // if (this.callBack.addToCallback('onlegendready', this.onLegendCallbackFunction) === true) { // if (enableConsoleDebugging)console.log('Suspending on onlegendready'); // } // return; // } // this.legendBusy = true; // if (this.loadedLegendUrls.length !== this.layers.length) { // somethingchanged = true; // } else { // for (let j = 0; j < this.layers.length; j++) { // let legendUrl = this.getLegendGraphicURLForLayer(this.layers[j]); // if (isDefined(legendUrl)) { // if (this.loadedLegendUrls[j] !== legendUrl) { // this.loadedLegendUrls[j] = legendUrl; // somethingchanged = true; // } // } // } // } // if (somethingchanged) { // this.loadedLegendUrls = []; // for (let j = 0; j < this.layers.length; j++) { // if (this.layers[j].enabled !== false) { // let legendUrl = this.getLegendGraphicURLForLayer(this.layers[j]); // // if (isDefined(legendUrl)) { // this.loadedLegendUrls[j] = legendUrl; // } // } // } // // if (somethingchanged){ // console.log( this.loadedLegendUrls); // } // return; // } // // } catch (e) { // console.log(e); // } // this.legendBusy = false; // this.callBack.triggerEvent('onlegendready'); }; setMessage (message) { if (!message || message === '') { this.setMessageValue = ''; } else { this.setMessageValue = message; } }; setTimeOffset (message) { if (!message || message === '') { this.setTimeOffsetValue = ''; } else { this.setTimeOffsetValue = message; } }; _adagucBeforeDraw (ctx) { if (this.baseLayers) { for (let l = 0; l < this.baseLayers.length; l++) { if (this.baseLayers[l].enabled) { if (this.baseLayers[l].keepOnTop === false) { if (this.baseLayers[l].type && this.baseLayers[l].type !== 'twms') continue; if (!this.tileRenderSettings) { console.log('tileRenderSettings not set'); continue; } const { attributionText } = this.wmjsTileRenderer.render( this.bbox, this.updateBBOX, this.srs, this.width, this.height, ctx, bgMapImageStore, this.tileRenderSettings, this.baseLayers[l].name ); { const adagucAttribution = ('ADAGUC webmapjs ' + this.WebMapJSMapVersion); const txt = attributionText ? (adagucAttribution + ' | ' + attributionText) : adagucAttribution; const x = this.width - 8; const y = this.height - 8; ctx.font = '10px Arial'; ctx.textAlign = 'right'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#FFF'; ctx.globalAlpha = 0.75; const width = ctx.measureText(txt).width; ctx.fillRect(x - (width), y - 6, (width) + 8, parseInt(14)); ctx.fillStyle = '#444'; ctx.globalAlpha = 1.0; ctx.fillText(txt, x + 4, y + 2); } } } } } } _adagucBeforeCanvasDisplay (ctx) { const drawTextBG = (ctx, txt, x, y, fontSize) => { ctx.textBaseline = 'top'; ctx.textAlign = 'left'; ctx.fillStyle = '#FFF'; ctx.globalAlpha = 0.75; const width = ctx.measureText(txt).width; ctx.fillRect(x - 8, y - 8, width + 16, parseInt(fontSize) + 14); ctx.fillStyle = '#444'; ctx.globalAlpha = 1.0; ctx.fillText(txt, x, y + 2); }; // console.log('adagucBeforeCanvasDisplay' + this.getId()); /* Map Pin */ if (this.divMapPin.displayMapPin) { WMJSDrawMarker(ctx, this.divMapPin.x, this.divMapPin.y, '#9090FF', '#000'); } if (this._displayLegendInMap) { /* Draw legends */ let legendPosX = 0; for (let j = 0; j < this.layers.length; j++) { if (this.layers[j].enabled !== false) { let legendUrl = this.getLegendGraphicURLForLayer(this.layers[j]); if (isDefined(legendUrl)) { let image = legendImageStore.getImage(legendUrl, { headers: this.layers[j].headers }); if (image.hasError() === false) { if (image.isLoaded() === false && image.isLoading() === false) { image.load(); } else { let el = image.getElement()[0]; let legendW = parseInt(el.width) + 4; let legendH = parseInt(el.height) + 4; legendPosX += (legendW + 4); let legendX = this.width - legendPosX + 2; let legendY = this.height - (legendH) - 2 - 13; ctx.beginPath(); ctx.fillStyle = '#FFFFFF'; ctx.lineWidth = 0.3; ctx.globalAlpha = 0.5; ctx.strokeStyle = '#000000'; ctx.rect(parseInt(legendX) + 0.5, parseInt(legendY) + 0.5, legendW, legendH); ctx.fill(); ctx.stroke(); ctx.globalAlpha = 1.0; try { ctx.drawImage(el, legendX, legendY); } catch (e) { error('Unable to draw legend image ' + legendUrl); } } } } } } } /* Map header */ if (this.isMapHeaderEnabled) { ctx.beginPath(); ctx.rect(0, 0, this.width, this.mapHeader.height); if (this.mapIsActivated === false) { ctx.globalAlpha = this.mapHeader.hovering ? this.mapHeader.hover.opacity : this.mapHeader.fill.opacity; ctx.fillStyle = this.mapHeader.hovering ? this.mapHeader.hover.color : this.mapHeader.fill.color; } else { ctx.globalAlpha = this.mapHeader.hovering ? this.mapHeader.hoverSelected.opacity : this.mapHeader.selected.opacity; ctx.fillStyle = this.mapHeader.hovering ? this.mapHeader.hoverSelected.color : this.mapHeader.selected.color; } ctx.fill(); ctx.globalAlpha = 1; } /* Gather errors */ for (let i = 0; i < this.layers.length; i++) { // let request = ''; for (let j = 0; j < this.layers[i].dimensions.length; j++) { // request += '&' + this._getCorrectWMSDimName(this.layers[i].dimensions[j].name); // request += '=' + URLEncode(this.layers[i].dimensions[j].currentValue); if (this.layers[i].dimensions[j].currentValue === WMJSDateOutSideRange) { this.canvasErrors.push({ linkedInfo: { layer:this.layers[i], message: 'Time outside range' } }); } else if (this.layers[i].dimensions[j].currentValue === WMJSDateTooEarlyString) { this.canvasErrors.push({ linkedInfo:{ layer:this.layers[i], message: 'Time too early' } }); } else if (this.layers[i].dimensions[j].currentValue === WMJSDateTooLateString) { this.canvasErrors.push({ linkedInfo:{ layer:this.layers[i], message: 'Time too late' } }); } } } /* Display errors found during drawing canvas */ if (this.canvasErrors && this.canvasErrors.length > 0) { let mw = this.width / 2; let mh = 6 + this.canvasErrors.length * 15; let mx = this.width - mw; let my = this.isMapHeaderEnabled ? this.mapHeader.height : 0; ctx.beginPath(); ctx.rect(mx, my, mx + mw, my + mh); ctx.fillStyle = 'white'; ctx.globalAlpha = 0.9; ctx.fill(); ctx.globalAlpha = 1; ctx.fillStyle = 'black'; ctx.font = '10pt Helvetica'; ctx.textAlign = 'left'; for (let j = 0; j < this.canvasErrors.length; j++) { if (this.canvasErrors[j].linkedInfo) { let message = this.canvasErrors[j].linkedInfo.message ? ', ' + this.canvasErrors[j].linkedInfo.message : ''; ctx.fillText('Layer with title ' + this.canvasErrors[j].linkedInfo.layer.title + ' failed to load' + message, mx + 5, my + 11 + j * 15); } else { ctx.fillText('Layer failed to load.', mx + 5, my + 11 + j * 15); } } this.canvasErrors = []; } // Time offset message if (this.setTimeOffsetValue !== '') { ctx.font = '20px Helvetica'; drawTextBG(ctx, this.setTimeOffsetValue, (this.width / 2) - 70, this.height - 26, 20); } // Set message value if (this.setMessageValue !== '') { ctx.font = '15px Helvetica'; drawTextBG(ctx, this.setMessageValue, (this.width / 2) - 70, 2, 15); } // ScaleBar if (this.showScaleBarInMap === true) { let getScaleBarProperties = () => { let desiredWidth = 25; let realWidth = 0; let numMapUnits = 1.0 / 10000000.0; let boxWidth = this.updateBBOX.right - this.updateBBOX.left; let pixelsPerUnit = this.width / boxWidth; if (pixelsPerUnit <= 0) { return; } let a = desiredWidth / pixelsPerUnit; let divFactor = 0; do { numMapUnits *= 10.0; divFactor = a / numMapUnits; if (divFactor === 0) return; realWidth = desiredWidth / divFactor; } while (realWidth < desiredWidth); do { numMapUnits /= 2.0; divFactor = a / numMapUnits; if (divFactor === 0) return; realWidth = desiredWidth / divFactor; } while (realWidth > desiredWidth); do { numMapUnits *= 1.2; divFactor = a / numMapUnits; if (divFactor === 0) return; realWidth = desiredWidth / divFactor; } while (realWidth < desiredWidth); let roundedMapUnits = numMapUnits; let d = Math.pow(10, Math.round(Math.log10(numMapUnits) + 0.5) - 1); roundedMapUnits = Math.round(roundedMapUnits / d); if (roundedMapUnits < 2.5)roundedMapUnits = 2.5; if (roundedMapUnits > 2.5 && roundedMapUnits < 7.5)roundedMapUnits = 5; if (roundedMapUnits > 7.5)roundedMapUnits = 10; roundedMapUnits = (roundedMapUnits * d); divFactor = (desiredWidth / pixelsPerUnit) / roundedMapUnits; realWidth = desiredWidth / divFactor; return { width:parseInt(realWidth), mapunits: roundedMapUnits }; }; let scaleBarProps = getScaleBarProperties(); if (scaleBarProps) { let offsetX = 7.5; let offsetY = this.height - 25.5; let scaleBarHeight = 23; ctx.beginPath(); ctx.lineWidth = 2.5; ctx.fillStyle = '#000'; ctx.strokeStyle = '#000'; ctx.font = '9px Helvetica'; ctx.textBaseline = 'middle'; ctx.textAlign = 'left'; for (let j = 0; j < 2; j++) { ctx.moveTo(offsetX, scaleBarHeight - 2 - j + offsetY); ctx.lineTo(scaleBarProps.width * 2 + offsetX + 1, scaleBarHeight - 2 - j + offsetY); } let subDivXW = parseInt(Math.round(scaleBarProps.width / 5)); ctx.lineWidth = 0.5; for (let j = 1; j < 5; j++) { ctx.moveTo(offsetX + subDivXW * j, scaleBarHeight - 2 + offsetY); ctx.lineTo(offsetX + subDivXW * j, scaleBarHeight - 2 - 5 + offsetY); } ctx.lineWidth = 1.0; ctx.moveTo(offsetX, scaleBarHeight - 2 + offsetY); ctx.lineTo(offsetX, scaleBarHeight - 2 - 7 + offsetY); ctx.moveTo(offsetX + scaleBarProps.width, scaleBarHeight - 2 + offsetY); ctx.lineTo(offsetX + scaleBarProps.width, scaleBarHeight - 2 - 7 + offsetY); ctx.moveTo(offsetX + scaleBarProps.width * 2 + 1, scaleBarHeight - 2 + offsetY); ctx.lineTo(offsetX + scaleBarProps.width * 2 + 1, scaleBarHeight - 2 - 7 + offsetY); let units = ''; if (this.srs === 'EPSG:3411') units = 'meter'; if (this.srs === 'EPSG:3412') units = 'meter'; if (this.srs === 'EPSG:3575') units = 'meter'; if (this.srs === 'EPSG:4326') units = 'degrees'; if (this.srs === 'EPSG:28992') units = 'meter'; if (this.srs === 'EPSG:32661') units = 'meter'; if (this.srs === 'EPSG:3857') units = 'meter'; if (this.srs === 'EPSG:900913') units = 'meter'; if (this.srs === 'EPSG:102100') units = 'meter'; if (units === 'meter') { if (scaleBarProps.mapunits > 1000) { scaleBarProps.mapunits /= 1000; units = 'km'; } } ctx.fillText('0', offsetX - 3, 12 + offsetY); // valueStr.print("%g",(p.mapunits)); let valueStr = scaleBarProps.mapunits.toPrecision() + ''; ctx.fillText(valueStr, offsetX + scaleBarProps.width - valueStr.length * 2.5 + 0, 12 + offsetY); valueStr = (scaleBarProps.mapunits * 2).toPrecision() + ''; ctx.fillText(valueStr, offsetX + scaleBarProps.width * 2 - valueStr.length * 2.5 + 0, 12 + offsetY); ctx.fillText(units, offsetX + scaleBarProps.width * 2 + 10, 18 + offsetY); ctx.stroke(); } } if (this.showInfoInMap === true) { // Mouse projected coords ctx.font = '10px Helvetica'; ctx.textBaseline = 'middle'; if (isDefined(this.mouseGeoCoordXY)) { let roundingFactor = 1.0 / Math.pow(10, parseInt(Math.log((this.bbox.right - this.bbox.left) / this.width) / Math.log(10)) - 2); if (roundingFactor < 1)roundingFactor = 1; ctx.fillStyle = '#000000'; let xText = Math.round(this.mouseGeoCoordXY.x * roundingFactor) / roundingFactor; let yText = Math.round(this.mouseGeoCoordXY.y * roundingFactor) / roundingFactor; let units = ''; if (this.srs === 'EPSG:3857') { units = 'meter'; } ctx.fillText('CoordYX: (' + yText + ', ' + xText + ') ' + units, 5, this.height - 50); } // Mouse latlon coords if (isDefined(this.mouseUpdateCoordinates)) { let llCoord = this.getLatLongFromPixelCoord(this.mouseUpdateCoordinates); if (isDefined(llCoord)) { let roundingFactor = 100; ctx.fillStyle = '#000000'; let xText = Math.round(llCoord.x * roundingFactor) / roundingFactor; let yText = Math.round(llCoord.y * roundingFactor) / roundingFactor; ctx.fillText('Lat/Lon: (' + yText.toFixed(2) + ', ' + xText.toFixed(2) + ') ' + ' degrees', 5, this.height - 38); } } ctx.fillStyle = '#000000'; ctx.fillText('Map projection: ' + this.srs, 5, this.height - 26); // ctx.font = '7px Helvetica'; // ctx.fillText('ADAGUC webmapjs ' + this.WebMapJSMapVersion, this.width - 85, this.height - 5); } } /* Is called when the WebMapJS object is created */ init () { try { // eslint-disable-next-line no-undef if (geoNamesURL) { // eslint-disable-next-line no-undef this.geoNamesURL = geoNamesURL; } } catch (e) { } try { // eslint-disable-next-line no-undef if (defaultUsernameSearch) { // eslint-disable-next-line no-undef this.defaultUsernameSearch = defaultUsernameSearch; } } catch (e) { } try { // eslint-disable-next-line no-undef if (xml2jsonrequestURL) { // eslint-disable-next-line no-undef this.setXML2JSONURL(xml2jsonrequestURL); } } catch (e) { } try { // eslint-disable-next-line no-undef if (WMJSTileRendererTileSettings) { // eslint-disable-next-line no-undef this.setWMJSTileRendererTileSettings(WMJSTileRendererTileSettings); } } catch (e) { } if (!this.mainElement) { return; } if (this.mainElement.style) { if (!this.mainElement.style.height) { this.mainElement.style.height = '1px'; } if (!this.mainElement.style.width) { this.mainElement.style.width = '1px'; } } this.baseDivId = this.makeComponentId('baseDiv'); jquery('<div/>', { id:this.baseDivId, css: { position:'relative', overflow:'hidden', width: this.mainElement.clientWidth, height: this.mainElement.clientHeight, border:'0px solid black', margin:0, padding:0, clear:'both', left:'0px', top:'0px' } }).appendTo(this.mainElement); this.baseDiv = jquery('#' + this.baseDivId); this.baseDiv.css('cursor', 'default'); this.mainElement.style.margin = '0px'; this.mainElement.style.padding = '0px'; this.mainElement.style.border = 'none';// "1px solid gray"; this.mainElement.style.lineHeight = '0px'; this.mainElement.style.display = 'inline-block'; // Attach zoombox this.divZoomBox.style.position = 'absolute'; this.divZoomBox.style.display = 'none'; this.divZoomBox.style.border = '2px dashed #000000'; this.divZoomBox.style.margin = '0px'; this.divZoomBox.style.padding = '0px'; this.divZoomBox.style.lineHeight = '0'; this.divZoomBox.style.background = '#AFFFFF'; this.divZoomBox.style.opacity = '0.3'; // Gecko this.divZoomBox.style.filter = 'alpha(opacity=30)'; // Windows this.divZoomBox.style.left = '0px'; this.divZoomBox.style.top = '0px'; this.divZoomBox.style.width = '100px'; this.divZoomBox.style.height = '100px'; this.divZoomBox.style.zIndex = 1000; this.divZoomBox.oncontextmenu = () => { return false; }; this.baseDiv.append(this.divZoomBox); // Attach bbox box this.divBoundingBox.style.position = 'absolute'; this.divBoundingBox.style.display = 'none'; this.divBoundingBox.style.border = '3px solid #6060FF'; this.divBoundingBox.style.margin = '0px'; this.divBoundingBox.style.padding = '0px'; this.divBoundingBox.style.lineHeight = '0'; this.divBoundingBox.style.left = '0px'; this.divBoundingBox.style.top = '0px'; this.divBoundingBox.style.width = '100px'; this.divBoundingBox.style.height = '100px'; this.divBoundingBox.style.zIndex = 1000; this.divBoundingBox.oncontextmenu = () => { return false; }; this.baseDiv.append(this.divBoundingBox); /* Attach divDimInfo */ this.divDimInfo.style.position = 'absolute'; this.divDimInfo.style.zIndex = 1000; this.divDimInfo.style.width = 'auto'; this.divDimInfo.style.height = 'auto'; this.divDimInfo.style.background = 'none'; this.divDimInfo.oncontextmenu = () => { return false; }; this.divDimInfo.innerHTML = ''; this.baseDiv.append(this.divDimInfo); /* Attach loading image */ this.baseDiv.append(this.loadingDiv); /* ONLY VISIBLE IF USERNAME FOR GEONAMES API IS SET */ if (typeof (defaultUsernameSearch) !== 'undefined') { /* Creating the div for the input */ jquery('<div/>', { id: this.makeComponentId('searchboxdiv'), mousedown:(event) => { event.stopPropagation(); } }).addClass('webmapjs_searchboxdiv').html('<input class=\'webmapjs_locationfield\' type=\'text\' name=\'searchtextfield\'' + ' id=\'searchtextfield\' placeholder=' + I18n.place_search_term.text + ' />', { mousedown:(event) => { event.stopPropagation(); preventdefaultEvent(event); } }) .appendTo(this.baseDiv); jquery('<button/>', { id: this.makeComponentId('searchboxbutton'), mousedown:(event) => { event.stopPropagation(); }, click:() => { let value = jquery('#searchtextfield').val(); this.searchForLocation(value); } }).addClass('webmapjs_locationbutton').appendTo(this.baseDiv); /* On Enter */ jquery('#searchtextfield').keypress((e) => { if (e.which === 13) { let value = jquery('#searchtextfield').val(); this.searchForLocation(value); return false; } }); } /* Attach events */ this.attachEvents(); this.bbox.left = -180; this.bbox.bottom = -90; this.bbox.right = 180; this.bbox.top = 90; this.srs = 'EPSG:4326'; this.setSize(this.mainElement.clientWidth, this.mainElement.clientHeight); // IMAGE buffers for (let j = 0; j < 2; j++) { let d = new WMJSCanvasBuffer(this.callBack, 'imagebuffer', getMapImageStore, this.getWidth(), this.getHeight(), { beforecanvasstartdraw: this._adagucBeforeDraw, beforecanvasdisplay: this._adagucBeforeCanvasDisplay, canvasonerror: (e) => { this.canvasErrors = e; } }); getMapImageStore.addLoadEventCallback(d.imageLoadComplete, this.mainElement.id, 'getMapImageStore'); this.baseDiv.append(d.getBuffer()); this.divBuffer.push(d); } legendImageStore.addLoadEventCallback(() => { this.draw('legendImageStore loaded'); }, this.mainElement.id, 'legendImageStore'); this.callBack.addToCallback('display', this.display, true); this.callBack.addToCallback('draw', () => { console.log('draw event triggered externally, skipping'); }, true); // callBack.addToCallback("drawbuffers",this.flipBuffers,true); bgMapImageStore.addLoadEventCallback(() => { this.draw('bgMapImageStore loaded'); }, this.mainElement.id, 'bgMapImageStore'); this._updateBoundingBox(this.bbox); this.wmjsAnimate = new WMJSAnimate(this); this.wmjsTileRenderer = new WMJSTileRenderer(); this.initialized = 1; }; rebuildMapDimensions () { for (let j = 0; j < this.mapdimensions.length; j++) { this.mapdimensions[j].used = false; } for (let i = 0; i < this.layers.length; i++) { for (let j = 0; j < this.layers[i].dimensions.length; j++) { let dim = this.layers[i].dimensions[j]; let mapdim = this.getDimension(dim.name); if (isDefined(mapdim)) { mapdim.used = true; } else { let newdim = dim.clone(); newdim.used = true; this.mapdimensions.push(newdim); } } } for (let j = 0; j < this.mapdimensions.length; j++) { if (this.mapdimensions[j].used === false) { this.mapdimensions.splice(j, 1); j--; } } this.callBack.triggerEvent('onmapdimupdate'); }; getLayerByServiceAndName (layerService, layerName) { for (let j = 0; j < this.layers.length; j++) { let layer = this.layers[this.layers.length - j - 1]; if (layer.name === layerName) { if (layer.service === layerService) { return layer; } } } }; getLayers () { /* Provide layers in reverse order */ let returnlayers = []; for (let j = 0; j < this.layers.length; j++) { let layer = this.layers[this.layers.length - j - 1]; returnlayers.push(layer); } return returnlayers; }; setLayer (layer, getcapdoc) { return this.addLayer(layer, getcapdoc, layer); }; /* Indicate weather this map component is active or not */ setActive (active) { this.mapIsActivated = active; this.isMapHeaderEnabled = true; }; setActiveLayer (layer) { for (let j = 0; j < this.layers.length; j++) { this.layers[j].active = false; } this.activeLayer = layer; this.activeLayer.active = true; this.loadLegendInline(); this.callBack.triggerEvent('onchangeactivelayer'); }; // Calculates how many baselayers there are. // Useful when changing properties for a divbuffer index (for example setLayerOpacity) calculateNumBaseLayers () { this.numBaseLayers = 0; if (this.baseLayers) { for (let l = 0; l < this.baseLayers.length; l++) { if (this.baseLayers[l].enabled) { if (this.baseLayers[l].keepOnTop === false) { this.numBaseLayers++; } } } } }; enableLayer (layer) { layer.enabled = true; this.calculateNumBaseLayers(); this.rebuildMapDimensions(); this.loadLegendInline(true); }; disableLayer (layer) { layer.enabled = false; this.calculateNumBaseLayers(); this.rebuildMapDimensions(); this.loadLegendInline(true); }; toggleLayer (layer) { if (layer.enabled === true) { layer.enabled = false; } else layer.enabled = true; this.calculateNumBaseLayers(); this.rebuildMapDimensions(); this.loadLegendInline(true); }; displayLayer (layer, enabled) { layer.enabled = enabled; this.calculateNumBaseLayers(); this.rebuildMapDimensions(); this.loadLegendInline(true); }; _getLayerIndex (layer) { if (!layer) return; for (let j = 0; j < this.layers.length; j++) { if (this.layers[j] === layer) { return j; } } return -1; }; removeAllLayers () { for (let i = 0; i < this.layers.length; ++i) { this.layers[i].setAutoUpdate(false); } this.layers.length = 0; this.mapdimensions.length = 0; this.callBack.triggerEvent('onlayeradd'); }; deleteLayer (layerToDelete) { if (this.layers.length <= 0) return; layerToDelete.setAutoUpdate(false); let layerIndex = this._getLayerIndex(layerToDelete); if (layerIndex >= 0) { // move everything up with id's higher than this layer for (let j = layerIndex; j < this.layers.length - 1; j++) { this.layers[j] = this.layers[j + 1]; } this.layers.length--; this.activeLayer = undefined; if (layerIndex >= 0 && layerIndex < this.layers.length) { this.rebuildMapDimensions(); this.setActiveLayer(this.layers[layerIndex]); } else { if (this.layers.length > 0) { this.rebuildMapDimensions(); this.setActiveLayer(this.layers[this.layers.length - 1]); } } } this.callBack.triggerEvent('onlayerchange'); this.rebuildMapDimensions(); }; moveLayerDown (layerToMove) { let layerIndex = this._getLayerIndex(layerToMove); if (layerIndex > 0) { let layerToMoveDown = this.layers[layerIndex - 1]; let layer = this.layers[layerIndex]; if (layerToMoveDown && layer) { this.layers[layerIndex] = layerToMoveDown; this.layers[layerIndex - 1] = layer; } } else { try { error('moveLayerDown: layer \'' + layerToMove.name + '\' not found.'); } catch (e) { error('moveLayerDown: layer invalid.'); } } }; swapLayers (layerA, layerB) { // console.log('--- swap layers ---'); // for(let j = 0;j < this.layers.length; j++ ) { // console.log(j + '). Name: ' + this.layers[j].name); // } let layerIndexA = this._getLayerIndex(layerA); let layerIndexB = this._getLayerIndex(layerB); // console.log(layerIndexA, layerIndexB); if (layerIndexA >= 0 && layerIndexB >= 0) { let layerA = this.layers[layerIndexA]; let layerB = this.layers[layerIndexB]; // console.log(layerA.name, layerB.name); if (layerB && layerA) { this.layers[layerIndexA] = layerB; this.layers[layerIndexB] = layerA; } } else { try { error('moveLayers: layer \'' + layerA.name + '\' not found.'); } catch (e) { error('moveLayers: layer invalid.'); } } // console.log('---'); // for(let j = 0;j < this.layers.length; j++ ) { // console.log(j + '). Name: ' + this.layers[j].name); // } } moveLayerUp (layerToMove) { let layerIndex = this._getLayerIndex(layerToMove); if (layerIndex < this.layers.length - 1) { let layerToMoveUp = this.layers[layerIndex + 1]; let layer = this.layers[layerIndex]; if (layerToMoveUp && layer) { this.layers[layerIndex] = layerToMoveUp; this.layers[layerIndex + 1] = layer; } } else { try { error('moveLayerUp: layer \'' + layerToMove.name + '\' not found.'); } catch (e) { error('moveLayerUp: layer invalid.'); } } }; /** * @param layer of type WMJSLayer */ addLayer (layer) { if (!isDefined(layer)) { console.warn('add