I want to draw a map using Equirectangular projection in the react-leaflet.
The reaction-leaflet used CRS, which supports Equirectangular projection, but the image of the desired map is not connected and truncated.
The coordinates also do not appear in the correct position.
<MapContainer
center={[0, 0]}
zoom={2}
scrollWheelZoom={true}
zoomControl={false}
style={{ width: "100%", height: "100%" }}
minZoom={2}
maxZoom={5}
doubleClickZoom={false}
crs={CRS.EPSG4326}
>
It looks like you are rendering an Open Streets Map correct? I believe that the Open Steets Map is supposed to use the EPSG:3857 projection. Open Street Map tiles use a coordinate system based on the wgs84 datum (ESPG 3857). I don't think you can project any map on any projection. You can refer to this GIS.stackexchange question which explains the differences.
I just tried it on a demo leaflet map that I have and got the same thing. .
<MapContainer ref={mapRef} center={[lat, lon]} zoom={zoom} scrollWheelZoom={true} crs={CRS.EPSG4326} id="leaflet-container">
Related
I am trying to render an image like below and want it to act like the world map.
I want to create a javascript function which shows location dynamically into the image when I pass (latitude, longitude) pair.
I have tried google map API documented in "developers.google.com/maps/documentation/javascript/examples/…". But the problem is that image is not in that projection type. So results are so different than expected.
Your image appears to use a plate carreé projection, which is commonly used for raster data sets of the world. This projection easily allows reprojection - and as rioV8 suggests, simply maps longitude and latitude as though they were x,y coordinates on a Cartesian plane rather than a spheroid.
The image you have shared is twice as wide as high, which also helps confirm a plate carreé: if the projection maps longitude and latitude as Cartesian coordinates the image should be twice as wide as high (360 degrees around, 180 degrees pole to pole).
Now we need to make a projection for this (not particularly difficult) or we could use a d3 projection: d3.geoEquirectangular() (plate carreé goes by a few names).
I'll just go over the d3 method here, if using the d3 projection, we need to understand the scale of the projection. The default value takes 2π radians and maps it to 960 pixels, which gives us a scale of: 960/2π. If we want to wrap 2π radians to an arbitrary image width we use a scale of width/2π.
So we could project points relative to this image with:
d3.geoEquirectangular()
.scale(width/Math.PI/2)
.translate([width/2,height/2]) // image width/height so [0,0] is centered
var width =400;
var height = 200;
var projection = d3.geoEquirectangular()
.scale(width/Math.PI/2)
.translate([width/2,height/2]);
var svg = d3.select("svg");
svg.append("circle")
.attr("r", 4)
.attr("fill","yellow")
.attr("transform", "translate("+projection([79.842778,6.934444])+")")
img, svg {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<div>
<img src="https://i.stack.imgur.com/4p3MK.jpg" width="400" height="200"/>
<svg width="1958" height="929"></svg>
</div>
Of course once we know the projection, we could reproject the original raster image (eg.), and project points onto that.
I have a problem with leaflet when it come to have point near W180. The problem is the same as this one : https://github.com/Leaflet/Leaflet/issues/82
But on marine traffic we can see exactly what I try to achieve.
A continuous world where -180 W will cross this section so I can have a polyline which is not cut and rendered on the other side.
How is it possible since leaflet is able to have greater longitude than 180 ? I've been in the dark on this issue for some time.
I first tried to remove the worldcopyjump and the maxbounds but I don't know how to have two maps at the same time and how to avoid the polyline being cut.
EDIT
I've been looking through the mtMap object on https://www.marinetraffic.com with one boat and there are using this settings :
center: [16.46769474828897, 216.73828125],
maxBounds: [[150,540],[-150,-540]],
My guess is that here are not using negative longitude, so maybe the solution is to have only positive longitude (greater than 180) ?
I'm working with react-leaflet package, however, if you can answer the question in plain leaflet that would be helpful as well.
I am successfully panning to the bounds of a polygon that I supply like so:
<Map center={position}
zoom={13}
bounds={this.state.bounds}
className="campaignimagery-map">
<TileLayer
url="http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution=""
/>
However, I would like the entire polygon boundary box to be some transparent color so they can see exactly where the boundary box lies on the map. Is this possible?
Short answer
Use the bounds to draw a colored rectangle like this L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);. See related documentation for more information.
Explanation
I don't think it's possible to color bounds as is, but you can use bounds for drawing a polygon. Then the polygon itself can be colored and managed as you wish.
I am using Leafletjs. Currently its pretty straight forward, I have a streets view from open maps.
var streets = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors'
});
I also have a WMS layer that is coming from a geoserver. It has the standard getFeatureInfo and everything shows up correctly.
L.tileLayer.wms("GEOSERVERURL", {
layers: 'layers',
format: 'image/png'
,transparent: true
}).addTo(map);
The wms layer is also clickable and I use getFeatureInfo to get the info for that layer. The issue is that the user doesn't know its clickable because the cursor never changes when they hover of the wms layer. My question is how do make the cursor change when hovering over the layer?
Has anyone implemented this feature before or have an idea to implement it? The only research I have stumbled across so far has using mouseover on the map and calling getFeatureInfo to tell if its over a layer. However, that seems like it would cause a lot of chatter just to identify cursor area.
EDIT: To clarify, I want the cursor to only change when its hovered over the wms layer that is populated. Although it technically gets applied to the whole map, it only has content on a part of it. Which kind of raises the question of 'Can I limit the wms layer to only the content area and then show a cursor?' Maybe a bounding area or something along those lines?
EDIT 2: Below is an example of what it looks like. The street map parts I want to keep the normal cursor but I want a pointer when hovering over the colored wms map parts.
Set an ID on the tileLayer's container and then use CSS to change the cursor:
Javascript:
var wms = L.tileLayer.wms("GEOSERVERURL", {
layers: 'layers',
format: 'image/png',
transparent: true
}).addTo(map);
wms.getContainer().setAttribute('id', 'wmsContainer');
Stylesheet:
#wmsContainer {
cursor: grab; /* or any other cursor: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor */
}
Note: you need to do this after the layer is added to the map. Before you add it to the map the getContainer method will return undefined.
Edit after question edit and comments:
Unfortunatly that's not possible. At least not as far as i know. Because L.TileLayer.WMS is a layer of images, there is absolutely no way of deducting which tiles have features on them and which are transparent.
What you could do as a workaround is work out the boundaries of your object, use that to create a transparent polygon without stroke and put that over your WMS layer. Polygons are interactive thus you get the cursorchange included, plus as an extra bonus, you can do other fancy stuff like show the outline or something like that on mouseover. I've created a little demo from the WMS example you supplied in the comments.
http://plnkr.co/edit/1HGn6IUzdrn1N5KGazXQ?p=preview
Note that i'm using a GeoJSON layer with one feature instead of a polygon, because it was easier to find the outline of the US in GeoJSON format. But in your case a four point polygon would do the trick just as wel.
Hope that helps, let me know if something isn't clear.
I use angularjs-google-maps for my application,
in this plugin we have icon option for <marker> :
http://rawgit.com/allenhwkim/angularjs-google-maps/master/build/docs/index.html
Now I have an icon and use in this option, but how can I say show pin#2x.png on retina displays ?
<map center="[40.74, -74.18]">
<marker
position="[40.76, -74.16]"
draggable="false"
visible="true"
icon="pin.png"></marker>
</map>
In Google Map API V3 there are two scale parameter for Custom Icon. One is size and other one is scaleSize. For this you can try out adding a scale parameter in the marker tag. This is a potential solution for getting a higher resolution while displaying the custom icons in Google Maps retina display.
<marker
position="[40.76, -74.16]"
draggable="false"
visible="true"
symbol="pin.png">
scaleSize=2</marker>
Source: https://developers.google.com/maps/documentation/javascript/reference#Icon
Hope this would help :)