How to center a google map marker with a smooth zoom (api V3)? - google-maps-api-3

i'm using map.panTo() to have a nice smooth transition between the markers, when i click from a list of locations, but i can't see a similar methods for the zoom...I imagine something like setZoom(13, 1500) where 1500 is the duration...
any clue?

The only native function to zoom so far is map.setZoom which does not let you change the speed.
If you want to set your map to the zoom level based on a set of markers you can do something like this:
var bounds : LatLngBounds = new LatLngBounds(southwestmarker.getLatLng(), northeastmarker.getLatLng());
bounds.extend(someMarker.getLatLng());
//some more extend() here
map.setZoom(map.getBoundsZoomLevel(bounds));

I've found that the map.setZoom will smooth the transition if the zoom level is within 2 of the current zoom level.
So if the map is set to zoom of 10, and I set it to 12 it will transition. However if I set it to 13 it wouldn't.
Also you can set zoom to a non whole number but the map tiles will not load and state 'Sorry, we have no imagery here'.
You could try chaining zooms but I they ease in/out so it would look jerky.
If the transition is more than 2 and it's important to be smooth, you could manually edit the matrix transform on one of the map DOM elements. It looks like -webkit-transform: matrix(1, 0, 0, 1, -62, 71);. Changing the 1st and 4th numbers would affect the scale, the first is x-scale and 4th is y-scale.
The matrix is like so transform: matrix(xs, 0, 0, ys, xt, yt);, where xs and ys are the scale, setting it to 2 would zoom in 200%. This matrix does take fractional values, so you can zoom to 1.1 etc. You could then map.setZoom() to your final number at the end of the transition.
This does have some caveats as it's not the intended usage:
Panning or zooming while transitioning would break the matrix transformation by resetting it to Google's own methods.
Zooming out is harder because the surrounding tiles (beyond the viewport) aren't loaded - defaulting to a grey square. You could have a duplicate map with a viewport the size of your current map multiplied by the factor you're zooming out - so if you were zooming out so your map was half the size, then the viewport would be double. You could then place the viewport over the top and set the zoom on the 'real' map, transition the adjusted viewport map and hide it on completion.

Related

Geoviews map WMTS starting 'box'

Is there a way in Geoviews to always display only a small box / portion of the map rather than the whole world zoomed out? It seems to always begin such that the entire world is displayed. I was wondering if there is any option to choose the min/max latitude and min/max longitude?
If you display a WMTS element on its own it will default to a global view. You can however override that by setting the extents on the element, e.g.:
gv.WMTS(some_url, extents=(-70, 20, -50, 30))
The extents are defined a 4-tuple of the (left, bottom, right, top) edges. However if you overlay some actual data on top of a tile source it should automatically set the extents to the range of your data.

jQuery Flot - Force same tick interval on X and Y when zooming in/ out

I have a grid in jQuery Flot. On this grid, there are a lot of separate points scattered across, each with an X and a Y position.
Additionally, the grid utilizes flot.navigation to allow zooming in and out. Now this is where my problem occurs... This is undoubtedly rectangles, where as the first image, and most zoom levels, are square..
To force squares on the initial load, I normalize the data x/y values. When I zoom in/ out, the grid is still square, for a while. If I zoom in and out sporadically, the grid becomes rectangles.
Removing the scroll-zoom, and adding zoom in/ zoom out buttons did not fix the issue. While testing this, I realized that if I pan up a little bit, so that 0,0 is not visible, that's when the zoom and ratio starts to act up.
Applying the fix suggested in this answer didn't change the behavior at all.

2D Zoom: Adjusting Distances Between Sprites

I'm trying to implement 2d zoom for a basic game. I have the images scaling. I also have a basic zoom that fails on occasion. Like...it pretty much looks legit until you start testing heavily. Sometimes when I zoom in, and move two objects close to each other, and I zoom back out, the objects now overlap, although the zoomed in version suggests otherwise.
zoom_level starts at 1.
zoomIn():
zoom_level *=1.2;
for sprite in sprites:
//make sprites 1.2 times their current size
sprite.x *= (zoom_level * zoom_level);
sprite.y *= (zoom_level * zoom_level);
It's really hard to give a proper answer, since no engine/platform/language is given.
Explained in a general way:
You will want to scale the x/y coordinates of your sprites by the same factor as you want to scale their dimensions. And the corner closest to your "zoom-point" should be the anchor point for your scaling. [Meaning if you zoom in to the x/y-coordinates of your sprite it will be enough to scale the width/height. But if you want to zoom in to the center of a sprite, the x/y-coordinates will also change since they will be pushed towards the edge of the screen.]
But most of the time you shouldn't handle zooming/transforming by changing the sprites' actual world-positions/dimensions. Most engines use a "Camera" or "Viewport" to project the world-coordinates of object to screen-coordinates. Meaning they scale/transform all images at render-time, leaving the world-coordinates untouched. You should use whatever is the equivalent of that in your engine.
As an example, given a square at (1,1) with dimensions of 1x1, if we zoom in by a factor of 2 (effectively doubling everything) using the coordinate origin as the anchor, we end up with a square rendered at (2,2) and dimensions of 2x2 in screen space.
Specific to your given code snippet:
Why to you square your zoom level in this line?
sprite.x *= (zoom_level * zoom_level);
seems to be wrong, are you sure a simple
sprite.x *= zoom_level;
isn't enough?
And as far as I can tell, this will only scale the position of the sprites but not their dimension, you should probably scale their width/height too.
OTOH, if your engine already handles camera/viewport scaling, you probably don't want to change the x/y-coordinates of your sprites at all or else you might be double transforming them.
Anyway, I'd recommend reading documentation/tutorials specific to your engine.

Trying to zoom image based on mouse origin, yet my math is slightly off

I'm working on a full screen image viewer, I'll temporarily open a dev URL here:
http://www.jungledragon.org/apps/jd3/image/704/great_grey_owl.html/zoom
This viewer is responsive and scales to your browser width/height. One of its key features is being able to zoom in and out of the image using your mouse wheel. Rather than a center-based zoom, the idea is to zoom based on origin, meaning the coordinates of your mouse, allowing you to zoom into specific areas of the image.
How to reproduce the issue
If you open the above URL and have a quick play with your mouse wheel, it may appear to be working correctly. However, the math I am using is slightly off. Here is how you can reproduce the issue:
Open the above URL
Hover your mouse over the left eye of the Owl
Zoom one step using your mouse wheel, it should zoom exactly into the eye
Position your mouse on the owl's beak
Zoom one more step using your mouse wheel
You should now notice that the second zoom step did not go into the Owl's beak exactly, it seems to be slightly off, both horizontally and vertically. I'm thinking this is a result of bad math.
How it works
Here is the javascript that handles it all:
http://www.jungledragon.org/apps/jd3/js/jd3-slideshow.js
I am capturing the mousewheel event. Based upon its direction, I am increasing or decreasing the zoom level. The actual zooming is nothing more than applying a CSS class that scales the image using a CSS3 transform:
&.grow1 { #include jd-scale(1); }
&.grow2 { #include jd-scale(1.5); }
&.grow3 { #include jd-scale(2.0); }
&.grow4 { #include jd-scale(2.5); }
&.grow5 { #include jd-scale(3.0); }
Note: the above is a call to a SASS mixin that translates into the right vendor prefixes for transform:scale.
The above accomplishes the basic zooming without issues. To make origin-based zooming possible, however, a few more steps are needed. Upon doing the actual zooming, I first set the origin of the zoom in javascript, using transform-origin. Here is my helper function for setting it:
function zoomOrigin(selector, originStr) {
selector.css({'-webkit-transform-origin': originStr});
selector.css({'-moz-transform-origin': originStr});
selector.css({'-ms-transform-origin': originStr});
selector.css({'-o-transform-origin': originStr});
selector.css({'transform-origin': originStr});
}
The heart of this question is about calculating the correct origin. There are two things worthy to mention in calculating this value:
The absolute coordinates (meaning the X and Y) are relative to the image, not relative to the page
The calculation of the origin should take into account that the image has grown/shrunk based on the current zoom state
The origin calculation happens in realtime, based on the mousemove event. Here is the method that does so, with irrelevant parts removed:
$("#image-container img").mousemove(function(e) {
// user has moved their mouse. in case of zooming or panning, this means that the
// origin (center point) of those interactions need to be recalculated
// calculate the mouse offset within the zoomable object (which is different than the page-level offset)
// this relies on the parent of the element having position:relative set
var parentOffset = $(this).offset();
zoomOriginX = e.pageX - parentOffset.left;
zoomOriginY = e.pageY - parentOffset.top;
// recalculate the width and height of the image given the current zoom level
width = $(this).outerWidth() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerWidth());
height = $(this).outerHeight() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerHeight());
// calculate origin percentages based on zoomed width and height
// the zoom methods rely on these variables to be set
zoomOriginPercX = (zoomOriginX / width * 100);
zoomOriginPercY = (zoomOriginY / height * 100);
});
The main purpose of this method is to correctly set the global variables zoomOriginPercX and zoomOriginPercY, which are used to set the origin (percentage) prior to zooming.
From a math perspective, my idea was to simply calculate the zoomed width of the image, and to use the offset X and Y to come to a reliable origin percentage. As the problem statement shows, I am quite close to a correct calculation, yet something is off.
Although the zooming currently works well, I want it to be perfect. It would make for quite a powerful image viewer that is really easy to implement, also for others.
Desired Effect
To start answering your question I think it's worth first clarifying the desired effect. Essentially you're looking for the same effect you'd get if you pinched to zoom on an iPhone - the 'origin' of the pinch stays exactly the same, and everything around it stretches. You can imagine pinning some stretchy fabric at the origin, and pulling the corners.
Problem
This is working fine for you if you don't move the mouse between zooms, but if you do, the origin appears to move. The cause of the problem is exactly that - you are changing the origin of the transform every time you move the mouse. Of course you do need to do this, but you are calculating the origin based on the original (100% zoomed) position of the image. The actual origin needs to be somewhere between the origin of the first zoom and the new mouse position.
In other words, CSS is just doing one transform. If you set the origin to x,y then zoom to zoom level 2, this will give the same result as if you set the origin to x2,y2, zoom to level 1, then move to x,y, and go to level 2.
Solutions
I presume you could solve the issue in several ways:
Calculate a scaling factor for the 'new' origin on each zoom
this is likely a function of zoom level, mouse position and previous origin
Calculate and apply a translation each time the origin is moved
again will depend on the current origin, zoom level and mouse position
Find another way to 'stack' transforms on top of one another.
One way to do this may be to dynamically generate a new containing div each time you and apply a scale transform to that similar to the accepted solution in this question.
Unfortunately I don't have the time to go further than this, but hopefully it points you in the right direction?

Google Maps fitBounds doesn't take more than 10 positions if the width and height of the map are set

I have a map that is taller than wide. I noticed that in some instances, the fitBounds method was failing to adjust the zoom and center correctly in order to display all of the markers.
I've managed to isolate the issue in this example:
http://jsbin.com/welcome/2568
In the example I first try to load 23 positions and you will notice its zoomed quite far in. What I'm doing is:
//extending 23 positions doesn't really work
bounds = new google.maps.LatLngBounds ();
for (var i = 0; i < markerList.length; i++) {
pos = new google.maps.LatLng (markerList[i]["Za"],markerList[i]["$a"])
bounds.extend(pos);
}
window.map.fitBounds(bounds);
After 5 seconds I run that basic script again, but this time instead of extending 23, I only extend the bounds 5 times. This time the map actually zooms out!
What I noticed is that to get this issue to reproduce, I have to set the width and height of the canvas div:
<div id="map_canvas" style="width:450px;height:600px;"></div>
So I guess my question is: How can I both set the map canvas size and successfully fitBounds() for 25+ positions?
I just figured what was happening is that I was setting the minZoom in the map configuration.
It seems that if the minZoom is lower than the one needed by fitBounds() to display all the positions, it silently fails.
The reason the width of the map influenced is that the thinner the map, the more it had to zoom out to display the whole set of positions, and when it met the constraint of minZoom, it would die.
The reason the subset of 5 positions would work I think is just because it wasn't reaching the minZoom.
To solve the issue I removed the minZoom setting.

Resources