From 80a9d819effb65bb72a0c2693b0661541938778c Mon Sep 17 00:00:00 2001 From: saricicekibrahim Date: Tue, 25 Dec 2018 21:10:36 +0300 Subject: [PATCH 1/3] added shapefile & geojson templaye layer support --- app/static/app/js/classes/TemplateLayer.js | 103 +++++++++++++++++++++ app/static/app/js/components/Map.jsx | 60 +++++++----- package.json | 3 + 3 files changed, 142 insertions(+), 24 deletions(-) create mode 100644 app/static/app/js/classes/TemplateLayer.js diff --git a/app/static/app/js/classes/TemplateLayer.js b/app/static/app/js/classes/TemplateLayer.js new file mode 100644 index 00000000..fec85518 --- /dev/null +++ b/app/static/app/js/classes/TemplateLayer.js @@ -0,0 +1,103 @@ +import shp from 'shpjs'; +import Spinner from 'spin'; + +export function addTempLayer(file, rejected, _this) { + //random color for each feature + let getColor = (_geojson) => { + return 'rgb(' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ')'; + } + + //notifications on top + let writeMessage = (_err) => { + _this.setState({ error: _err.message || JSON.stringify(_err) }); + spinner.stop(); + } + + //show wait spinner + var spinner = new Spinner({ color: '#fff', lines: 12 }).spin(_this.map._container); + + if (typeof rejected !== 'undefined' && rejected.length > 0) { + let err = {}; + if (rejected[0].size > _this.maxTempLayerSize) { + err.message = "File is bigger than " + _this.maxTempLayerSize + " bytes"; + } else { + err.message = "Data error"; + } + writeMessage(err); + } else { + //get just the first file + file = file[0]; + let reader = new FileReader(); + let isZipFile = file.name.slice(-3) === 'zip'; + if (isZipFile) { + //zipped shapefile + reader.onload = function () { + if (reader.readyState != 2 || reader.error) { + return; + } else { + if (isZipFile) { + shp(reader.result).then(function (geojson) { + addLayer(geojson); + }).catch(function (err) { + err.message = "Not a proper zipped shapefile!"; + writeMessage(err); + }) + } + } + } + reader.readAsArrayBuffer(file); + } else { + //geojson file + reader.onload = function () { + try { + let geojson = JSON.parse(reader.result); + addLayer(geojson); + } catch (err) { + err.message = "Not a proper json file!"; + writeMessage(err); + } + } + reader.readAsText(file); + } + } + + let addLayer = (_geojson) => { + let tempLayer = + L.geoJson(_geojson, { + style: function (feature) { + return { + opacity: 1, + fillOpacity: 0.7, + color: getColor() + } + }, + //for point layers + pointToLayer: function (feature, latlng) { + return L.circleMarker(latlng, { + radius: 6, + color: getColor(), + opacity: 1, + fillOpacity: 0.7 + }); + }, + // + onEachFeature: function (feature, layer) { + if (feature.properties) { + if (feature.properties) { + layer.bindPopup(Object.keys(feature.properties).map(function (k) { + return k + ": " + feature.properties[k]; + }).join("
"), { + maxHeight: 200 + }); + } + } + } + }); + tempLayer.addTo(_this.map); + //add layer to layer switcher with file name + _this.autolayers.addOverlay(tempLayer, file.name); + //zoom to all features + _this.map.fitBounds(tempLayer.getBounds()); + spinner.stop(); + } +} \ No newline at end of file diff --git a/app/static/app/js/components/Map.jsx b/app/static/app/js/components/Map.jsx index 923cb2a8..e3ed7c9d 100644 --- a/app/static/app/js/components/Map.jsx +++ b/app/static/app/js/components/Map.jsx @@ -12,10 +12,12 @@ import ErrorMessage from './ErrorMessage'; import SwitchModeButton from './SwitchModeButton'; import ShareButton from './ShareButton'; import AssetDownloads from '../classes/AssetDownloads'; +import {addTempLayer} from '../classes/TemplateLayer'; import PropTypes from 'prop-types'; import PluginsAPI from '../classes/plugins/API'; import Basemaps from '../classes/Basemaps'; import update from 'immutability-helper'; +import Dropzone from 'react-dropzone'; class Map extends React.Component { static defaultProps = { @@ -273,34 +275,44 @@ class Map extends React.Component { if (this.shareButton) this.shareButton.hidePopup(); } + onDrop(file, reject, _this) { + addTempLayer(file, reject, _this); + } + render() { return ( -
- + { this.onDrop(accepted, rejected, this) }} disableClick={true} + maxSize={this.maxTempLayerSize} multiple={false} + > + {({ getRootProps, getInputProps }) => ( +
+ -
(this.container = domNode)} - onMouseDown={this.handleMapMouseDown} - > -
- +
(this.container = domNode)} + onMouseDown={this.handleMapMouseDown} + > +
-
- {this.state.pluginActionButtons.map((button, i) =>
{button}
)} - {(!this.props.public && this.state.singleTask !== null) ? - { this.shareButton = ref; }} - task={this.state.singleTask} - linksTarget="map" - /> - : ""} - -
-
+
+ {this.state.pluginActionButtons.map((button, i) =>
{button}
)} + {(!this.props.public && this.state.singleTask !== null) ? + { this.shareButton = ref; }} + task={this.state.singleTask} + linksTarget="map" + /> + : ""} + +
+
+ )} + ); } } diff --git a/package.json b/package.json index 39e85e8b..8d021275 100644 --- a/package.json +++ b/package.json @@ -51,12 +51,15 @@ "raw-loader": "^0.5.1", "react": "^16.2.0", "react-dom": "^16.2.0", + "react-dropzone": "^8.0.3", "react-router": "^4.1.1", "react-router-dom": "^4.1.1", "react-test-renderer": "^15.6.1", "regenerator-runtime": "^0.11.0", "sass-loader": "^7.0.3", + "shpjs": "^3.4.2", "sinon": "^4.0.0", + "spin": "0.0.1", "statuses": "^1.3.1", "style-loader": "^0.13.1", "tween.js": "^16.6.0", From 3668b552863c4f7c503cd2730c551ddc9971f70f Mon Sep 17 00:00:00 2001 From: saricicekibrahim Date: Fri, 28 Dec 2018 16:00:40 +0300 Subject: [PATCH 2/3] used Dropzone instead of react-dropzone --- .../{TemplateLayer.js => TempLayer.js} | 32 ++++----- app/static/app/js/components/Map.jsx | 71 +++++++++---------- package.json | 1 - 3 files changed, 49 insertions(+), 55 deletions(-) rename app/static/app/js/classes/{TemplateLayer.js => TempLayer.js} (77%) diff --git a/app/static/app/js/classes/TemplateLayer.js b/app/static/app/js/classes/TempLayer.js similarity index 77% rename from app/static/app/js/classes/TemplateLayer.js rename to app/static/app/js/classes/TempLayer.js index fec85518..dd5c9f1d 100644 --- a/app/static/app/js/classes/TemplateLayer.js +++ b/app/static/app/js/classes/TempLayer.js @@ -1,9 +1,11 @@ import shp from 'shpjs'; import Spinner from 'spin'; -export function addTempLayer(file, rejected, _this) { +export function addTempLayer(file, _this) { + let maxSize = 10485760; + //random color for each feature - let getColor = (_geojson) => { + let getColor = () => { return 'rgb(' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ')'; } @@ -16,17 +18,13 @@ export function addTempLayer(file, rejected, _this) { //show wait spinner var spinner = new Spinner({ color: '#fff', lines: 12 }).spin(_this.map._container); - if (typeof rejected !== 'undefined' && rejected.length > 0) { + if (file && file.size > maxSize) { let err = {}; - if (rejected[0].size > _this.maxTempLayerSize) { - err.message = "File is bigger than " + _this.maxTempLayerSize + " bytes"; - } else { - err.message = "Data error"; - } + err.message = "File is bigger than 10 MB."; writeMessage(err); } else { //get just the first file - file = file[0]; + //file = file[0]; let reader = new FileReader(); let isZipFile = file.name.slice(-3) === 'zip'; if (isZipFile) { @@ -35,14 +33,12 @@ export function addTempLayer(file, rejected, _this) { if (reader.readyState != 2 || reader.error) { return; } else { - if (isZipFile) { - shp(reader.result).then(function (geojson) { - addLayer(geojson); - }).catch(function (err) { - err.message = "Not a proper zipped shapefile!"; - writeMessage(err); - }) - } + shp(reader.result).then(function (geojson) { + addLayer(geojson); + }).catch(function (err) { + err.message = "Not a proper zipped shapefile " + file.name; + writeMessage(err); + }) } } reader.readAsArrayBuffer(file); @@ -53,7 +49,7 @@ export function addTempLayer(file, rejected, _this) { let geojson = JSON.parse(reader.result); addLayer(geojson); } catch (err) { - err.message = "Not a proper json file!"; + err.message = "Not a proper json file " + file.name; writeMessage(err); } } diff --git a/app/static/app/js/components/Map.jsx b/app/static/app/js/components/Map.jsx index e3ed7c9d..2f3989b7 100644 --- a/app/static/app/js/components/Map.jsx +++ b/app/static/app/js/components/Map.jsx @@ -7,17 +7,17 @@ import '../vendor/leaflet/L.Control.MousePosition.css'; import '../vendor/leaflet/L.Control.MousePosition'; import '../vendor/leaflet/Leaflet.Autolayers/css/leaflet.auto-layers.css'; import '../vendor/leaflet/Leaflet.Autolayers/leaflet-autolayers'; +import Dropzone from '../vendor/dropzone'; import $ from 'jquery'; import ErrorMessage from './ErrorMessage'; import SwitchModeButton from './SwitchModeButton'; import ShareButton from './ShareButton'; import AssetDownloads from '../classes/AssetDownloads'; -import {addTempLayer} from '../classes/TemplateLayer'; +import {addTempLayer} from '../classes/TempLayer'; import PropTypes from 'prop-types'; import PluginsAPI from '../classes/plugins/API'; import Basemaps from '../classes/Basemaps'; import update from 'immutability-helper'; -import Dropzone from 'react-dropzone'; class Map extends React.Component { static defaultProps = { @@ -174,6 +174,15 @@ class Map extends React.Component { } componentDidMount() { + var thisComponent = this; + var mapTempLayerDrop = new Dropzone(this.container, {url : "/", clickable : false}); + mapTempLayerDrop.on("addedfile", function(file) { + addTempLayer(file, thisComponent); + }); + mapTempLayerDrop.on("error", function(file) { + mapTempLayerDrop.removeFile(file); + }); + const { showBackground, tiles } = this.props; this.map = Leaflet.map(this.container, { @@ -275,44 +284,34 @@ class Map extends React.Component { if (this.shareButton) this.shareButton.hidePopup(); } - onDrop(file, reject, _this) { - addTempLayer(file, reject, _this); - } - render() { return ( - { this.onDrop(accepted, rejected, this) }} disableClick={true} - maxSize={this.maxTempLayerSize} multiple={false} - > - {({ getRootProps, getInputProps }) => ( -
- +
+ -
(this.container = domNode)} - onMouseDown={this.handleMapMouseDown} - > -
+
(this.container = domNode)} + onMouseDown={this.handleMapMouseDown} + > +
+ -
- {this.state.pluginActionButtons.map((button, i) =>
{button}
)} - {(!this.props.public && this.state.singleTask !== null) ? - { this.shareButton = ref; }} - task={this.state.singleTask} - linksTarget="map" - /> - : ""} - -
-
- )} - +
+ {this.state.pluginActionButtons.map((button, i) =>
{button}
)} + {(!this.props.public && this.state.singleTask !== null) ? + { this.shareButton = ref; }} + task={this.state.singleTask} + linksTarget="map" + /> + : ""} + +
+
); } } diff --git a/package.json b/package.json index 8d021275..c5fa2818 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ "raw-loader": "^0.5.1", "react": "^16.2.0", "react-dom": "^16.2.0", - "react-dropzone": "^8.0.3", "react-router": "^4.1.1", "react-router-dom": "^4.1.1", "react-test-renderer": "^15.6.1", From bb20f69df2cce03d54651d516dc546bf9744d6ec Mon Sep 17 00:00:00 2001 From: saricicekibrahim Date: Mon, 31 Dec 2018 09:39:49 +0300 Subject: [PATCH 3/3] limited file size to 5mb --- app/static/app/js/classes/TempLayer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/static/app/js/classes/TempLayer.js b/app/static/app/js/classes/TempLayer.js index dd5c9f1d..1a11827f 100644 --- a/app/static/app/js/classes/TempLayer.js +++ b/app/static/app/js/classes/TempLayer.js @@ -2,7 +2,7 @@ import shp from 'shpjs'; import Spinner from 'spin'; export function addTempLayer(file, _this) { - let maxSize = 10485760; + let maxSize = 5242880; //random color for each feature let getColor = () => { @@ -20,7 +20,7 @@ export function addTempLayer(file, _this) { if (file && file.size > maxSize) { let err = {}; - err.message = "File is bigger than 10 MB."; + err.message = file.name + " is bigger than 5 MB."; writeMessage(err); } else { //get just the first file