I have made offline map using leaflet and tiles. These tiles does not contain countries border or state border. I want to add all countries border as well as state border into these tiles. Here is the code for building map.
var map = L.map('map').setView([33.705, -84.3900], 4);
L.tileLayer('tiles/{z}/{x}/{y}.png', {
attribution: '© <a>ABC</a>',
maxZoom: 11,
minZoom: 4
}).addTo(map);
map.attributionControl.setPrefix('');
var london = new L.LatLng(51.505, -0.09);
map.addLayer(london);
Here is the map tiles without any border lines. How to add border layer using leaflet.
I am expecting output should look like
Well first you will need the latitude/longitude pairs of the points that define that "borders layer". It would be best if you have that points in a geoJSON format. Once you have that data you can iterate through those points and connect them and create a layer.
var states = [{
"type": "Feature",
"properties": {"party": "Republican"},
"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": {"party": "Democrat"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}];
L.geoJson(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Republican': return {color: "#ff0000"};
case 'Democrat': return {color: "#0000ff"};
}
}
}).addTo(map);
Of course, those points need to be logically grouped, so you can connect the right points. Be sure to check out this link http://leafletjs.com/examples/choropleth.html
Related
I am totally stuck with my WGS 84 / EPSG:3857 coordinates and display them on Leaflet.
I have Geojson with coordinates.
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
"6690861",
"682187"
]
},
"properties": {
"id": "908",
"message": "105",
"date": "",
"place": "",
"shape": ""
}
}
Now i want it display on Leaflet. But nothing show up. I search already 5 hours and find something about Proj4. Also no errors showing up.
My script code:
var map = L.map('map').setView([52.2129919, 5.2793703], 8);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: 'Map data © OpenStreetMap'}).addTo(map);
// GeoJSON layer (UTM15)
proj4.defs('EPSG:3857');
async function addGeoJson() {
const response = await fetch("geojs.php");
const data = await response.json();
L.geoJson(data).addTo(map);
var layerGroup = L.geoJSON(data, {
onEachFeature: function (feature, layer) {
layer.bindPopup('<h1>'+feature.properties.message+'</h1><p>Datum: '+feature.properties.date+'</p>');
}
}).addTo(map);
}
addGeoJson();
It's for my the first time i work with this coordinates. With lat/long coordinates was don't have problems. And just started with javascript.
Kind regards,
I might be a bit late, but following the documentation of Proj4, I would say that you need to add the crs to your geojson, like so :
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
"6690861",
"682187"
]
},
"properties": {
"id": "908",
"message": "105",
"date": "",
"place": "",
"shape": ""
},
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:EPSG::3857"
}
}
}
Also, I think it's
L.Proj.geoJson(data).addTo(map);
instead of
L.geoJson(data).addTo(map);
I tried L.geoJson on my code and it didn't show anything contrary to L.Proj.geoJson so it might be your problem here.
I am trying to show clusters using markerclustergroups with Polygons. Right now the polygons are shown but the clusters aren't. I have been trying to use center of mass for the polygons because it seems like markerclustergroup doesn't like polygons but that doesn't really work since the animation of markerclustergroup will be set on the centroids and not the actual polygon.
My polygons all vary in amount of coordinates. Some have +10 sets others have 3.
How would I use markerclustergroup for polygons?
Below my code can be seen:
// Create variable to hold map element, give initial settings to map
var map = L.map('map', {
center: [23.70489, 43.90137],
zoom: 5
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
}).addTo(map);
var ojStyle = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
// Hardcoded polygons as GeoJSON
var polygons = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[37.99896240234376, 21.55017532555692],
[39.39422607421876, 21.476073444092435],
[38.88336181640626, 22.56582956966297],
[38.023681640625, 22.611475436593366],
[37.43591308593751, 21.99908185836153],
[37.28485107421876, 21.624239377938288],
[37.28485107421876, 21.624239377938288],
[37.99896240234376, 21.55017532555692]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[38.50708007812501, 21.453068633086783],
[39.20745849609376, 21.37124437061832],
[39.10858154296876, 20.876776727727016],
[38.80920410156251, 20.912700155617568],
[38.49884033203126, 20.94604992010052],
[38.50708007812501, 21.453068633086783]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[50.57830810546875, 25.980268007469803],
[50.77606201171876, 25.956809920555312],
[50.780181884765625, 25.69970044378398],
[50.56457519531251, 25.822144306879686],
[50.56182861328126, 25.945696562830516],
[50.57830810546875, 25.980268007469803]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[54.37408447265626, 24.51963836811676],
[54.29443359375001, 24.40963901896311],
[54.25872802734375, 24.449649897759667],
[54.32739257812501, 24.539627918861232],
[54.37133789062501, 24.559614286039903],
[54.37408447265626, 24.51963836811676]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[54.40155029296876, 24.463400705082282],
[54.41940307617188, 24.489648077028683],
[54.45785522460938, 24.462150693715266],
[54.43450927734376, 24.43839812102505],
[54.40155029296876, 24.463400705082282]
]
]
}
}]
}
var polygonArray = []
for (i = 0; i < polygons.features.length; i++) {
polygonArray.push(polygons.features[i]);
}
var markers = L.markerClusterGroup().addTo(map);
var geoJsonLayer = L.geoJson(polygonArray);
markers.addLayer(geoJsonLayer);
map.fitBounds(markers.getBounds());
http://js.do/code/165930 - Shows how clustering doesn't work for the polygons
I am looking for a solution like this: http://jsfiddle.net/ve2huzxw/237/
You can do it very much like in this GIS post: Is it possible to cluster polygons in Leaflet?
// Compute a polygon "center", use your favourite algorithm (centroid, etc.)
L.Polygon.addInitHook(function() {
this._latlng = this._bounds.getCenter();
});
// Provide getLatLng and setLatLng methods for
// Leaflet.markercluster to be able to cluster polygons.
L.Polygon.include({
getLatLng: function() {
return this._latlng;
},
setLatLng: function() {} // Dummy method.
});
Updated live example: http://js.do/code/166021
I have data of, say, density over 30 districts from 2000 to 2010.
I'd like to make an interactive choropleth map for each year and then either use a slider (ideally) or a radio button to select between years.
I can get interactivity on the first year, but NOT on the layers for other years.
You can see a working example here, but let me put some details below:
For simplicity, consider just two years. blocks1995 has the non-overlapping polygons BlockA and BlockB (the two districts) and blocks1996 has the same blocks. They have a property called density that produces the choropleth:
var blocks1995 = {
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" }
},
"features": [{
"type": "Feature",
"properties": { "time": 1995, "density": 3.1, "nameB": "BlockA" },
"geometry": {
"type": "Polygon",
"coordinates": [[[50.0, 29.0],[50.0, 29.99],[50.51, 29.99],[50.0, 29.0]]]
}
}, {
"type": "Feature",
"properties": { "time": 1995, "density": 1.1, "nameB": "BlockB" },
"geometry": {
"type": "Polygon",
"coordinates": [[[50.01, 30.0],[50.52, 30.0],[50.52, 30.5]]]
}
}]
};
var blocks1996 = {
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" }
},
"features": [{
"type": "Feature",
"properties": {"year": 1996, "density": 2.2, "name": "BlockA" },
"geometry": {
"type": "Polygon",
"coordinates": [[[50.0, 29.0],[50.0, 29.99],[50.51, 29.99]]]
}
}, {
"type": "Feature",
"properties": {"year": 1996,"density": 1.2,"name": "BlockB"},
"geometry": {
"type": "Polygon",
"coordinates": [[[50.01, 30.0],[50.52, 30.0],[50.52, 30.5]]]
}
}]
};
I've tried adding them to an OverlayLayer
var blocks1995Layer = L.layerGroup([ L.geoJson(blocks1995)]),
blocks1996Layer = L.layerGroup([ L.geoJson(blocks1996)]);
var overlayMaps = {
"Blocks 1995": blocks1995Layer,
"Blocks 1996": blocks1996Layer
};
var map = new L.map('map', {layers:[blocks1995Layer]})
.setView([29, 50], 7);
I put the boilerplate interactivity code found in this Leaflet interactive choropleth tutorial and then I add back to the map:
geojson = L.geoJson(blocks1995, {
style: density_style,
onEachFeature: addToFeature
}).addTo(map);
L.control.layers(null, overlayMaps).addTo(map);
The problem is I'm adding interactivity to blocks1995 only, but I haven't been able to add it to overlayMaps.
I'm OK using a Leaflet plug-in (I tried TimeSlider but also couldn't figure it out).
Another possibility is to combine the two block1995and block1996 variables into one with an extra feature year or time is that makes things easier. The idea would be for Leaflet to query by time (say, when a slider moves) and produce the interactive choropleth per year.
Thanks!
Basically, you're not adding layers to control properly. Currently, you're doing this
var blocks1995Layer = L.layerGroup([ L.geoJson(blocks1995)]),
blocks1996Layer = L.layerGroup([ L.geoJson(blocks1996)]);
var overlayMaps = {
"Blocks 1995": blocks1995Layer,
"Blocks 1996": blocks1996Layer
};
geojson = L.geoJson(blocks1995, {
style: density_style,
onEachFeature: addToFeature
}).addTo(map);
Instead, try this
geojson = L.geoJson(blocks1995, {
style: density_style,
onEachFeature: addToFeature
}).addTo(map);
geojson1 = L.geoJson(blocks1996, {
style: density_style,
onEachFeature: addToFeature
}).addTo(map);
var overlayMaps = {
"Blocks 1995": geojson,
"Blocks 1996": geojson1
};
Here is a working example
Here is another example where I've implemented radio buttons instead of checkboxes using this plugin
Edited
As per your comment, I've created a example using this leaflet time slider plugin. Here is the part of the code.
//I've created 5 geojson layers, in order the slider to look appropriate.
geojson = L.geoJson(blocks1995, {
style: density_style,
onEachFeature: addToFeature,
time: "1995" //this is for labeling, you may alter this value if required
});
geojson1 = L.geoJson(blocks1996, {
style: density_style,
onEachFeature: addToFeature,
time: "1996"
});
geojson2 = L.geoJson(blocks1997, {
style: density_style,
onEachFeature: addToFeature,
time: "1997"
});
geojson3 = L.geoJson(blocks1998, {
style: density_style,
onEachFeature: addToFeature,
time: "1998"
});
geojson4 = L.geoJson(blocks1999, {
style: density_style,
onEachFeature: addToFeature,
time: "1999"
});
//now add each geojson layer to a single layer group, as the slider take only one layer
var layerGroup = L.layerGroup([geojson, geojson1, geojson2, geojson3, geojson4 ]);
//initiate slider, follow = 1 means, show one feature at a time
var sliderControl = L.control.sliderControl({layer:layerGroup, follow: 1});
map.addControl(sliderControl);//add slider to map
sliderControl.startSlider();//starting slider
Here is the working example
I would like to wrap multiple polygons in a parent polygon. Example below:
Is this possible in Leaflet js? Assume I have an array of L.polygon objects.
Thank you
Short answer: no.
If you want to create an envelope for your polygones, then it is an algorithm problem that goes beyond the scope of leafletjs.
You can look at the answers of this question to start solving your problem.
EDIT: here is an example using Turfjs library (thanks to #IvanSanchez for the heads up and to #HudsonPH for the polygons).
// draw envelope
var points = {
"type": "FeatureCollection",
"features":
[
// collect the points of your polygons
turf.point([-104.05, 48.99]),
// ...
]
};
var hull = turf.convex(points);
L.geoJson(hull).addTo(map);
You can have a group, but you need define all the coordinates
more info: http://leafletjs.com/examples/geojson.html
var states = [{
"type": "Feature",
"properties": {"party": "Republican"},
"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": {"party": "Democrat"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}];
L.geoJson(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Republican': return {color: "#ff0000"};
case 'Democrat': return {color: "#0000ff"};
}
}
}).addTo(map);
Updated with a JSFIDDLE link
I am using LeafletJS to build a web map with a timeline slider. I am using the LeafletSlider plugin to show a group of markers based on a GEOJSON property named DATE_START. Here's an example of what my data object looks like:
var camps = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"STATUS": "UNOCCUPIED",
"DATE_START": "2015-06-23",
"DATE_CLOSED": "2016-01-23"
},
"geometry": {
"type": "Point",
"coordinates": [64.6875, 34.97600151317591]
}
}, {
"type": "Feature",
"properties": {
"STATUS": "OCCUPIED",
"DATE_START": "2014-01-21",
"DATE_CLOSED": "2015-05-25"
},
"geometry": {
"type": "Point",
"coordinates": [65.335693359375, 36.26199220445664]
}
}, {
"type": "Feature",
"properties": {
"STATUS": "UNOCCUPIED",
"DATE_START": "2015-09-13",
"DATE_CLOSED": ""
},
"geometry": {
"type": "Point",
"coordinates": [67.587890625, 35.969115075774845]
}
}]
};
An example of my code:
//Create a marker layer (in the example done via a GeoJSON FeatureCollection)
var testlayer = L.geoJson(camps, {
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.DATE_START);
}
});
var sliderControl = L.control.sliderControl({
position: "topright",
layer: testlayer,
timeAttribute: 'DATE_START'
});
//Make sure to add the slider to the map ;-)
map.addControl(sliderControl);
//And initialize the slider
sliderControl.startSlider();
I've added the timeslider plugin to my map, and although it's functioning, I can't seem to get the slider to show the markers in a temporal order. For example, the marker with the DATE_START value of 2014-01-21 is shown second when in fact it should be shown first because it's the marker with the earliest date.
How can I get my timeslider/markers to appear in the correct order from earliest to latest? Thanks.
EDIT:
As ghybs mentions below (and shows in an example), the proper way to ensure that the slider returns data in the correct order is to sort the options.markers array of the sliderControl:
sliderControl.options.markers.sort(function(a, b) {
return (a.feature.properties.DATE_START > b.feature.properties.DATE_START);
});
My original answer (below) sorts the features of the GeoJSON, but this does not guarantee that Leaflet will return them in the correct order.
Original answer:
You can use the array.sort method to sort the features array in place:
camps.features.sort(function(a, b) {
return (a.properties.DATE_START > b.properties.DATE_START);
});
http://jsfiddle.net/nathansnider/ngeLm8c0/4/