Best way to make marker resizable in leaflet - javascript

I am trying to resize my markers every time the map is zoomed in or out.
Currently I am using this approach:
Iterate all markers in zoomend method.
get current icon size
Perform some calculation to get the new marker size according the zoom size.
set the new dimension to the icon object.
map.on('zoomend', function() {
zoomEndLevel = map.getZoom();
var difference = zoomEndLevel - zoomStartLevel;
console.log("difference in zoom " + difference);
markerArray.forEach(function(marker) {
var icon = marker.options.icon;
var oldX = icon.options.iconSize[0];
var oldY = icon.options.iconSize[1];
var newX = getNewIconAxis(oldX, difference);
var newY = getNewIconAxis(oldY, difference);
console.log(newX + " " + newY);
icon.options.iconSize = [ newX, newY ];
marker.setIcon(icon);
});
});
map.on('zoomstart', function() {
zoomStartLevel = map.getZoom();
});
function getNewIconAxis(value, zoomChange) {
if (zoomChange > 0) {
for (var i = zoomChange; i > 0; i--) {
value = value * 2;
}
} else {
for (var i = zoomChange; i < 0; i++) {
value = value / 2;
}
}
return value;
}
Problem :
This code works fine if I zoom in and out 1 level at once. If I scroll in and out my mouse too frequently then this code given strange outputs. Sometimes the marker size becomes too large or too small.
Question :
1) Is this the only way to make the markers resizable on different zoom levels?
2) If yes then what am I missing here or what changes should be made to make it work perfectly.?
Note : Tagging google maps also because it's more of a logical issue with map (either google or leaflet or mapbox) rather than api specific issue.

Looks like there are several previous posts that you guide you:
Mapbox,leaflet: Increase marker size on Zoom
is there a way to resize marker icons depending on zoom level in leaflet?
https://gis.stackexchange.com/questions/171609/resize-divicons-svgs-at-zoom-levels-leaflet
As for your bug, instead of reading the current icon size value at "zoomstart" event, you might better remember the previous zoom value and read it only at "zoomend" event. I am not sure the "zoomstart" event is fired only once when you scroll (to zoom in/out) successively, while the "zoomend" event may be fired only at the very end.

Related

Adding a scale to canvas image zoom

I'm using a some code from https://github.com/dimxasnewfrozen/Panning-Zooming-Canvas-Demos/blob/master/demo12/main.js (demo at http://dayobject.me/canvas/demo12/) to zoom in on an image using the Canvas element.
However, when zooming the jump between one zoom level and the next is too large, so I need to add a scale parameter.
How would I got about doing this?
In your main.js, you can change your zoomLevel here,
mouseWheel: function (e) {
e.preventDefault() // Please add this, coz the scroll event bubbles up to document.
var zoomLevel = 2;
...
if (delta > 0)
{
// ZOOMING IN
var zoomedX = canvasPos.deltaX - (canvasZoomX - canvasPos.deltaX);
var zoomedY = canvasPos.deltaY - (canvasZoomY - canvasPos.deltaY);
// scale the image up by 2
initialImageWidth = initialImageWidth * zoomLevel;
}
else
{
// ZOOMING OUT
var zoomedX = (canvasPos.deltaX + canvasZoomX);
var zoomedY = (canvasPos.deltaY + canvasZoomY);
// scale the image down by 2
initialImageWidth = initialImageWidth / zoomLevel;
}
}
Disclaimer: this ruins the zoomedX and zoomedY values. You gotta fix them :)
It seams to me as if the algorithm always takes half of the dimension befor the zoom. At the end of you code you see it in main.js the mouseWheel function:
initialImageWidth = initialImageWidth * 2;
the width is divided by 2 so just change the used value.
You said the step used to zoom in and out is too big.
So I suggest that you generate the new value by using the dimensions of the image you want to zoom. For example you take a percentage of the biggest dimension of the current image.
That's how you can implement a zoom function that zooms according to the dimensions of the image

How to trigger an event onMousewheel?

I am developing a WebGL application. For example, I have a sphere object that uses orbit controls for Zoom in/out.
Now I want to setup an event for the mousewheel. When zooming on my current WebGL block corresponding map location it can be zoomed in/out (used inline-block) for maps and WebGL. But the problem is that first of all my event is being triggered when I use the mousewheel. I also want to know whether my event logic is correct or not.
root.addEventListener('mousewheel', mousewheel, false);
function mousewheel(event) {
var mX = (event.wheeldetailX/width)* 2 - 1;
var mY = (event.wheeldetailY/height)* 2 + 1;
var WebGLZoom = new THREE.Vector3(mX, mY, 1);
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(WebGLZoom, camera);
WebGLZoom.sub(camera.position);
var mapzoom = map.getZoom();
if (WebGLZoom.z <= 5 && WebGLZoom.z > 2) {
map.setZoom(17);
} else if (WebGLZoom.z <= 2 && WebGLZoom.z > 0.0) {
map.setZoom(19);
} else {
map.setZoom(14);
}
}
You can use the wheel event like so.
document.addEventListener('wheel', function(event){
console.log(event.deltaY);
}, false);
This will result in a console log every time your mousewheel scrolls over the document. The deltaX and deltaY properties of the MouseWheel event are especially useful to figure out exactly how much the user scrolled and in which direction.
The event to use is wheel. You can find a working example here.

Replace tile picures in Google maps API getTile override

I'm doing an application, where you can click on a google maps tile, and replace it with another picture.
The current solution is that I added an overlay map, and overrode the getTile(), to create a custom div with an ID, and a click event listener, where I can select it with ID selector, and work with it.
The current solution is (summed up):
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
var div = ownerDocument.createElement('div');
div.id = 'block_' + coord.x + '_' + coord.y;
return div;
};
google.maps.event.addListener(map, 'click', function(event) {
var coord = ... the current tile coordinate
var block_to_select = $('#block_' + coord.x + '_' + coord.y);
do_magic(block_to_select);
}
It would be better to add the click event listener in the gettile() so I could get rid of the IDs, and a lot of computing code.
I tried:
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
var div = ownerDocument.createElement('div');
div.dataset.x = coord.x;
div.addEventListener('click',function(){
alert(1);
});
return div;
}
But it the onclick function won't run.
Is there any more efficient way to replace tile pictures?
Returning a jquery $("") also throws error in getTile().
The tiles will be rendered in the overlayLayer-mapPane .
According to the documentation this mapPane may not receive DOM-events, so I'm afraid there is no better way than detecting a particular tile via a calculation.

Gravity Points not working properly with other elements

There's this awesome codepen called Gravity Points which I liked very much and wanted to use on my next project but it turns out it only works well if it is the only element on the page. Once you start adding content above and below it, it miscalculates the mouse position.
Take a look at my fork here, I've added the content above it. Notice if the canvas is aligned perfectly with the screen, the gravity points are created in the right spot but if you click on the canvas when you're half way scrolled up, the points are created a few pixels down.
I'm not great with javascript and jquery, although I'm able to understand which functions it's calling and which functions are being used to draw the points but I can't understand where the calculations are happening and how it's related to scroll position. This functions seems to be triggered when left clicked but where does the cursor coordinates come from?
function mouseDown(e) {
for (var i = gravities.length - 1; i >= 0; i--) {
if (gravities[i].isMouseOver) {
gravities[i].startDrag(mouse);
return;
}
}
gravities.push(new GravityPoint(e.clientX, e.clientY, G_POINT_RADIUS, {
particles: particles,
gravities: gravities
}));
}
So can someone take a look at it and give some insights?
<canvas> element has its own coordinate system, which differs from the document one (the one sent by mouseEvents).
What you need to do is to check canvas's bounding box and remove its offset to your mouseEvents coordinates :
canvas.onmousemove = function(mouseEvent){
var rect = canvas.getBoundingClientRect();
var x = mouseEvent.clientX - rect.left;
var y = mouseEvent.clientY - rect.top;
// doSomething with x and y
for (var i = gravities.length - 1; i >= 0; i--) {
if (gravities[i].isMouseOver) {
gravities[i].startDrag(mouse);
return;
}
}
gravities.push(new GravityPoint(x, y, G_POINT_RADIUS, {
particles: particles,
gravities: gravities
}));
}

Google Maps API V3 Zoom level matching viewport size?

I'm currently working on a responsive website with a page-wide div-box containing a Google Map. As the display width (and height) varies, I'd need to set a different zoom level at width 320 as I do at 1200+. Resizing is not the issue nor is centering.
What I want to achieve is the zoom level to adjust as the viewport changes, either by setting different zoom levels corresponding to certain screen resolutions or something from min to max zoom.
I think this post on Stackoverflow pretty much is about the same problem, but without solution. Any ideas greatly appreciated!
You need the bounding box,i.e. corners of the window. Then you can use the mercator projection to compute the x and y ratio:Convert lat/lon to pixel coordinate?. Then you can multiply the ratio with the zoom levels and check min and max values.
Tricky problem indeed. It's best to set a timer in the resize event handler as that event can fire a lot.
var zoomLevelSizes = [
{triggerWidth: 10000, zoomLevel: 9 },
{triggerWidth: 720, zoomLevel: 8 },
{triggerWidth: 320, zoomLevel: 7 }
];
var resizeTimeout = -1;
function handleResizeEvent() {
resizeTimeout = -1;
var width = window.innerWidth;
for(var i = zoomLevelSizes.length - 1; i >= 0; i--) {
if(width < zoomLevelSizes[i].triggerWidth) {
if(map.getZoom() > zoomLevelSizes[i].zoomLevel) {
map.setZoom(zoomLevelSizes[i].zoomLevel);
console.log('changed to zoom level ' + zoomLevelSizes[i].zoomLevel);
break;
}
}
}
}
handleResizeEvent()
//Can't do anything resource intensive here as this can get triggered a lot
google.maps.event.addDomListener(window, 'resize', function() {
if(resizeTimeout !== -1) {
clearTimeout(resizeTimeout);
}
resizeTimeout = setTimeout(handleResizeEvent, 500);
});
JSFiddle example

Categories