Leaflet.draw geojson layer edit - javascript

As you see in this fiddle , I have a polygon like this:
var data = [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[2.504410743713379,44.28253972334941],
[2.504410743713379,44.28929846767132],
[2.5168561935424805,44.28929846767132],
[2.5168561935424805,44.28253972334941],
[2.504410743713379,44.28253972334941]
]
]
}}]
When I want to add it to my featureGroup drawnItems I use:
var geojsonLayer = L.geoJson(data);
geojsonLayer.getLayers()[0].addTo(drawnItems);
Then I decide to edit polygon I can't move it because the central move handler does not appear, But when I draw new polygon using the toolbar I have move handler.
Could you please help me?
how can I add my polygon to have move handler?

Do something like this to add every Geojson layer to drawnItems:
var geeoojson = L.geoJSON(JSON.parse(data), {
onEachFeature: function (feature, layer) {
layer.addTo(drawnItems);
}
}).addTo(map)

Related

How to add new layer to client mapbox map on button click with JS/jQuery?

Problem:
I am working on project where I use node.js server that communicate with my spatial DB in PG and my client uses mapbox to vizualize map on his side. After hitting a button, the request is send to server, server to psql, psql to server as result query and then through socket.io back to client, where I want to put my geoJSON / new geometry as new layer on his map after that client buttonclick occurs. Map on client side in HTML is well working and I can interact with it. I use JS inside of HTML page of my client. From there I need to update mapbox map with new geometry after button click.
Code sample:
But I tried this code, but this do nothing after button click and will show no errors in devTool Chrome console:
<script>
mapboxgl.accessToken = 'secretToken-I-have-just-for-ilustr--this-is-working';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v10',
center: [17.10, 48.14], // starting position on Bratislava
zoom: 11 // starting zoom
});
// Add zoom and rotation controls to the map.
map.addControl(new mapboxgl.NavigationControl());
// later SOCKET PROCESSING
$(document).ready(function(){
$('#buttonRun').click(function(e){
map.on('load', function () {
alert("got HERE") // this is working, alert shows itself
map.addLayer({
"id": "route",
"type": "line",
"source": {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[-122.48369693756104, 37.83381888486939],
[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],
[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971],
[-122.48404026031496, 37.83049717427869],
[-122.48348236083984, 37.829920943955045],
[-122.48356819152832, 37.82954808664175],
[-122.48507022857666, 37.82944639795659],
[-122.48610019683838, 37.82880236636284],
[-122.48695850372314, 37.82931081282506],
[-122.48700141906738, 37.83080223556934],
[-122.48751640319824, 37.83168351665737],
[-122.48803138732912, 37.832158048267786],
[-122.48888969421387, 37.83297152392784],
[-122.48987674713133, 37.83263257682617],
[-122.49043464660643, 37.832937629287755],
[-122.49125003814696, 37.832429207817725],
[-122.49163627624512, 37.832564787218985],
[-122.49223709106445, 37.83337825839438],
[-122.49378204345702, 37.83368330777276]
]
}
}
},
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#888",
"line-width": 8
}
});
});
});
});
</script>
Even this is not working - even if I set data in click function in a static way, but this data will later change dynamically. If I add that layer out of click event function scope, it is working and layer loads on client map.
Settings / versions:
Windows10 Pro - 64-bit
Google Chrome - Version 69.0.3497.100 (Official Build) (64-bit)
Node.js - v10.11.0
mapbox-gl.js v0.49.0
Q:
Is there any way how to add layer to mapbox map dynamically, please? And later to remove without page refresh? (I still not found answer, even here)
Solution
Okay, I found something I before did not see, concretely this.
I better read documentation, and it is impossible to setup new layers dynamically, but now it is working as follows / you need to:
Out of all scopes define your variables, for example geoJson1, and geoJson2 that you can later edit / fill with function
Setup your layer in advance on map with your ID (as in code below) and fill it for example with goeJson1 or with empty []
In your on click listener function call this: map.getSource('data-update').setData(geojson2);
You just can setup as many layers in advance as you need, and later you can update them.
Code result:
<script>
mapboxgl.accessToken = 'token-from-your-registered-account';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v10',
center: [17.10, 48.14], // starting position on Bratislava
zoom: 11 // starting zoom
});
var geojson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-122.48369693756104, 37.83381888486939],
[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],
[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971]
]
}
}]
};
var geojson2 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-122.48369693756104, 37.83381888486939],
[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],
[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971],
[-122.48404026031496, 37.83049717427869],
[-122.48348236083984, 37.829920943955045],
[-122.48356819152832, 37.82954808664175],
[-122.48507022857666, 37.82944639795659],
[-122.48610019683838, 37.82880236636284],
[-122.48695850372314, 37.82931081282506],
[-122.48700141906738, 37.83080223556934],
[-122.48751640319824, 37.83168351665737],
[-122.48803138732912, 37.832158048267786],
[-122.48888969421387, 37.83297152392784],
[-122.48987674713133, 37.83263257682617],
[-122.49043464660643, 37.832937629287755],
[-122.49125003814696, 37.832429207817725],
[-122.49163627624512, 37.832564787218985],
[-122.49223709106445, 37.83337825839438],
[-122.49378204345702, 37.83368330777276]
]
}
}]
};
map.on('load', function () {
map.addLayer({
"id": "data-update",
"type": "line",
"source": {
"type": "geojson",
"data": geojson // your previously defined variable
},
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#888",
"line-width": 8
}
});
});
$(document).ready(function(){
$('#buttonRun').click(function(e){
map.getSource('data-update').setData(geojson2);
});
});
</script>

How to style each Geometry of a GeoJSON GeometryCollection individually using Leaflet

I'm working on an interactive map showing the history of rail transport in a city using Leaflet and some GeoJSON data. My GeoJSON data looks like this:
var lines = [
{
"type": "FeatureCollection",
"name": "stadtmitte_gerresheim",
"startYear": "1902",
"endYear": "2019",
"lineColor": "#DD0000",
"trainID": "001",
"features": [
{
"type": "Feature",
"properties": {
"lineName": "U73",
"station1": "Universität Ost/Botanischer Garten",
"station2": "Gerresheim S",
"startYear": "2016",
"endYear": "2019",
"lineColor": "#DD0000",
},
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "LineString",
"lineID": "001",
"lineDescription": "Schleife am S-Bahnhof Gerresheim",
"coordinates": [...
]
},
{
"type": "LineString",
"lineID": "002",
"lineDescription": "Gerresheim S bis Ecke Schönaustraße/Heyestraße",
"coordinates": [...
]
}
....
I'm working with several FeatureCollections, that consist of some Features. As you can see the geometry of each feature is defined by a GeometryCollection (that mostly comprises LineStrings).
I'd like to use Leaflet to style each single geometry (the LineStrings from the GeometryCollections) according to its members. At the moment I only manage to style the whole GeometryCollection via the Feature:
L.geoJSON(route, {
filter: function(feature) {
if (checkYear(feature)) {
return true;
} else {
return false;
}
},
style: function(feature) {
switch (feature.properties.tunnel) {
case 'yes': return {color: "#ff0000", dashArray: "1,6"};
default: return {color: "#ff0000"}
}
},
pointToLayer: function (feature, latlng) {
getIconSize();
switch (feature.properties.underground) {
case 'yes': return L.marker(latlng, {icon: stadtbahnIcon});
default: return L.marker(latlng, {icon: strassenbahnIcon});
}
}
}).addTo(mymap);
}
My question: Is it possible to hand individual style functions to different Geometries of the same Feature instead of handing the same style function to all Geometries in this Feature? And if so, how? I guess it should be possible, as Leaflet creates a single path for every Geometry.
Cheers
Is it possible to hand individual style functions to different Geometries of the same Feature?
No.
Leaflet creates one instance of L.Layer per Feature in the GeoJSON, right over here; and the application of the style callback function just loops over the L.Layers corresponding to each feature, it doesn't drill down on nested L.LayerGroups (also, the L.Polylines and L.Polygons created as the result of a GeometryCollection don't have a reference to the original GeoJSON feature nor its properties).
I guess you'll want to use TurfJS' geomEach (or something similar) in order to preprocess your features&geometries.

Does anyone know how to remove geoJson polygon from a layer with mapboxgl?

I am running into some difficulties to remove a geojon polygon from a layer with mapboxGL.
Here the following code to add my geoson polygons where
array_geo is a polygon geometry. Adding the polygon works like a charm,
but I still did not find how to delete my polygons. The only trick I found is to use the removeLayer(id) function which delete the entire layer.
var id="mylayer";
itemObj = {
type:"Feature",
properties: {
description: description,
type: 23
},
geometry: {
type: "Polygon",
coordinates: array_geo
},
};
mpolygons.push(itemObj);
map.addSource(id,{
"type":"geojson",
"data":{
"type":"FeatureCollection",
"features":mypolygons
}
self.map.addLayer({
"id": id,
"source":id,
"type":"fill",
"layout": {'visibility':'visible'},
"paint": {
'fill-color': '#088',
//'fill-opacity': 0.8
}
})
Thanks !

Mapbox geoJSON formatting

I am trying to make an interactive map using MapBox.
The basic idea is that people will hover over certain regions and they will light up and an event will trigger showing some content.
I got the map set up using Mapbox and then went ahead and got some data for the points by first
Going here to create a shapefile - http://www.gadm.org/country
And then going here to convert that file into a json file - http://www.mapshaper.org/
I then load the data into the map via mapbox and here is my result! (code below) - http://dev.touch-akl.com/nzmap/
As you can see thanks to the data I have downloaded it is almost a perfect trace of the country the only problem is that all the regions seem to be ONE object when hovering.
$.ajax({
url: '/nzmap/js/nzmap.json',
dataType: 'json',
success: function load(data) {
// set up the regions based on the JSON data and then call the styles and the hovers
var regions = L.geoJson(data, {
style: getStyle,
onEachFeature: onEachFeature
}).addTo(map);
// selects used to style the regionsLayer
function getStyle(feature) {
return {
weight: 2,
opacity: 0.1,
color: 'black',
fillOpacity: 0.7,
fillColor: 'red'
};
}
// combine the mouse in and mouse out?
function onEachFeature(feature, layer) {
layer.on({
mousemove: mousemove,
mouseout: mouseout
});
}
// mouse over change the layer styles
function mousemove(e) {
var layer = e.target;
// highlight feature
layer.setStyle({
weight: 3,
opacity: 0.3,
fillOpacity: 0.9
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
//mouse out reset the style
function mouseout(e) {
regions.resetStyle(e.target);
}
}
});
Here is a link to the json file if that helps understand what is going on - http://dev.touch-akl.com/nzmap//js/nzmap.json
It looks like some of the polygons are 'multipolygons' and some are seperate. I managed to create a new version of the map using just one region and it looks like this - http://dev.touch-akl.com/nzmap2/
My function for doing this is much the same except I have split the region off and use a json file that only has the coordinates for that region.
This is the JSON file for that example - http://dev.touch-akl.com/nzmap2/js/waikato.json
So where I am stuck is... Is there a way to format the original json file in a way that will keep each region as it's own separate object for hovers? And if so how can I go about changing the way I am setting up the map get the desired result?
It looks like I could make a seperate json file for each region like I am doing with the second example but that just does not seem like the right way to do this, been stuck for days so any help would be appreciated!
This is because what you are using isn't proper GeoJSON, at least not the GeoJSON L.GeoJSON expects. What you need is a GeoJSON FeatureCollection. A collection would look something like this:
[{
"type": "Feature",
"properties": {
"foo": "bar"
},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-104.05, 48.99],
[-97.22, 48.98],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]]
}
}, {
"type": "Feature",
"properties": {
"bar": "foo"
},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}]
As you can see, a FeatureCollection contains individual features which can be or type Point, MultiPoint, LineString, MultiLineString, Polygon or MultiPolygon. If you use a FeatureCollection L.GeoJSON will work as you would expect. Take a look at the reference for FeatureCollection and L.GeoJSON. A tutorial/example on using them both can be found here.

leaflet map: make polygon clickable

I managed to create map with leaflet.js & jQuery mobile.
Now I need to get rid of jQuery mobile and just use jQuery instead.
Everything works just fine, but I can't click the polygons which I draw on the map anymore. It worked with jQuery mobile before.
Any hints?
here is my simplified code:
var map = L.map('map', {
zoomControl: false
});
L.tileLayer('http://{s}.tile.cloudmade.com/**apikey***/997/256/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
maxZoom: 18
}).addTo(map);
For the polygons:
var geojsonFeature = { "type": "Polygon","coordinates": value.polygon};
var polycolor = getGebColor(value.geb_nr);
var geojsonStyle = {"color": polycolor};
polygons[i] = L.geoJson(geojsonFeature, {style: geojsonStyle}).addTo(map);
// make clickable
polygons[i].on('click', function(e) {
if (lastMarker) {
map.removeLayer(lastMarker);
}
var url = "http://*****/tugetherMap.php?callback=&id="+value.id+"&type=B";
markers[i] = L.marker([value.point[1], value.point[0]]).addTo(map);
gebName = value.nameLang;
markers[i].bindPopup("<a class='gebOnMap' href='gebaeude.html' >"+gebName+"</a>").openPopup();
lastMarker = markers[i];
});
the polygons[i].on('click',...) is the part which does not work anymore. It works for map.on('click',...)
You need to bind each of your polygons to a click event handler, like so.
L.geoJson(geojsonFeature, {
onEachFeature: function(feature, layer) {
layer.on('click', function(e) {
// Do whatever you want here, when the polygon is clicked.
});
}
}).addTo(map);
Had a issue with this and solved it with the following
function onEachFeature(feature, layer) {
// Do all your popups and other binding in here
// does this feature have a property named popupContent?
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
var geojsonFeature = {
"type": "Feature",
"properties": {
"name": "Coors Field",
"amenity": "Baseball Stadium",
"popupContent": "This is where the Rockies play!"
},
"geometry": {
"type": "Point",
"coordinates": [-104.99404, 39.75621]
}
};
L.geoJson(geojsonFeature, {
onEachFeature: onEachFeature
}).addTo(map);
In your code I guess it would be
polygons[i] = L.geoJson(geojsonFeature, {onEachFeature: onEachFeature,
style: geojsonStyle}).addTo(map);
function onEachFeature(feature, layer) {
// Some jazz and magic you need to do with your layer and feature objects
}
The solution for me was to downgrade Leaflet to 0.7.3 or upgrade to 1.0-beta2 (latest version at the time of writing).

Categories