Align non-geographical leaflet map maxBounds to the bottom of the container - javascript

I am creating a non-geographical map with leaflet, which shows a ski resort.
JSFiddle: https://jsfiddle.net/exophunk/ruzgeqL4/
I am using map.fitBounds(bounds) to fit the map to the container and map.setMaxBounds(bounds) to make sure you can't pan outside the map.
This works perfect when zooming in, but as long as the map is smaller than the viewport height, I would like to "align" the whole thing to the bottom of the container, so the map never moves away from the bottom of the container. As it is a mountain, it is pretty obvious.
I achieved this by adding an offset to the maxBounds, as you can see in this example (blue box = max bounds):
https://jsfiddle.net/exophunk/05cq3rzt/
The problem with this approach is, that you can now pan into the "empty sky" when zooming in, while I would actually like to keep the maxBounds as in the first example, so it also restricts movement upwards.
I think this would mean I would need to resize the max bounds while zooming in maybe? But there, I messed up coordinate systems and containers and wasn't able to do this properly.
How can I make sure the map always sticks to the container bottom while keeping the original max bounds, if possible?

You can overwrite the default wheel zoom and check if the zoom mousepoint is in the bounds, else zoom to the center of the bounds/map:
map.scrollWheelZoom._performZoomOrg = map.scrollWheelZoom._performZoom;
map.scrollWheelZoom._performZoom = function(e){
var mouse = map.scrollWheelZoom._lastMousePos;
var llpixel = map.containerPointToLatLng(mouse)
if(!bounds.contains(llpixel)){
map.scrollWheelZoom._lastMousePos = map.unproject([container.clientWidth/2, mapHeight]);
}
map.scrollWheelZoom._performZoomOrg();
}
https://jsfiddle.net/falkedesign/c04ngftj/

Related

Zoom in/out in image, keep position under cursor at same place

I have been struggling for a while with a Angular application that has one component with a map. To be able to rule out any other problems I have done a rewrite in pure javascript to test the functionality but I can't figure out how to solve this.
What I want to do is the same kind of functionality as in for example Google Maps, If you have the cursor over a specific city and zoom in with the mouse scroll then the map zooms in but keeps the city at the same place under the cursor.
I have this code and it's the function "zoomImage" that give me problems..
https://codepen.io/m-rten-sw-rd/pen/BMZvZX
Anyone that could guide me right on this?
function zoomImage(scale, mousePosInCointainer, mousePosInImage) {
var imgElement = document.getElementById("img");
imgElement.width = imgElement.width * scale;
imgElement.height = imgElement.height * scale;
/* TODO: Determine how I'm going to center the image over cursor */
}
I believe the following is what you need to be doing.
Determine transform origin (should be center) of the image.
Determine difference between mouse cursor and that point.
Scale that difference by your scale factor.
Translate the image by that difference.

Prevent duplicating of map and keep dragging within world

Is there a way to make leaflet not repeat the world map and make the map stay within the world bounds when dragging? and also disable zoom out when the size of the world reaches the size of the window
To stop the tiles from repeating, use the noWrap option of L.TileLayer
If set to true, the tiles just won't load outside the world width (-180 to 180 longitude) instead of repeating.
http://leafletjs.com/reference.html#tilelayer-nowrap
If you want to stop panning beyond defined bounds, use the maxBounds option of L.Map or call the setMaxBounds method:
Restricts the view to the given geographical bounds, bouncing the user back when he tries to pan outside the view.
http://leafletjs.com/reference.html#map-maxbounds
http://leafletjs.com/reference.html#map-setmaxbounds
If you want to disable zoom beyond a certain level use L.Map's minZoom and maxZoom options. What you want to do is set a minimum zoom level and use that as initial zoom. What factor depends on your map's elementsize and your tilelayer's tilesize. Most tileproviders use 256px². At zoom 0 the world is 1 tile, at zoom 1, 2x2 tiles, at 3 it's 4x4 etc. So if your map's elements is 512px² your minZoom would be 1.
http://leafletjs.com/reference.html#map-minzoom
Here's a demonstration on Plunker: http://embed.plnkr.co/rP5NLQ/preview
By Setting minimum zoom level :
map._layersMinZoom=1 (which sets the minimum zoom level to 1)
OR
map.options.minZoom = 1;
Read more here

Reduced bing map to lowest extent does not fit in the map area

When we reduce the map size to lowest possible size by scrolling down or clicking zoom(-) sign, a square is shown which does not exactly fit in the map area on my web page.
i implemented bing map over openlayer.
cant attach image due to repo constraint on stackoverflow.
as of now my implementation looks like current look but i want map should look like desired look
if you mean that your map is too small for the DIV area, but the DIV area itself is OK, you can tell your map what is the last zoom level you want to use by setting the map options at the map init:
map = new OpenLayers.Map("map",{ numZoomLevels: 5, minZoomLevel: 3, maxZoomLevel: 5 } );
plus/minus zoom makes only your zoom change, not the area of the map, the area stays the same within the page. so how do you want the area of the map to be affected by zooming?
the area of the map is dependent only upon the size of the DIV that the map is placed in.
this is the DIV in your first exapmle: <div id="map" class="smallmap"></div>. If you change the proportions of the DIV element, the area of the map is changed too.

Understanding rotation and calculating the top left point in KineticJS

I am working on a page where I can view images. I want to create a rotation tool. I've done that, but, it's not working consistently. When I set up the centre point to rotate by, the image jumps slightly, and it gets worse each time. I was experimenting, and, I have code to add a wedge to the top left corner of my top level group ( so, at 0,0 ). If I rotate the image by 45 degrees and drag it so that half of it is off the left edge of my canvas, then I call getAbsolutePosition on the wedge and on the group, I get these values:
layer.getAbsolutePosition()
Object {x: 104.66479545850302, y: 279.2748571151325}
wedge.getAbsolutePosition()
Object {x: 180.2684127179338, y: -73.48773356791764}
I think this means my y position is actually the bottom of the image, which is off screen.
What I want to do, is calculate the absolute position of the middle of my image, when the mouse moves over it, regardless of it's rotation. I have some code that works out points with rotation, which seems like it works at first, almost, but it just gets more and more broken the more I use the tool. I feel like there's something about how Kinetic is tracking these things and what it's reporting, that I am missing. Any hints would be most appreciated. Tutorials I can read are even better ( yes, I've read everything linked from the KineticJS site and searched the web ).
In a nutshell, the question is, if I have an image inside a group, and it's rotated, how do I work out the centre point of the image, taking the rotation in to account, and how do I set the offset so it will rotate from that point, and stay in the same place ?
Thanks
As you've discovered about KinetiJS:
rotation is easy
dragging is easy
dragging+rotation is difficult
After you drag your image you must reset its rotation point (offsetX/offsetY).
KineticJS makes dragging+rotation more difficult than it has to be.
Resetting the offset points of your image will cause KineticJS to automatically move your image (Noooo!!).
That's what's causing your jumping.
The solution to the "jumping" problem:
When you reset the image's rotation point (offsetX/OffsetY) you must also reset the image's X/Y position.
This code resets both XY and Offsets for an image after dragging:
A Demo: http://jsfiddle.net/m1erickson/m9Nw7/
// calc new position and offset
var pos=rect.getPosition();
var size=rect.getSize();
var offset=rect.getOffset();
var newX=pos.x-offset.x+size.width/2;
var newY=pos.y-offset.y+size.height/2;
// reset both position and offset
rect.setPosition([newX,newY]);
rect.setOffset(size.width/2,size.height/2);

Center Google Maps (V3) on browser print

I have a map set to 100% of the page width. The map has one marker and is centered on that marker. When I print the browser, I want the map to stay centered on the marker. This is the code I wrote to do so:
var lastPos = map.getCenter();
google.maps.event.addListener(map, "idle", function() {
lastPos = map.getCenter();
console.log(lastPos.toString());
});
google.maps.event.addDomListener(window, "resize", function() {
google.maps.event.trigger(map, "resize");
map.setCenter(lastPos);
console.log("Re-center on " + lastPos.toString());
});
This works when I re-size my browser, but does not work when the browser re-sizes itself before printing. If my browser is above a certain width then the marker is shifted entirely off the page (to the right) when the map is printed.
Here is my test case: http://www-sf.talispoint.com/testmapprint.html
You would need to add a #media print and give the map the size when printing and then you can do what is explained below.
When a map is printed what happens is that the top left corner is kept and the map is adjusted to fit the #media print size.
If you want the center to stay the same you need to manually change the center of the map.
http://jsbin.com/owiwox/33 is an example on how to work around this.
It uses a listener for the print media being applied event and adjusts the center of the map using a ratio on how the map is changed (made smaller)
One thing that you have to take care of is that you might have to make this browser targeted to make it work on all browsers (This solution works well in Chrome)
A good resource for making it work across browsers is:
http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
The js code from the sample above listens to print requests and shifts the map so that the top left corner has the same center as the big map.
To cut the whole story short, this is how it works
You need to put in the ratio of the map vs printed map (or get the size by checking it from JS)
You assign it to:
var widthRatio = 2;
var heightRatio = 3;
You listen for print media being applied and shift the center so that it does not change
After you finish print , you revert the change.
Still here you have the problem that a part of the map will be cut, but there is not a good solution here, since the zoom level -1 tiles might not be cached so when you zoom out to fit bounds you might get no tiles.
It seems the problem with your 'printing' or 'printer'.
I did a test:
load the test map and make the browser very wide
print preview and saw the problem you described
But: I can change the printing scale from 'Shrint to fit' (default for IE and FF) to say 30% and was able to print the map as seen on the screen.
Another thought is:
You may try to use another CSS for print to limit the map div width, but I am not sure if that will trigger the resize of the map first (you may refer to this post: Javascript Event Handler for Print)

Categories