/* (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. */ /** * The controller for the display/save local file tool. * * The controller defines the logic for locally displaying and saving * several geodata file formats. * Note that this requires additional external libraries * (e.g. shapefile-js and FileSaver.js, see Readme.md). * * To use the display file tool add the controller to the controllers * array in your app and activate the tool in the * {@link LGB.ext4map.view.Toolbar toolbar}. * Ext.application({ classicControllers: [ 'DisplayFile' ... ], ... }); */ Ext.define('LGB.ext4map.controller.DisplayFile', { extend: 'Ext.app.Controller', map: null, layerID: 2000, /** * @private * Initialize the controller and map the events to function. */ init: function() { var me = this; this.control({ 'geofiledisplay combobox': { change: me.formatChanged }, 'geofiledisplay button[action=showfile]': { click: me.showFile }, 'geofilesave button[action=savefile]': { click: me.saveFile } }); }, setMap: function(map) { this.map = map.map; }, formatChanged: function(combobox, newValue, oldValue, scope) { var oldPanel = combobox.up('window').down('panel[name='+oldValue+'Attributes]'); var newPanel = combobox.up('window').down('panel[name='+newValue+'Attributes]'); oldPanel.hide(); newPanel.show(); }, showFile: function(button) { var format = button.up('window').down('combobox').getValue(); var currentPanel = button.up('window').down('panel[name='+format+'Attributes]'); var projection = currentPanel.down('textfield[name=projection]').getValue(); var file = button.up('window').down('filefield').fileInputEl.dom.files[0]; if (!file) { return; } var fileName = file.name.toLowerCase(); if (format === 'csv' && fileName.match('.csv')) { var lat = currentPanel.down('textfield[name=lat]').getValue(); var lon = currentPanel.down('textfield[name=lon]').getValue(); this.displayCSV(file, projection, lat, lon); } else if (format === 'kml' && fileName.match('.kml')) { this.displayKML(file, projection); } else if (format === 'shp' && (fileName.match('.shp') || fileName.match('.zip'))) { this.displayShape(file, projection); } else if (format === 'json' && (fileName.match('.json') || fileName.match('.gjson') || fileName.match('.geojson'))) { this.displayGeoJSON(file, projection); } else if (format === 'txt' && (fileName.match('.txt') || fileName.match('.wkt'))) { this.displayWKT(file, projection); } else { Ext.Msg.alert('Fehler!', 'Dateiformat oder -endung passt nicht zum ausgewählten Format.'); } button.up('window').close(); }, displayCSV: function(file, projection, lat, lon) { var me = this; var reader = new FileReader(); reader.addEventListener('load', function() { var content = reader.result; var gj = csv2geojson.csv2geojson(content, { latfield: lat, lonfield: lon, delimiter: ',' }, function(err, data) { if (err) { Ext.Msg.alert('Fehler!', 'Die angegebene CSV-Datei konnte nicht verarbeitet werden.'); return; } me.createLayerFromJSON(data, file.name, projection); }); }); reader.readAsText(file); }, displayKML: function(file, proj) { var me = this; var reader = new FileReader(); reader.addEventListener('load', function() { var content = reader.result; var style = new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(255, 130, 37, 1)', width: 2 }), image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: 'rgba(255, 130, 37, 0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(255, 130, 37, 1)' }) }) }); var source = new ol.source.Vector({ features: (new ol.format.KML({ extractStyles: false, defaultStyle: style })).readFeatures(content) }); var layer = new ol.layer.Vector({ name: file.name, source: source, layerID: me.layerID, options: {} }); me.layerID++; me.map.addLayer(layer); var tree = Ext.ComponentQuery.query('layertree')[0]; var store = tree.store; var opts = { visibility: true, printable: false }; var mapProj = me.map.getView().getProjection().getCode() if (proj && proj !== '' && proj !== mapProj) { me.transformFeatures(layer, proj, mapProj) } me.validateAndAdd(layer, store, file.name, opts, me); }); reader.readAsText(file); }, displayShape: function(file, projection) { var me = this; var reader = new FileReader(); reader.addEventListener('load', function() { shp(reader.result).then(function(geojson) { if (geojson instanceof Array) { for (var i = 0; i < geojson.length; i++) { var tmp = file.name; tmp = tmp + '/' + geojson[i].fileName; me.createLayerFromJSON(geojson[i], tmp, projection); } } else { me.createLayerFromJSON(geojson, file.name, projection); } }); }); reader.readAsArrayBuffer(file); }, displayGeoJSON: function(file, projection) { var me = this; var reader = new FileReader(); reader.addEventListener('load', function() { var content = reader.result; me.createLayerFromJSON(content, file.name, projection); }); reader.readAsText(file); }, displayWKT: function(file, proj) { var me = this; var reader = new FileReader(); reader.addEventListener('load', function() { var content = reader.result; var source = new ol.source.Vector({ features: (new ol.format.WKT()).readFeatures(content) }); var style = new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(255, 130, 37, 1)', width: 2 }), image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: 'rgba(255, 130, 37, 0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(255, 130, 37, 1)' }) }) }); var layer = new ol.layer.Vector({ name: file.name, source: source, layerID: me.layerID, style: style, options: {} }); this.layerID++; me.map.addLayer(layer); var tree = Ext.ComponentQuery.query('layertree')[0]; var store = tree.store; var opts = { visibility: true, printable: false }; var mapProj = me.map.getView().getProjection().getCode() if (proj && proj !== '' && proj !== mapProj) { me.transformFeatures(layer, proj, mapProj) } me.validateAndAdd(layer, store, file.name, opts, me); }); reader.readAsText(file); }, createLayerFromJSON: function(json, file, proj) { var source = new ol.source.Vector({ features: (new ol.format.GeoJSON()).readFeatures(json) }); var layer = new ol.layer.Vector({ name: file, source: source, layerID: this.layerID, options: {} }); this.layerID++; this.map.addLayer(layer); var tree = Ext.ComponentQuery.query('layertree')[0]; var store = tree.store; var opts = { visibility: true, printable: false }; var mapProj = this.map.getView().getProjection().getCode() if (proj && proj !== '' && proj !== mapProj) { this.transformFeatures(layer, proj, mapProj) } this.validateAndAdd(layer, store, file, opts, this); }, transformFeatures: function(layer, srcProj, destProj) { var features = layer.getSource().getFeatures(); for (var i = 0; i < features.length; i++) { features[i].getGeometry().transform(srcProj, destProj); } }, validateAndAdd: function(layer, store, name, opts, me) { var maxExtent; var conf = me.application.appParams.map; var proj = me.map.getView().getProjection().getCode(); for (var i = 0; i < conf.length; i++) { if (conf[i].switcherValue === proj) { maxExtent = conf[i].maxExtent; } } var validator = Ext.create('LGB.ext4map.util.CoordinateValidator', { epsg: proj.replace('EPSG:', ''), bounds: maxExtent }); var extent = layer.getSource().getExtent() var fit = validator.validate([extent[0], extent[1]]) && validator.validate([extent[2], extent[3]]); if (fit) { store.addLayer(layer, name, opts, store.getRootNode()); me.map.getView().fit(layer.getSource().getExtent(), me.map.getSize()); me.application.fireEvent('layerstatechanged', layer); } else { Ext.Msg.alert('Fehler!', 'Die Projektion der Daten ist nicht korrekt oder<br> die Daten liegen ausserhalb des Anzeigebereichs.'); me.map.removeLayer(layer); } }, saveFile: function(button) { var win = button.up('window'); var items = win.down('panel[name=layerchoose]').items.items; var layers = []; var features = []; for (var i = 0; i < items.length; i++) { features = features.concat(items[i].layer.getSource().getFeatures()); } var format = win.down('combobox').getValue(); if (format === 'csv') { this.saveCSV(features); } else if (format === 'kml') { this.saveKML(features); } else if (format === 'shp') { this.saveSHP(features, this.map.getView().getProjection().getCode()); } else if (format === 'wkt' || format === 'txt') { this.saveWKT(features); } else if (format === 'json') { this.saveGeoJSON(features); } win.close(); }, saveCSV: function(features) { var heads = []; heads.push('x'); heads.push('y'); for (var i = 0; i < features.length; i++) { var properties = features[i].getKeys(); for (var j = 0; j < properties.length; j++) { if (properties[j] === 'geometry' || heads.includes(properties[j])) { continue; } heads.push(properties[j]); } } lines = []; lines.push(heads); for (var i = 0; i < features.length; i++) { if (!(features[i].getGeometry() instanceof ol.geom.Point)) { continue; } var items = []; items.push(features[i].getGeometry().getCoordinates()[0]); items.push(features[i].getGeometry().getCoordinates()[1]); for (var j = 2; j < heads.length; j++) { var value = features[i].get(heads[j]); if (!value) { items.push(''); } else { items.push(value); } } var stringItems = items.join(','); lines.push(stringItems); } var stringLines = lines.join('\r\n'); this.saveAs(stringLines, {type: 'text/plain;charset=utf-8'}, 'csv'); }, saveKML: function(features) { var kmlFormat = new ol.format.KML(); var kml = kmlFormat.writeFeatures(features); this.saveAs(kml, {type: 'text/plain;charset=utf-8'}, 'kml'); }, saveSHP: function(features, proj) { if (proj != 'EPSG:4326') { for (var i = 0; i < features.length; i++) { features[i].getGeometry().transform(proj, 'EPSG:4326'); } } var jsonFormat = new ol.format.GeoJSON(); var json = jsonFormat.writeFeaturesObject(features); var content = shpwrite.zip(json); var byteString = atob(content); var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } this.saveAs(ab, {type: 'application/zip'}, 'zip'); }, saveWKT: function(features) { var wktFormat = new ol.format.WKT(); var wkt = wktFormat.writeFeatures(features); this.saveAs(wkt, {type: 'text/plain;charset=utf-8'}, 'txt'); }, saveGeoJSON: function(features) { var jsonFormat = new ol.format.GeoJSON(); var json = jsonFormat.writeFeatures(features); this.saveAs(json, {type: 'text/plain;charset=utf-8'}, 'json'); }, saveAs: function(content, type, format) { var blob = new Blob([content], type); saveAs(blob, 'bbviewer.' + format); } });