Openlayers 3 z-ordering of features - javascript

I have a vector layer, which contains polygons and points loaded from GEOJSON source. It looks to me, points are always positioned above polygons regardless of their order in source GEOJSON file. See an example definition below. Is there a way, how to position points below polygons on the same layer?
The example:
Points are styled as white and red circle. Polygon is gray.
My GEOJSON looks like this (I even tried to reverse features order in the file):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"radius": "1000"
},
"geometry": {
"type": "Point",
"coordinates": [
12.4,
50.08333
]
}
},
{
"type": "Feature",
"properties": {
"radius": "800"
},
"geometry": {
"type": "Point",
"coordinates": [
12.4,
50.08333
]
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[
12.4,
50.08333
],
...........

Use zIndex in the style objects.

Related

Leaflet not show EPSG:3857 coordinates

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.

How to make MarkerClusterGroup cluster polygons

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

Adding new paths to D3 Globe

I am working on an implementation of a D3 Globe. I am trying to add paths to the globe when the user clicks a button, but this is not proving successful. If I add all paths at once there is no issue, but if I try to add them after a trigger event then it fails. My jsfiddle: http://jsfiddle.net/Guill84/b6xvj76e/1/. I don't think there is an issue with the JSON, as it pops up in the console as expected.
The bit of the script that fails can be found right at the bottom of the fiddle. I paste it below for ease of reference:
$("#clickMe").click(function() {
data = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"name": "path1"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": "[[[116.4551,40.2539],[117.5977,44.3408],[116.4551,40.2539]]]"
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path2"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": "[[[116.4551,40.2539],[122.3438,41.0889],[116.4551,40.2539]]]"
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path3"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": "[[[116.4551,40.2539],[105.9961,37.3096],[116.4551,40.2539]]]"
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path4"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": "[[[116.4551,40.2539],[109.5996,35.6396],[116.4551,40.2539]]]"
},
"id": "RML"
}]}
console.log(data);
var svg = d3.select("#body");
flows = svg.selectAll("path")
.data(data)
.enter().append("svg:path")
.attr("d", clip)
.style("stroke", "black")
.attr("id", function(d) {
return d.properties.name.split(' ').join('_')
});
});
The problems are three:
1) Your JSON structure has a problem: the arrays are specified in string format, thus causing an error when used by the clip function.
2) You are binding the data object directly, when you should instead binding data.features which is the array which contains the four paths you need to create.
3) The selection will select the already existing paths for countries. You can avoid this by adding a class to the new paths. For example, classing them as flow.
4) The flows paths are declared inside the scope of their rendering function, therefore they cannot be updated on the refresh function.
Here's your code with the three fixes:
$("#clickMe").click(function () {
// 1) Arrays: Fixed arrays for coordinates so they are not serialized in a string
var data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "path1"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": [[[116.4551, 40.2539], [117.5977, 44.3408], [116.4551, 40.2539]]]
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path2"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": [[[116.4551, 40.2539], [122.3438, 41.0889], [116.4551, 40.2539]]]
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path3"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": [[[116.4551, 40.2539], [105.9961, 37.3096], [116.4551, 40.2539]]]
},
"id": "RML"
},
{
"type": "Feature",
"properties": {
"name": "path4"
},
"year": "2010",
"geometry": {
"type": "Polygon",
"coordinates": [[[116.4551, 40.2539], [109.5996, 35.6396], [116.4551, 40.2539]]]
},
"id": "RML"
}
]
};
console.log(data);
var svg = d3.select("#body");
// 3) Selection: Add a class to avoid collision with existing paths
// 4) Using var declared outside so it can be used on the update function
flows = svg.selectAll("path.flow")
// 2) Data binding: Bind the features property instead, which is an array
.data(data.features);
// 3) Enter nodes: When appending them, class them as flow so they keep separated
flows.enter().append("svg:path")
.classed("flow", true)
.attr("d", clip)
.style("stroke", "black")
.style("stroke-width", "1px")
.attr("id", function (d) {
return d.properties.name.split(' ').join('_')
});
});
Now it works, but I still cannot see the added paths on the globe. The path elements are for sure appended to the DOM of the svg element, though, which solves your initial problem ;)
- UPDATE -
As indicated on the comments, the added paths didn't follow the movement of the globe. That was due to the paths being added to the svg but not updated along the country shapes on the refresh() function (added point 4).
To do so, the selection for these paths should be made available inside the refresh() function (it suffices declaring the var flows at the top of the script), and then adding an update for this selection inside that function. Like this:
function refresh(duration) {
(duration ? feature.transition().duration(duration) : feature).attr("d", clip);
// 4) Added the flows to the paths selection whose d attribute will be updated (only when present)
flows && (duration ? flows.transition().duration(duration) : flows).attr("d", clip);
}
A complete version can be seen on this fiddle: http://jsfiddle.net/oscar_dr/0psy5udk/2/

How to save a GeoJSON into file using javascript

I am wondering if I have a GeoJSON object such as
var geoJSONLoc= {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"timeReported": "2013-01-22 08:42:26+01"
},
"geometry": {
"type": "Point",
"coordinates": [
7.582512743,
51.933292258,
1
]
}
},
{
"type": "Feature",
"properties": {
"timeReported": "2013-01-22 10:00:26+01"
},
"geometry": {
"type": "Point",
"coordinates": [
7.602516645,
51.94962073,
1
]
}
}]}
How can I save this into a .json file for future use?
I am trying to use
localStorage.setItem('geoJSONLoc.json', geoJSONLoc);
but it doesnt seem to be the right answer.
I've done a little work in NodeJS, so this maybe way off base.
But couldn't you use the fs module for this?
something like
var fs = require('fs')
fs.writeFile('geoJSONLoc.json', geoJSONLoc, function(err){
if(err){
console.log(err);
}
});

Parent polygon in Leaflet js

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);

Categories