I have created a web mapping application using OpenLayers 3 which is displaying the data that is stored in a database. Now I want to display additional data that is going to be provided by the users in the form of shapefiles. The data should only be displayed on the main application and not stored in the database as I do not want to make any changes in the database. I know it can be done through WMS but how it can be done without altering the database?
4 Answers
shp2geojson.js
can take a File object as url, so you could simply drag and drop zipped shapefiles onto the map from a network drive http://mikenunn.16mb.com/demo/shp.html
<!DOCTYPE html>
<html>
<head>
<title>Load SHP overlay</title>
<link rel="stylesheet" href="https://openlayers.org/en/v6.3.1/css/ol.css" type="text/css">
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v6.3.1/build/ol.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip-utils.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.6.1/proj4.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preprocess.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preview.js"></script>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script>
const featureStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 1
})
});
const map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
map.getViewport().addEventListener('dragover', function(event) {
event.preventDefault();
});
map.getViewport().addEventListener('drop', function(event) {
event.preventDefault();
const files = event.dataTransfer.files;
for (let i = 0, ii = files.length; i < ii; ++i) {
const file = files.item(i);
loadshp({url: file, encoding: 'utf-8'}, function(geojson) {
const features = new ol.format.GeoJSON().readFeatures(
geojson,
{ featureProjection: map.getView().getProjection() }
);
const vectorSource = new ol.source.Vector({
features: features
});
map.addLayer(
new ol.layer.Vector({
source: vectorSource,
style: featureStyle
})
);
map.getView().fit(vectorSource.getExtent());
});
}
});
</script>
</body>
</html>
From a (very) high level, for users to upload their own shapefiles and have your server manage the display/tiling/interactivity, as if it's any other layer, you will need to..
Create a dialog in your UI where they can select a file from their system to upload to your server.
Write a web service of some sort that.. a) receives the uploaded file b) stores it somewhere appropriate on your server with proper permissions, and.. c) adds any configurations to your server implementation that are necessary to green-light a new layer from a shapefile source
- In some cases, you might need to trigger a "reload" of the server's configuration at some level. You may also need to force a refresh of your client's browser or programmatically push the resulting new layer details into their UI, like into the legend, into the OpenLayers map itself, etc.
Step 2c) could include adding supplemental style configurations, or SLD's, as well as any other setting you would add do to create a new layer as the server admin.
Will your users also be uploading their own styling configurations?? If so, that adds some UI complexities. My expectation is that step 2c) will be the hard part.
Optionally.. it might be possible to have your users add shapefiles to their OpenLayers client directly, without funneling anything through the server. Here's a discussion with some implementation details you might want to review. Or some of these. This approach would require much less work, but big shapefiles might create a slow or "clunky" user experience; these solutions also don't tend to look very pretty, at least not right out of the box when the shapefiles take whatever default styles the map client imposes. You could try to develop around that, of course.
You can use gipong/shp2geojson : first, you convert the shp file into geojson data Then you add your data to your map
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 5
})
});
loadshp({
url: 'demo/10tnvillage.zip',
encoding: 'big5',
EPSG: 3826
}, function(data) {
var feature = new ol.format.GeoJSON().readFeatures(data, {
featureProjection: 'EPSG:3857'
});
var layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: feature
})
});
map.addLayer(layer);
var extent = layer.getSource().getExtent();
map.getView().fit(extent, map.getSize());
});
I know what you mean. My first recommendation is applying an appropriate client-server architecture that follows OGC standards. Among OGC standards, WMS
and WFS
are very popular to retrieve spatial data stored in database in order to display as a map layer.
If you don't want to store shape file
into database, you may have two alternatives: Using Geoserver
software or applying JSON
file format.
Geoserver
provides you with a type of store
that can use shape files directly without any database. What you need to do is only create a workspace > create a directory of spatial files > set directory of files
. The benefits of this choice is following standard services like WMS
and WFS
as OGC suggests.
If you don't want to use Geoserver
for any reason, you can opt for Geojson
files. This method is a file-based system. To achieve this you can use QGIS APIs
in server-side to convert uploaded .shp
to .json
. I break such a system into 4 components:
1. A component for uploading .shp
file (client-side).
2. A component which stores .shp
file in a directory at back-end (server-side).
3. A component that converts .shp
file to .json
file (server-side).
4. A component for retrieving .json
file and create a map layer (client-side).
The Geojson
file enables us to store spatial data (containing lat/long or easting/northing) and attributes at the same time in a javascript object structure. This
format has at least two benefits:
- It does support different types of
geometry
(point, line, polygon) and complex forms of them (multipoint, multiline, and multipolygon). - It is fully supported by any browsers and also handled by mapping libraries such as
openlayer
andleaflet
.
Attention: Please note that a large shape files with multiple attribute columns leads to a large Geojson
file and it will probably have negative effects on your application performance and may cause annoying lags when users want to do zooming or panning on map.