1

maybe there is a solution for this:

I'm using the Gmap api to embed a map undernaeth an overlay that I have on top of my map. The overlay has a little arrow on the right side and I want my map marker to be positioned at this point (or a few pixels beside it)

I know it would be possible to use a GMaps Infowindow, but I have it this way.

So I'm able to use $("#arrow").offset() in order to get its position on the page, but I don't know how to move or pan the map center to this pixel-destination.

window.onload = function() {
    var myOptions = {
        center: new google.maps.LatLng(47.259998, 11.398032),
        zoom: 17,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableDefaultUI: true
    };

    var map = new google.maps.Map(document.getElementById("map"), myOptions);

    var marker = new google.maps.Marker({
        position: new google.maps.LatLng(47.260071, 11.404705),
        map: map,
    });

    console.log( $("#arrow").offset().top );
}

enter image description here


Update:

This is the code I have in my page-template right now. I have on last problem though. If my page has a width of lets say 1440px the position of the marker relative to my little arrow works just fine: https://goo.gl/u489nd However as soon as I resize the page to a smaller width and load the page again the marker is behind the overlay and not positioned relative to the little arrow. https://goo.gl/k4rPYv

google.maps.event.addDomListener(window, 'load', initMap);

window.onresize = function() {
    positionMap();
}

function initMap() {
    var myOptions = {
        center: new google.maps.LatLng(47.260071, 11.404705),
        zoom: 17,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableDefaultUI: true,
        draggable: false,
        mapTypeControl: false,
        zoomControl: false,
        scaleControl: false,
        scrollwheel: false
    };

    var map = new google.maps.Map(document.getElementById("map"), myOptions);

    var marker = new google.maps.Marker({
        position: new google.maps.LatLng(47.260071, 11.404705),
        map: map,
        title: 'Österreichisches Rotes Kreuz Innsbruck'
    });
}

function positionMap() {
    var arrowPos = $("#map-center").position();
    console.log(arrowPos);

    var getPixelOffset = function(map, marker) {
        // Calculate marker position in pixels form upper left corner
        var scale = Math.pow(2, map.getZoom());
        var nw = new google.maps.LatLng(
            map.getBounds().getNorthEast().lat(),
            map.getBounds().getSouthWest().lng()
        );
        var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
        var worldCoordinate = map.getProjection().fromLatLngToPoint(marker.getPosition());
        var pixelOffset = new google.maps.Point(
            Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
            Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
        );
        return pixelOffset;
    };

    // Wait until the map is initialized
    var listener = google.maps.event.addListener(map, "idle", function() { 
        var pixelOffset = getPixelOffset(map, marker);

        // Do the pan
        map.panBy( Math.abs( pixelOffset.x - ( arrowPos.left ) - 150 ),
                 Math.abs( pixelOffset.y - ( arrowPos.top ) ) - 50 );

        google.maps.event.removeListener(listener); 
    });
}
matt
  • 42,713
  • 103
  • 264
  • 397

1 Answers1

3

One approach is to use map.getProjection().fromLatLngToPoint() to find the pixel position of the marker inside the map, then subtract your $("#arrow").offset() from the marker position and call map.panBy() to move the marker by the calculated difference.

Here's the demo in which the marker is moved to the sample position { top: 50, left: 100 }:

var myOptions = {
        center: new google.maps.LatLng(47.259998, 11.398032),
        zoom: 17,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableDefaultUI: true
    };

var map = new google.maps.Map(document.getElementById("map"), myOptions);

var marker = new google.maps.Marker({
        position: new google.maps.LatLng(47.260071, 11.404705),
        map: map,
        title: 'Hello World!'
    });


// Replace this with call to $("#arrow").offset()
var arrowPos = { top: 50, left: 100 };

var getPixelOffset = function(map, marker) {
    // Calculate marker position in pixels form upper left corner
    var scale = Math.pow(2, map.getZoom());
    var nw = new google.maps.LatLng(
        map.getBounds().getNorthEast().lat(),
        map.getBounds().getSouthWest().lng()
    );
    var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
    var worldCoordinate = map.getProjection().fromLatLngToPoint(marker.getPosition());
    var pixelOffset = new google.maps.Point(
        Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
        Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
    );
    return pixelOffset;
};

// Wait until the map is initialized
var listener = google.maps.event.addListener(map, "idle", function() { 
    var pixelOffset = getPixelOffset(map, marker);
    
    // Do the pan
    map.panBy(Math.abs(pixelOffset.x - arrowPos.left),
             Math.abs(pixelOffset.y - arrowPos.top));
    
    google.maps.event.removeListener(listener); 
});
html,
body,
#map {
    display: block;
    width: 100%;
    height: 100%;
}

#map {
    background: #58B;
}
<script src="http://maps.google.com/maps/api/js?sensor=true&.js"></script>
<div id="map"></div>

Also, note that you have to do that when the map is fully loaded, i.e. in the idle event handler. Otherwise (that's what I experienced) the getProjection() method might be unavailable.

References:

Community
  • 1
  • 1
dekkard
  • 6,121
  • 1
  • 16
  • 26
  • Hey @dekkard … I have on last problem though. Your script works just fine if my page is at a regular width (like landscape macbook) the position of the marker fits perfectly … https://goo.gl/u489nd However as soon as I resize the page to a smaller width and load the page again the marker is behind the overlay and not positioned relative to the little arrow. https://goo.gl/k4rPYv I updated my question with the entire code I have, also I would be interested in positioning the marker on resize. – matt May 05 '15 at 06:15
  • I suppose your overlay has an absolute position and size so when the viewport is too small it covers the marker. But to make sure I'll need to see the code and styles of the overlay. Can you put up a JSFiddle with it? – dekkard May 05 '15 at 08:10
  • Yes, it has an absolute position. But the marker should always be relative to the little arrow of this absolute overlay and if there is a smaller viewport but still a map visible at the right hand-side the marker of the map should be fairly to the right and not underneath the overlay. Even if the screen is too small that the overlay covers the entire map the marker should theoretically be underneath the right side of this overlay cause there is the little arrow. However if I remove the overlay in the inspector the marker is not relative to this little arrow. – matt May 06 '15 at 07:39
  • I read this all again and recalled that your original question was about putting the marker on the position of ```$("#arrow")```, i.e. if you position your arrow correctly, the marker will be there. In you code I noticed you change the map position by some absolute values: ```map.panBy( Math.abs( pixelOffset.x - ( arrowPos.left ) - 150 ), Math.abs( pixelOffset.y - ( arrowPos.top ) ) - 50 );```. This might be the problem. – dekkard May 06 '15 at 09:08
  • No, this is not it. This is just to move it slightly besides this position. However is there also a way of applying this map-repositioning onResize() … so whenever I scale the window the map position is adapted? – matt May 06 '15 at 11:51
  • Hey dekkard, you can see that I'm already trying to do that in my code-sample in the question, but doesn't work. – matt May 06 '15 at 13:55