I'm using leaflet.draw, and when a rectangle is created, i'm fetching rectangle's data using layer.toGeoJSON(), and then i save it into a db using ajax.
After that, when the user display the map again, i'm loading previously saved data, and push them into the featureGroup reserved for leaflet.draw using L.GeoJSON.geometryToLayer()
Problem is that my previously created rectangle is now a real polygon for leaflet.draw.
"Rectangle" does not exist in geoJson specs, so i can understand that.
Now, in "properties" of the geojson, i know that the previous shape was a rectangle, with the "type" attribut.
My question is : is there a way to force a shape to be a rectangle in a leaflet.draw point of view ?
Thanks in advance !
I ran into this same problem and have come up with a solutions which works for me although it isn't the most elegant method.
Using leaflet.draw I receive a new layer on which I call layer.toGeoJSON() to save the rectangle to my database. On refresh of the page I'm pulling that GeoJSON representation back from my database and storing it with:
var geojson = JSON.parse(geojson_string);
What I tried first was to build my own Rectangle from the points and add it to drawnItems.
var bounds = L.latLngBounds(geojson.geometry.coordinates);
var rect = L.rectangle(bounds);
drawnItems.addLayer(rect);
This code did not throw an error, but it also didn't show a rectangle on the map. After further investigation I found the coordinate pairs output from layer.toGeoJSON() and the coordinate pairs needed by L.latLngBounds() were reversed (i.e. one was [lat, lng] and the other was [lng, lat]) which caused the Rectangle to be created but in entirely the wrong location. To get around this I constructed the layer first as a GeoJSON layer which results in a polygon, but then use that representation's bounds to construct my Rectangle.
var geojson_layer = L.GeoJSON.geometryToLayer(geojson);
var rect = L.rectangle(geojson_layer.getBounds());
drawnItems.addLayer(rect);
This successfully creates a Rectangle which leaflet.draw recognizes and allows for the edit tools to work correctly.
Related
my LeafLet map contains a GeoJSON and a Maptiler layer.
First I set up my map by var map = L.map(...). Right after that I add my GeoJSON layer. Then I load my map style via AJAX, change a few things in it, and finally add it to the map as well.
After the map is initialized, both layers seem to have a mismatch in zoom and pan (see image).
I just figured out that the Mapbox-GL-LeafLet-plugin (https://github.com/mapbox/mapbox-gl-leaflet) which is advised by Maptiler, is not working for me.
When I use an open, unstyled TileLayer, the problem is gone.
I have a drawing feature where, as in one case, a person can draw a circle using the methodology in OL docs example. When that's saved, the server needed to be have it converted to a polygon, and I was able to do that using fromCircle.
Now, I'm needing to make the circle modifiable after it's been converted and saved. But I don't see a clear cut way to get a Circle geometry out of the Polygon tools provided in the library. There is a Polygon.circular, but that doesn't sound like what I want.
I'm guessing the only way to do this is to grab the center, and one of the segment points, and figure out the radius manually?
As long as fromCircle used sides set to a multiple of 4 and rotation zero (which are the default) center and radius can be easily obtained to convert back to a circle:
center = ol.extent.getCenter(polygon.getExtent());
radius = ol.extent.getWidth(polygon.getExtent())/2;
So I'm currently working on Deck.gl and React and I need to load a geojson file which has an additional property named "floors" or something similar which tells how many floors the building has.
Is there any way to extrude alternating floors horizontally just a little bit so that it looks like a floor edge like some of the buildings in this image (although most of them just go thinner at the top). I tried searching the deck.gl but there is no such thing. I looked up and found MapBox-gl-js has something called an extrusion-base-height which lets you add polygon above another but there is no such thing as extruding horizontally to make 1 floor thinner and then back to the original size. This would give and edge whenever a new floor starts.
I have scoured the docs for deck.gl but couldn't find any thing on extruding horizontally or in another sense changing the polygon area/size so that I can draw multiple size polygons on the same spot.
Another clear picture of what I'm trying
Things I want to do.
The red polygon is tilted. Need to make it's orientation the same as the green one and reducing it's area at the same time.
Move the red polygon base at the top of the green polygon.
The test data I'm using is given below,
var offset = 0.00001;
var data = [{
polygon: [
[-77.014904,38.816248],
[-77.014842,38.816395],
[-77.015056,38.816449],
[-77.015117,38.816302],
[-77.014904,38.816248]
],
height: 30
},
{
polygon: [
[-77.014904 + offset ,38.816248],
[-77.014842 - offset, 38.816395 - offset],
[-77.015056 - offset, 38.816449 - offset],
[-77.015117 + offset, 38.816302],
[-77.014904 + offset, 38.816248]
],
height: 40
}
];
EDIT:- I think the proper way would be to convert longitude/latitude to Cartesian Coordinates, get the vectors to the 4 corners of the polygon translate the vectors to move towards the center by the offset amount then convert back. But this would only work with quad/rectangle polygon, for buildings that are made up of multiple quads I'd need another way.
If I'm understanding correctly, your problem boils down to: given a polygon (the footprint of the lower part of the building), generate a slightly smaller version of the same polygon, centered within it.
Fortunately, this is really easy using Turf's transformScale method.
So your steps will be:
Convert your polygon data into GeoJSON. (Which I assume you have some mechanism to do, in order to display it in Mapbox-GL-JS in the first place.)
Generate a smaller polygon using turf.transformScale(base, 0.9)
Add the new polygon with map.addSource
Display the new polygon with map.addLayer, setting the extrusion base height etc as required.
I am using Australian government map data found here: Victoria, Australia locality data, which is provided in the EPSG4326 projection.
When I try to use the data with leaflet, of course, my data is a bit distorted due to the earth's curvature - so my data is not represented properly on the screen because the maps are using a different projection to my data.
I have tried to force the map to use EPSG4326 by setting it in Map options and also in the TileLayer, as shown here:
var gisLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
//subdomains: ['0', '1', '2', '3'],
attribution: 'openstreetmap',
reuseTiles: true,
updateWhenIdle: false,
crs: L.CRS.EPSG4326
});
var map = L.map('map', {
center: [-28.5, 135.575],
zoom: 4
,crs: L.CRS.EPSG4326
});
map.addLayer(gisLayer);
but when I do this, the maps do not display. I don't believe the map tiles have been generated for this projection. That said, there is a suggestion in the docos here that it might be possible, but I couldn't get this working. (Did I just get the configuration wrong?)
It seemed like it was working when I retrieved the data and placed it on the map, but when I got the map bounds to select the data for the visible region, it also showed distorted. So I tried to convert the map bounds to EPSG4326 manually, to pass that to the database, as follows:
var bounds = map.getBounds();
var coords4326_NE = L.Projection.SphericalMercator.unproject(bounds._northEast);
console.log(coords4326_NE);
but that broke the code. I was passing the wrong structure in and I couldn't get this right either.
Of course, I would also accept transforming every point returned from the database to the default projection, which I think is EPSG3857. But I am having doing this as well.
I have provided as jsFiddle here where I have been attempting to do the above.
Does anyone know how I can achieve this?
Your GeoJSON data is encoded in WGS84, which can be simply plotted on EPSG4326, but is also the expected input for EPSG3857 (Web Mercator).
From that Wikipedia article:
While the Web Mercator's formulas are for the spherical form of the Mercator, geographical coordinates are required to be in the WGS 84 ellipsoidal datum.
Therefore, you do not have to change anything to plot your data onto a regular Leaflet map, using regular tiles (from OSM or Mapbox, which provide tiles only for EPSG3857).
I am trying to get the geometry of the polygon with queryRenderedFeatures
On zoom level 12 is ok, but on 15 I got the wrong geomentry.
Here is my code, and I everytime on mouse over I get the different coordinates.
Here https://codepen.io/benderlidze/pen/qPXNJv - hover the mouse from the top on the poly and from the bottom. The red poly is a geometry returned by queryRenderedFeatures and it is always different.
map.on("mousemove", "seatRowsFill", function(e) {
map.getCanvas().style.cursor = 'pointer';
map.setFilter("seatRowsFill-hover", ["==", "rowNumber", e.features[0].properties.rowNumber]);
var relatedFeatures = map.queryRenderedFeatures(e.point, { layers: ['seatRowsFill'],"filter": ["==", "rowNumber", e.features[0].properties.rowNumber] } )
console.log(relatedFeatures["0"].geometry.coordinates["0"][2])
At zoom 15, the geometry crosses a tile boundary. You can see this by adding map.showTileBoundaries = true: https://codepen.io/stevebennett/pen/XezJNB
From the documentation for queryRenderedFeatures():
Because features come from tiled vector data or GeoJSON data that is converted to tiles internally, feature geometries may be split or duplicated across tile boundaries and, as a result, features may appear multiple times in query results. For example, suppose there is a highway running through the bounding rectangle of a query. The results of the query will be those parts of the highway that lie within the map tiles covering the bounding rectangle, even if the highway extends into other tiles, and the portion of the highway within each map tile will be returned as a separate feature. Similarly, a point feature near a tile boundary may appear in multiple tiles due to tile buffering.
Instead of retrieving the geometry and then displaying that, it's usually better to have a separate layer which is just used for highlighting, then update the filter on that layer to match some property.
So, if you update the highlight layer's filter to be ['==', id, 500], then all the different pieces of that polygon will display correctly.
See the "Create a hover effect" example.