/* (C) GeoBasis-DE/LGB * Copyright by Landesvermessung und Geobasisinformation Brandenburg (LGB) * * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (>=v3) * and comes with ABSOLUTELY NO WARRANTY! Check out the * LICENSE for details. */ /** * Loader for OpenLayers.Layer * * Creates layers from valid OpenLayers.Layer configurations. * The following layer types are supported by the loader: * - WMS * - WFS (V1.0.0,V1.1.0, V2.0) * - KML * * The loader can parse additional attributes to style the layer(WFS/KML) and * create groups and folders. * For WFS layers the attribute 'search' defines a set of search filters and * result sets. * * Example WMS layer configuration: * var layers = [{ name: "Standard", url: "http://isk.geobasis-bb.de/ows/dnm.php", type: "wms", params:{ layers: "bg,vegetation,gewaesser,siedlung,bln,brb,transport,verkehrsobjekte,strassennamen,ortsnamen,gewaessernamen", format: "image/png", BGCOLOR: '0xFFFFFF' }, options: { isBaseLayer: true, buffer: 0, visibility: true, "TILED": true, group: 'Kartenpräsentation', level: 'Geobasisdaten' } }, { * * Example WFS layer configuration: * name: "Öbvi-WFS", url: "http://isk.geobasis-bb.de/ows/oebvi.php", type: "wfs", options: { featureType: ['Alle', 'PotsdamMittelmark'], version: '1.1.0', visibility: false, group: 'WFS', level: 'Geobasisdaten' }, search: { types: [{ featureType: 'Alle', filter: ['nachname', 'plz'], result: [{ display: 'Vorname', name: 'vorname' }, { display: 'Nachname', name: 'nachname' }, { display: 'PLZ', name: 'plz' }] }] } }, { * * Example for KML layer configuration: * name: "Test", url: "test.kml", type: "kml", options: { featureSelect: true, showLabel: true, labelStyle: { fontColor: '#0000ff', fontOutlineColor: '#00ff00', fontOutlineWidth: 2, fontSize: '10px', labelAlign: 'cl' }, visibility: false, group: 'KML', level: 'Zusätzliche' } }] * * To load layers from a configuration like seen above use: * var loader = Ext.create('LGB.ext4map.util.LayerLoader',{}); loader.projection = 'EPSG:25833'; // Set the default projection var layerObjects = loader.load(layers); */ Ext.define('LGB.ext4map.util.LayerLoader', { requires: [ 'LGB.ext4map.util.StyleFunctionFactory', 'LGB.ext4map.util.Toolbox' ], /** * The layers. */ layers: [], toolbox: null, /** * The current projection. */ projection: 'EPSG:4326', mapOptions: [], layerCounter: 0, hasVisibleBaseLayer: false, permalinkIDs: new Ext.util.HashMap(), statics: { layerGroups:{}, baseLayers: [], addToGroup: function(layer, group) { if (Ext.isArray(this.layerGroups[group])) { LGB.ext4map.util.LayerLoader.layerGroups[group].push(layer); return; } LGB.ext4map.util.LayerLoader.layerGroups[group] = []; LGB.ext4map.util.LayerLoader.layerGroups[group].push(layer); }, addBaseLayer: function(layer) { LGB.ext4map.util.LayerLoader.baseLayers.push(layer); }, getLayerGroups: function() { return LGB.ext4map.util.LayerLoader.layerGroups; }, getBaseLayers: function() { return LGB.ext4map.util.LayerLoader.baseLayers; } }, /** * Replaces a placeholder object inside the layer list or the layer tree if already created */ asyncLayerLoaded: function(scope, id, layer) { // scope.layers[id] = layer; //If views are already created, insert layer directly var layertree = Ext.getCmp('layertree'); var map = Ext.getCmp('mapId'); //If layertree already exists, add async loaded layer there, else try to add to map if (layertree) { var options = layer.get('options'); layertree.addCustomLayer(layer, layer.get('name'), options.level, options.group, false, true); } else if (map) { map.layers.push(layer); } }, /** * Checks if the given permalinkID is already in use. * Returns true if id is available, else false */ isPermalinkIdAvailable: function(permalinkID) { return !this.permalinkIDs.get(permalinkID); }, /** * Get the layers loaded via the {@link LGB.ext4map.util.LayerLoader#load} * method. */ getLayers: function() { return this.layers; }, /** * Load the layers from a json config. * * Each config item contains a typical OpenLayers layer configuration. */ load: function(config, scope) { var me; if (scope) { me = scope; } else { me = this; } var layerconfig = config.layers; var nextSublayerId = layerconfig.length + 1; this.toolbox = Ext.create('LGB.ext4map.util.Toolbox'); this.toolbox.initProjections(this.mapOptions); if (this.mapOptions.length > 0) { this.projection = this.mapOptions[0].projection; this.mapOption = this.mapOptions[0]; } for (var i = 0; i < layerconfig.length; i++) { var cfg = layerconfig[i]; var ndx = cfg.options.isBaseLayer ? 0 : (cfg.options.index | 3); //Check if there are sublayers to load if (cfg.options && cfg.options.sublayers) { subCfg = cfg.options.sublayers; cfg.options.sublayers = []; for (var j = 0; j < subCfg.length; j++) { subCfg[j].options.isBaseLayer = false; subCfg[j].options.displayInLayerSwitcher = false; subCfg[j].options.visibility = cfg.options.visibility; subCfg[j].options.layerGroup = undefined; var subLayers = this.loadLayers(subCfg[j], nextSublayerId, ndx - 1, config.map[0]); nextSublayerId++; for (var k = 0; k < subLayers.length; k++) { subLayers[k].set('visible', cfg.options.visibility); cfg.options.sublayers.push(subLayers[k]); } } } var layerId = i + 1; var layers = this.loadLayers(cfg, layerId, ndx, config.map[0]); for (var j = 0; j < layers.length; j++) { me.layers.push(layers[j]); } } return me.layers; }, loadLayers: function(cfg, layerId, ndx, mapCfg) { var layers = []; if (cfg.type === 'wms') { layers.push(this.loadWMS(cfg, layerId, ndx, mapCfg)); } else if (cfg.type === 'wmts') { layers.push(this.loadWMTS(cfg, layerId, ndx)); } else if (cfg.type === 'wfs') { layers = this.loadWFS(cfg, layerId, ndx); } else if (cfg.type === 'csv') { layers.push(this.loadCSV(cfg, layerId, ndx)); } else if (cfg.type === 'kml') { layers.push(this.loadKML(cfg, layerId, ndx)); } return layers; }, loadWMS: function(config, layerId, ndx, mapCfg) { var me = this; if (config.options.TILED) { var gridOpts = { extent: mapCfg.maxExtent }; var resolutions = []; if (mapCfg.resolutions !== undefined) { resolutions = this.mapOption.resolutions; gridOpts.resolutions = resolutions; } else if (this.mapOption.scales !== undefined) { for (var j = 0; j < this.mapOption.scales.length; j++) { resolutions.push( this.toolbox.getResolutionFromScale(this.mapOption.scales[j], this.mapOption.units)); } gridOpts.resolutions = resolutions; } var layer = new ol.layer.Tile({ source: new ol.source.TileWMS({ url: config.url, params: config.params, wrapX: false, noWrap: true, tileGrid: new ol.tilegrid.TileGrid(gridOpts) }), name: config.name, zIndex: ndx, options: config.options, visible: config.options.visibility, layerID: layerId }); layer.getSource().on('tileloadstart', function() { me.layerCounter++; me.showLoadingIcon(); }); layer.getSource().on('tileloadend', function() { me.layerCounter--; me.hideLoadingIcon(); }); } else { var layer = new ol.layer.Image({ source: new ol.source.ImageWMS({ url: config.url, params: config.params }), name: config.name, zIndex: ndx, options: config.options, visible: config.options.visibility, layerID: layerId }); layer.getSource().on('imageloadstart', function() { me.layerCounter++; me.showLoadingIcon(); }); layer.getSource().on('imageloadend', function() { me.layerCounter--; me.hideLoadingIcon(); }); } if (config.options.opacity){ layer.setOpacity(config.options.opacity); } if (config.options.isBaseLayer && config.options.visibility ) { if (!me.hasVisibleBaseLayer) { me.hasVisibleBaseLayer = true; } else { layer.setVisible(false); } } this.setPermalinkID(layer, config); if (config.options.layerGroup) { LGB.ext4map.util.LayerLoader.addToGroup(layer, config.options.layerGroup); } return layer }, loadWMTS: function(config, layerId, ndx) { var me = this; var layer = new ol.layer.Tile({ extent: config.params.extent, source: new ol.source.WMTS({ url: config.url, layer: config.params.layer, matrixSet: config.params.matrixSet, projection: 'EPSG:25833', // TODO WHAAAT? Why hardcoded? format: config.params.format, tileGrid: new ol.tilegrid.WMTS({ origin: ol.extent.getTopLeft(config.params.extent), tileSize: config.params.tileSize, resolutions: config.params.resolutions, matrixIds: config.params.matrixIds }), style: config.params.style }), name: config.name, options: config.options, visible: config.options.visibility, layerID: layerId }); this.setPermalinkID(layer, config); layer.getSource().on('tileloadstart', function() { me.layerCounter++; me.showLoadingIcon(); }); layer.getSource().on('tileloadend', function() { me.layerCounter--; me.hideLoadingIcon(); }); if (config.options.isBaseLayer && config.options.visibility ) { if (!me.hasVisibleBaseLayer) { me.hasVisibleBaseLayer = true; } else { layer.setVisible(false); } } if (config.options.layerGroup) { LGB.ext4map.util.LayerLoader.addToGroup(layer, config.options.layerGroup); } return layer; }, loadWFS: function(config, layerId, ndx) { var me = this; var version = '1.1.0'; if (config.options.version) { version = config.options.version; } var layers = []; for (var j = 0; j < config.options.featureType.length; j++) { var type = config.options.featureType[j]; var namespace; if (config.options.featureNS) { namespace = config.options.featureNS; } else { namespace = 'http://mapserver.gis.umn.edu/mapserver'; } var str = (config.url.indexOf("?") != -1 ? config.url + "&" : config.url + "?") + "SERVICE=WFS&VERSION=" + version + "&REQUEST=GetFeature&TYPENAME=" + type + "&SRSNAME="; var source = new ol.source.Vector({ format: new ol.format.WFS({ featureNS: namespace, featureType: type, gmlFormat: new ol.format.GML3({ featureNS: namespace, featureType: type }) }), url: function() { var srcUrl = str; return function(bounds, resolution, projection) { var encoded = srcUrl + encodeURIComponent(projection.getCode()); return encoded; }; }() }); var stylecfg = config.options.style; var styleFunction = undefined; //If style is defined, create style function if (stylecfg) { var functionFactory = Ext.create('LGB.ext4map.util.StyleFunctionFactory'); var styleFunctionObj = functionFactory.createStyleFunction(stylecfg); styleFunction = styleFunctionObj.styleFunction; //Put all available styles in the layer object for later use in the legend config.options.styleObj = { defaultStyle: styleFunctionObj.defaultStyle, styleRules: styleFunctionObj.styleRules } } config.options.trueType = config.options.featureType[j]; config.options.format = config.type; var layer = new ol.layer.Vector({ name: config.name, source: source, visible: config.options.visibility, zIndex: config.options.index | 1, options: config.options, group: config.options.group, level: config.options.level, search: config.search, layerID: layerId + 1000 + j, style: styleFunction }); this.setPermalinkID(layer, config); if (config.options.layerGroup) { LGB.ext4map.util.LayerLoader.addToGroup(layer, config.options.layerGroup); } layers.push(layer); } return layers; }, loadCSV: function(config, layerId, ndx) { var me = this; var url = config.url; config.options.format = config.type; config.options.url = url; var source = new ol.source.Vector({ loader: function(extend, resolution, proj) { Ext.Ajax.request({ url: url, success: function(response) { var gj = csv2geojson.csv2geojson(response.responseText, { latfield: config.options.lat, lonfield: config.options.lon, delimiter: config.options.delimiter }, function(err, data) { if (err) { Ext.Msg.alert('Fehler!', 'Die angegebene CSV-Datei konnte nicht verarbeitet werden.'); return; } source.addFeatures((new ol.format.GeoJSON()).readFeatures(data)); }); }, failure: function(response) { Ext.Msg.alert('Fehler!', 'Die angegebene CSV-Datei konnte nicht geladen werden.'); } }); } }); var layer = new ol.layer.Vector({ name: config.name, source: source, visible: config.options.visibility, zIndex: config.options.index | 1, options: config.options, group: config.options.group, level: config.options.level, layerID: layerId }); this.setPermalinkID(layer, config); if (config.options.layerGroup) { LGB.ext4map.util.LayerLoader.addToGroup(layer, config.options.layerGroup); } return layer; }, loadKML: function(config, layerId, ndx) { var url = config.url; var extractStyles = true; var showPointNames = true; if (config.options.hasOwnProperty('extractStyles')) { extractStyles = config.options.extractStyles; } if (config.options.hasOwnProperty('showPointNames')) { showPointNames = config.options.showPointNames; } var format = new ol.format.KML({ extractStyles: extractStyles, showPointNames: showPointNames }); format.defaultDataProjection = ol.proj.get(config.projection); var source = new ol.source.Vector({ format: format, url: url }); config.options.format = config.type; config.options.url = url; var layer = new ol.layer.Vector({ name: config.name, source: source, visible: config.options.visibility, zIndex: config.options.index | 1, options: config.options, group: config.options.group, type: config.type, level: config.options.level, layerID: layerId }); this.setPermalinkID(layer, config); if (config.options.layerGroup) { LGB.ext4map.util.LayerLoader.addToGroup(layer, config.options.layerGroup); } if (layer.getVisible() == true) { layer.once('render', function(e){ var map = Ext.getCmp('mapId'); if (map.zoomToKml == true) { map.renderedKmlFeatures.push(e.target.getSource().getFeatures()); map.kmlLayersRendered++; map.zoomToKmlLayer(); } }); } return layer; }, setPermalinkID: function(layer, config) { if (!config.options.permalinkID) { Ext.raise('No permalinkID set for layer "' + layer.get('name') + '"'); } if (!this.isPermalinkIdAvailable(layer.get('options').permalinkID)) { Ext.raise('permalinkID "' + layer.get('options').permalinkID + '" is already used.') } else { this.permalinkIDs.add(layer.get('options').permalinkID, 1); } }, loadStart: function() { this.layerCounter++; this.showLoadingIcon(); }, loadEnd: function() { this.layerCounter--; this.hideLoadingIcon(); }, showLoadingIcon: function() { var loadingIcon = Ext.ComponentQuery.query('container[id=idLayerLoading]')[0]; if (loadingIcon) { loadingIcon.show(); } }, hideLoadingIcon: function() { if (this.layerCounter === 0) { var loadingIcon = Ext.ComponentQuery.query( 'container[id=idLayerLoading]')[0]; if (loadingIcon) { loadingIcon.hide(); } } }, /** * Get all layers with the attribute 'printable = false'. */ getPrintBlacklist: function() { var blacklist = []; for (var i = 0; i < this.layers.length; i++) { if (this.layers[i].get('options').printable != undefined && this.layers[i].get('options').printable == false) { blacklist.push(this.layers[i]); } } return blacklist; }, /** * Remove all layers previously loaded. */ clear: function() { this.layers = []; } });