I make map using Leaflet with one circle.
index code:
<div id="mapid" style="height: 500px;"></div>
<script type="text/javascript">
var mymap = L.map('mapid').setView([52.233333, 19.016667], 6);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
minZoom: 6,
}).addTo(mymap);
var x = 52.233333;
var y = 19.016667;
showCircle(x,y);
</script>
ShowCircle :
function showCircle(x,y)
{
var circle = L.circle([x,y], 1900, {
color: 'blue',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap);
}
The problem is : the circle always have the same size.
I want to get: if i zoomout map the circle is bigger, when i zoomin the circle is smaller. (zoomin, zoomout is from scroll)
How to get this effect?
There are two kinds of circles in Leaflet: L.Circle and L.CircleMarker. L.Circle has a radius specified in meters, and L.CircleMarker has a radius specified in pixels.
Your question is not fully clear (what do you mean by "always have the same size"? Meters or pixels?); but I guess that you want to use L.CircleMarker instead of L.Circle.
Try the following , and tweak it as per your requirement :
var radiusQuantifier=100;
map.on('zoomend',function (e) {
circle.setRadius(map.getZoom()*radiusQuantifier);
});
This will change the radius of the circle on zoomend event.You can combine it with zoomstart event to get the desired result.
Note : Increase/Decrease the value of radiusQuantifier as it seems fit.
Related
I have some code with points which draws a polygon.
Here is the code:
app.pts = [
[33.644631, -70.610453],
[33.637884, -70.608253],
[33.637566, -70.608704],
[33.638933, -70.610935],
[33.641044, -70.614036],
[33.641386, -70.614176]
];
app.map = L.map('map').setView(app.pt, 15);
app.polygon = L.polygon(app.pts, {
color: '#00ff00',
opacity: 0.6,
fillOpacity: 0.2
});
What I would like is a circle instead, so my question is:
How do I modify this code so I can draw a Circle instead of a polygon?
The circle would be 50 meters radius and centered on 33.644631, -70.610453
Per the documentation
app.circle = L.circle([33.644631, -70.610453], {radius: 50});
I have a paper.js layer where users can draw different paths (circles, line, etc). This layer can be panned or zoomed using mouse scrolling or dragging. I use affine matrix transformation to zoom/pan paths in this layer. This works rather well.
What i'm looking for is to create a circle (Path.Circle object) that can be panned and zoomed using matrix, just its radius has to be always fixed (5px for example). So basically matrix transformation needs to be applied only to position of circle, but not to outline of it.
Below is sample of a circle with radius 20px transformedPath, that is zoomed to 2x. Questions is how to keep radius of circle transformedPath fixed (radius = 20px), while applying the matrix transformation.
var transformedPath = new paper.Path.Circle(100,100,20);
transformedPath.strokeColor = 'black';
paper.project.activeLayer.matrix = new paper.Matrix(
2, 0,
0, 2,
0, 0
);
UPDATE. Here's a more general sketch (code below) that is based on solution suggested by sasensi. In this sample blue circle radius stays fixed (this is correct), but problem is that blue circle also stays on the same place instead.
The desired outcome is that both circles move to new position, but blue circle radius stays fixed.
// draw a normal circle
var normalCircle = new Path.Circle({
center: new Point(100,100),
radius: 50,
fillColor: 'orange',
});
// draw another circle that will have scale transformation reversed
var notScalingCircle = new Path.Circle({
center: new Point(100,100),
radius: 30,
fillColor: 'blue',
});
// draw instructions
new PointText({
content: 'press mouse button down to zoom in and see that blue circle size does not change',
point: view.center + [0, -80],
justification: 'center'
});
function transformLayer(matrix) {
// scale layer
// project.activeLayer.applyMatrix = false;
project.activeLayer.matrix = matrix;
// scale item with inverted amount to make it display like if it was not scaled with the layer
notScalingCircle.matrix = matrix.clone().invert();
}
var matrix = new paper.Matrix(
2,0,
0,1.5,
50,30
);
// on mouse down...
function onMouseDown() {
// ...scale up
transformLayer(matrix);
}
// on mouse up...
function onMouseUp() {
// ...scale down
transformLayer(matrix.clone().invert());
}
I think that the best way do that is, when you scale your layer with a given amount, to scale your circle with the inverted amount.
That will make your circle look like if it was not scaled.
Here is a sketch demonstrating the solution:
// draw a normal circle
var normalCircle = new Path.Circle({
center: view.center,
radius: 50,
fillColor: 'orange'
});
// draw another circle that will have scale transformation reversed
var notScalingCircle = new Path.Circle({
center: view.center,
radius: 30,
fillColor: 'blue'
});
// draw instructions
new PointText({
content: 'press mouse button down to zoom in and see that blue circle size does not change',
point: view.center + [0, -80],
justification: 'center'
});
function scaleLayer(amount) {
// scale layer
project.activeLayer.scale(amount, view.center);
// scale item with inverted amount to make it display like if it was not scaled with the layer
notScalingCircle.scale(1 / amount);
}
// on mouse down...
function onMouseDown() {
// ...scale up
scaleLayer(3);
}
// on mouse up...
function onMouseUp() {
// ...scale down
scaleLayer(1 / 3);
}
Edit
In response to the new example, you just have to invert the scaling transformation on the item and not all the matrix (which also include translation and rotation).
Here is the corrected sketch:
// draw a normal circle
var normalCircle = new Path.Circle({
center: new Point(100, 100),
radius: 50,
fillColor: 'orange'
});
// draw another circle that will have scale transformation reversed
var notScalingCircle = new Path.Circle({
center: new Point(100, 100),
radius: 30,
fillColor: 'blue'
});
// draw instructions
new PointText({
content: 'press mouse button down to zoom in and see that blue circle size does not change',
point: view.center + [0, -80],
justification: 'center'
});
function transformLayer(matrix) {
// scale layer
// project.activeLayer.applyMatrix = false;
project.activeLayer.matrix = matrix;
// just invert the scale and not all matrix
notScalingCircle.scale(1 / matrix.scaling.x, 1 / matrix.scaling.y);
}
var matrix = new paper.Matrix(
2, 0,
0, 1.5,
50, 30
);
// on mouse down...
function onMouseDown() {
// ...scale up
transformLayer(matrix);
}
// on mouse up...
function onMouseUp() {
// ...scale down
transformLayer(matrix.clone().invert());
}
Am using ImageOverlay to use an image as a map, using Leaflet.js - but when changing the zoom the markers change position.
Have followed guideance in this tutorial and a code pen example is here.
// Markers
var markers = [{"title":"OneOcean Port Vell","description":"Super yacht marina","link":"http:\/\/www.oneoceanportvell.com\/","x":"68.28125","y":"68.443002780352178"}];
var map = L.map('image-map', {
minZoom: 2,
maxZoom: 4,
center: [0, 0],
zoom: 2,
attributionControl: false,
maxBoundsViscosity: 1.0,
crs: L.CRS.Simple
});
// dimensions of the image
var w = 3840,
h = 2159,
url = 'map.png';
// calculate the edges of the image, in coordinate space
var southWest = map.unproject([0, h], map.getMaxZoom()-1);
var northEast = map.unproject([w, 0], map.getMaxZoom()-1);
var bounds = new L.LatLngBounds(southWest, northEast);
// add the image overlay,
// so that it covers the entire map
L.imageOverlay(url, bounds).addTo(map);
// tell leaflet that the map is exactly as big as the image
map.setMaxBounds(bounds);
// Add Markers
for (var i = 0; i < markers.length; i++){
var marker = markers[i];
// Convert Percentage position to point
x = (marker['x']/100)*w;
y = (marker['y']/100)*h;
point = L.point((x / 2), (y / 2))
latlng = map.unproject(point);
L.marker(latlng).addTo(map);
}
In the codepen, change zoom to 4 to see the markers lose their position.
Ideally I'm trying to change the zoom to allow for different screen sizes and to get more of the map visible on mobile devices.
Also perhaps related, I can't see to get the zoomSnap feature to work to allow for fractional zooming.
Any pointers greatly appriciated.
map.unproject needs the zoom value at which you want the un-projection to be applied.
You correctly specify your static imageZoom value to unproject when computing your bounds and center, but not for your markers positions.
If the zoom parameter is not specified, then unproject uses the current map zoom level, i.e. what you have defined in your zoom variable. That is why when you change its value, unproject for your markers uses a different value, and they are positioned in different locations.
You even had to divide your x and y values (relative to your image) by 2, to account for the fact that in your initial situation, they are correct for an imageZoom of 4, but since you do not specify the zoom for unproject, the latter uses the current zoom (i.e. 3), so coordinates should be divided by 2 to be "correct".
Updated codepen: https://codepen.io/anon/pen/pLvbvv
I'm trying to draw a hexagonal grid in Google Maps. I've come up with a solution based off this answer which looks fine at higher zooms, but when zoomed further out I find that the classic "orange-peel" problem occurs: The hexagons no longer fit together like they should:
I'm using this rather cool geodesy library to calculate hexagon centers based on an ellipsoidal model (since a 2d model clearly doesn't work on a real-world map) but it's still looking pretty bad when zoomed out.
Preferably, I'd like to draw the hexagons in such a way that they are exactly the same shape and size on screen.
Here's the code I've been working with, also available as a Plunker here. I've tried calculating the vertices of each polygon using the same geodesy library that I'm using to calculate the polygon centers, but it still doesn't look right when zoomed out.
var hexgrid = [];
function initialize(){
// Create the map.
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 51.5, lng: 0},
scrollwheel: true,
zoom: 8
});
// This listener waits until the map is done zooming or panning,
// Then clears all existing polygons and re-draws them.
map.addListener('idle', function() {
// Figure out how big our grid needs to be
var spherical = google.maps.geometry.spherical,
bounds = map.getBounds(),
cor1 = bounds.getNorthEast(),
cor2 = bounds.getSouthWest(),
cor3 = new google.maps.LatLng(cor2.lat(), cor1.lng()),
cor4 = new google.maps.LatLng(cor1.lat(), cor2.lng()),
diagonal = spherical.computeDistanceBetween(cor1,cor2),
gridSize = diagonal / 20;
// Determine the actual distance between tiles
var d = 2 * gridSize * Math.cos(Math.PI / 6);
// Clear all the old tiles
hexgrid.forEach(function(hexagon){
hexagon.setMap(null);
});
hexgrid = [];
// Determine where the upper left-hand corner is.
bounds = map.getBounds();
ne = bounds.getNorthEast();
sw = bounds.getSouthWest();
var point = new LatLon(ne.lat(), sw.lng());
// ... Until we're at the bottom of the screen...
while(point.lat > sw.lat()){
// Keep this so that we know where to return to when we're done moving across to the right
leftPoint = new LatLon(point.lat, point.lon).destinationPoint(d, 150).destinationPoint(d, 210).destinationPoint(d, 270).destinationPoint(d, 90)
step = 1;
while(point.lon < ne.lng()){
// Use the modulus of step to determing if we want to angle up or down
if (step % 2 === 0){
point = new LatLon(point.lat, point.lon).destinationPoint(d, 30);
} else {
point = new LatLon(point.lat, point.lon).destinationPoint(d, 150);
}
step++; // Increment the step
// Draw the hexagon!
// First, come up with the corners.
vertices = [];
for(v = 1; v < 7; v++){
angle = v * 60;
vertex = point.destinationPoint(d / Math.sqrt(3), angle);
vertices.push({lat: vertex.lat, lng: vertex.lon});
}
// Create the shape
hexagon = new google.maps.Polygon({
map: map,
paths: vertices,
strokeColor: '#090',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#090',
fillOpacity: 0.1,
draggable: false,
});
// Push it to hexgrid so we can delete it later
hexgrid.push(hexagon)
}
// Return to the left.
point = leftPoint;
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Please consider that Google Maps is in Mercator Projection.
You have to compensate for the sphere of the globe on the projection.
https://en.wikipedia.org/wiki/Mercator_projection
On Leaflet I can create a new circle easily given the centre and the radius:
// Circle
var radius = 500; // [metres]
var circleLocation = new L.LatLng(centreLat, centreLon);
var circleOptions = {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
};
var circle = new L.Circle(circleLocation, radius, circleOptions);
map.addLayer(circle);
The circle above is created and drawn without problems, so it is all.
However, if I wanted now to create and draw a rectangle that which bounds the circle, it does not work. Here is what I did:
// Rectangle
var halfside = radius; // It was 500 metres as reported above
// convert from latlng to a point (<-- I think the problem is here!)
var centre_point = map.latLngToContainerPoint([newCentreLat, newCentreLon]);
// Compute SouthWest and NorthEast points
var sw_point = L.point([centre_point.x - halfside, centre_point.y - halfside]);
var ne_point = L.point([centre_point.x + halfside, centre_point.y + halfside]);
// Convert the obtained points to latlng
var sw_LatLng = map.containerPointToLatLng(sw_point);
var ne_LatLng = map.containerPointToLatLng(ne_point);
// Create bound
var bounds = [sw_LatLng, ne_LatLng];
var rectangleOptions = {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
};
var rectangle = L.rectangle(bounds, rectangleOptions);
map.addLayer(rectangle);
The size of the rectangle that I obtain has nothing to do with 500 metres. Also, it looks like the size of the rectangle depends on the zoom level the map is. None of these problems arose for the circle.
I suspect the way I transform the latitude/longitude to point and viceversa is wrong.
Just use the getBounds method that L.Circle inherits from L.Path:
Returns the LatLngBounds of the path.
http://leafletjs.com/reference.html#path-getbounds
var circle = new L.Circle([0,0], 500).addTo(map);
var rectangle = new L.Rectangle(circle.getBounds()).addTo(map);
Working example on Plunker: http://plnkr.co/edit/n55xLOIohNMY6sVA3GLT?p=preview
I was getting "Cannot read property 'layerPointToLatLng' of undefined" error, So I made some changes to iH8's answer.
var grp=L.featureGroup().addTo(map);
var circle=L.circle([0,0],{radius:<circle radius>}).addTo(grp);
L.rectangle(circle.getBounds()).addTo(this.bufferMap);
map.removeLayer(grp);