Deduplicate polygon state/country shared boundaries - leaflet

I am using GEOJSON to draw a world map with leaflet and having dashed line to draw boundaries, like in below image.
The problem I am having is that the line is not shared by two states if two states share boundaries, rather two lines are drawn each for different state. Due to this when zoomed enough lines looks weird as they get overlapped on each other. As show below.
var GeoJsonLayer = L.geoJson();
var myStyle = {
"color": "#fff",
"weight": 0.8,
"opacity": 1,
"fillOpacity": "1",
"fillColor": "#243E54"
};
// here data.world contains GEOJson to draw whole map
if (data.world) {
GeoJsonLayer.options.className = "geojsonlayerpolygon";
GeoJsonLayer.on("dblclick", function (ev) {
map.fireEvent("dblclick", ev);
});
GeoJsonLayer.addData(data.world);
GeoJsonLayer.setStyle(myStyle);
}
For making it dashed line i am using below CSS
.geojsonlayerpolygon{
stroke-dasharray: 6 4;
}
GEOJson I am using is
https://jsonblob.com/826f1a94-c1a3-11e9-a004-354d7c27cab2
How can i make sure that boundaries, when shared, have only one line?

Sounds like a job for TopoJSON. From its readme file:
TopoJSON is an extension of GeoJSON that encodes topology. Rather than representing geometries discretely, geometries in TopoJSON files are stitched together from shared line segments called arcs. This technique is similar to Matt Bloch’s MapShaper and the Arc/Info Export format, .e00.
TopoJSON eliminates redundancy, allowing related geometries to be stored efficiently in the same file. For example, the shared boundary between California and Nevada is represented only once, rather than being duplicated for both states. A single TopoJSON file can contain multiple feature collections without duplication, such as states and counties. Or, a TopoJSON file can efficiently represent both polygons (for fill) and boundaries (for stroke) as two feature collections that share the same arc mesh.
So, start by loading the topojson library...
<script src="https://unpkg.com/topojson#3"></script>
...then create a topology object for your GeoJSON data; note that TopoJSON expects an array of GeoJSON features, e.g. I'll load a GeoJSON FeatureCollection containing the Natural Earth country boundaries via fetch and create a topology:
fetch("ne_110m_admin_0_countries.geojson")
.then(res=>res.json())
.then(json=>{
var topo = topojson.topology([json]);
/* ...more stuff here soon */
});
...then add a L.GeoJSON layer with just the polygon fill, setting the stroke option to avoid drawing any lines on the contour of the polygons (remember that path styling options can be passed to GeoJSON constructors) ...
var layerFill = L.geoJson(json, { stroke: false }).addTo(map);
...calculate the mesh of the topology, which will be a GeoJSON MultiLineString...
topojson.mesh(topo);
...and create another L.GeoJSON instance to draw said MultiLineString. Style the lines as you like (including dashArray), e.g. ...
var layerLines = L.geoJson(topojson.mesh(topo), {
fill: false, dashArray:[3, 6], weight: 2
}).addTo(map);
The end result, which you can see here as a working example, contains no overlapping dashed lines, as expected:
Using TopoJSON is one possible approach. There are other possible approaches (e.g. pre-generating a MultiLineString GeoJSON file with just the boundaries, using a different tool, etc); but the idea of using topological rules on the dataset would be the same.

Related

cant find source-Layer Ids after reading Vector Tile using vector-tile JS library

I took a vector tile to read the Layer and its corresponding features.
I found
My layer is "Landuse"
I found all the features that are inside the "Landuse" Layer.
I know that some of the features belong to Cemetry, Education etc..
The problem is , i am not able to find the ID of each feature like its been represented in the StyleSheet.
With out the "id", i cannot cannot seperate and display my features with in "landuse" layer
Here is one sample from the style sheet
"id": "landuse_cemetery",
"source": "orgVector",
"source-layer": "landuse",
"type": "fill",
"minzoom": 11
My question is how to get the "id" along with features?
Please help me if i am missing some thing while reading the MVT tile.
You're confusing vector tile layers and style layers.
Your vector tiles contain a layer called landuse.
Your style can contain layers called whatever they want. In this case your style layer is called landuse_cemetery, but you could call it something else. The link between your style layer and the vector tile layer is this:
"source-layer": "landuse",
If you want your cemetery layer to only include cemeteries, you probably want to add a further filter, which make use of other attributes in the data.
You can use Vector Inspector to better understand what those are.

Is there a way to check for markers whos icons intersect / overlap visibly?

I am building a map and want to use the leaflet markercluster plugin to cluster any markers that intersect visibly (the icons overlap each other). I can't seem to figure out a way to check whether the markers icons intersect though.
I've examined the documentation and the Marker objects. The marker object has no "bounds" object and has no function to return the bounds of the icon.
Yes, it's possible.
This is implemented in some Leaflet plugins, like Leaflet.LayerGroup.Collision - the technique involves fetching the computed style of each icon's HTML element to get the actual size in CSS pixels, offset those numbers by the relative pixel position of the marker's LatLng, and using a rtree data structure to speed up the calculation of the overlaps. Do have a look at the complete source for LayerGroup.Collision plugin.
Note that this technique only takes into account the rectangular bounding boxes of the icons; while it would be possible to check for the individual transparent pixels, that would involve more complex data structures and a different technique to fetch the opacity of each pixel.

Using Mapzen tiles with Leaflet

My reading of the Leaflet and Mapzen documentations suggest that in order to use a custom tile provider with Leaflet, one needs to do just two things:
Specify the tile provider in L.tilelayer(urlTemplateToTileProvider)
Set this provider to MapZen
var urlTemplateToTileProvider =
'http://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt?api_key=apiKey'
However, when I try this I end up with an empty map which then proceeds to display markers etc correctly. And yet a manual test for a generated tile URL, e.g.
http://tile.mapzen.com/mapzen/vector/v1/all/14/8471/5583.mvt?api_key=apiKey
did in fact download some - unintelligible to me - data.
I also tried using the other two formats mentioned in the Mapzen docs (.json and .geojson) but with exactly the same result. Given that the latter two formats return human readable data, I checked them out for my test tile in my browser and the data is indeed for the area I want to use.
Curiously enough, the Leaflet docs and tutorials request a PNG tile layer (http://{s}.tile.osm.org/{z}/{x}/{y}.png), not raw data.
What am I doing wrong here?
The Tile Layer is for raster tiles (i.e. plain images, like the PNG format for example).
Mapzen delivers vector tiles. To use them with Leaflet, you could use a plugin, e.g. Leaflet.VectorGrid (license)
Display gridded vector data (sliced GeoJSON or protobuf vector tiles) in Leaflet 1.0.0
See the demo, which includes tiles from Mapzen
var mapzenTilesUrl = "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt?api_key={apikey}";
var mapzenVectorTileOptions = {
rendererFactory: L.canvas.tile,
attribution: '© MapZen, © OpenStreetMap contributors',
vectorTileLayerStyles: vectorTileStyling,
apikey: 'KEY',
};
var mapzenTilesPbfLayer = L.vectorGrid.protobuf(mapzenTilesUrl, mapzenVectorTileOptions);
Since you have raw data in the vector tiles, you need to provide the styling spec (vectorTileStyling)

Is it possible to conditionally color countries in Mapbox Studio based on data?

I am attempting to create a choropleth using the actual polygons included in any one of the base Mapbox maps.
Specifically, I have a geojson structure with a data specific property in the properties object and I'd like to have a different color land fill for all countries, depending on where the fall on a certain scale.
So far the Map class appears to color all land at once:
Map {
background-color: red;
}
And I can't seem to do this:
Map {
[myVar > 0.4] { background-color: pink; }
[myVar <= 0.4] { background-color: green; }
}
I've tried to use my own polygons from my GeoJSON file but they aren't nearly as clean as the Mapbox polygons, even at the highest resolution I've found. Additionally, I want to be able to overlay the labels and other markers that Mapbox base styles have, just on top of my cholorpleth.
I've also tried to color the #admin[admin_level=2][maritime=0] regions, but they don't appear to be polygons and result in something like this:
Thanks in advance!
Assuming Tilemill 0.10.1 and using this GeoJSON (imported as countrydata) and this CartoCSS:
#countrydata {
line-color:#594;
line-width:0.5;
polygon-opacity:1;
polygon-fill:#ae8;
[2014_pop>=100000] {polygon-fill:#yellow;}
[2014_pop>=10000000] {polygon-fill:#orange;}
[2014_pop>=20000000] {polygon-fill:#pink;}
[2014_pop>=200000000] {polygon-fill:#red;}
}
I get:
Notice how color is informed by the 2014_pop property. I would recommend naming properties with a starting letter so that the editor doesn't get confused.

Leaflet: How to deal with overlapping lines?

How can I deal with overlapping lines in the Leaflet map library?
I download geoJSON from the server sid and draw it right onto the map. If there are two identical entries, Leaflet draws them twice. This could be fixed by finding exact duplicated on the server side.
That however doesn't work for different datasets sharing some of the same space. As a result parts of both are drawn onto the same spot.
It appears that the lines are being rendered with the default Leaflet Polyline opacity of 0.5. If you were instantiating the Polylines yourself in code, you could override the opacity to make the lines opaque in this manner:
var myPolyLine = new L.Polyline( myPoints, { opacity: 1 } );
The line that would appear on top would then be the line that you added to the map last (one or the other is going to be on top, unless you make them both opaque and the same color). But this may be moot if you are loading in geoJSON directly and don't have control over how Leaflet renders it.