views:

379

answers:

2

look at this url

there is the "floating image", the one with arrow that when clicked centers the map on a certain location. I have been desperately trying to find out the way to do that, and I have coded my google maps app with just that one thing missing. any ideas?

EDIT: try navigating away from the center of the map (which would be the red marker). there will appear a red marker with an arrow that trails you if the center is not visible in the map. that is what I am looking for :)

A: 

It's listed under Map Basics, "Info Windows"

http://code.google.com/apis/maps/documentation/introduction.html#Info_Windows

Steve-o
A: 

This is the code to create a 'tracker' marker. The logic resides completely in the Pointer object.

You simple instantiate a new Pointer and pass the marker and map. The Pointer automatically shows and hides, no work necessary on your part.

I see no licensing info but if I am not mistaken, this is based on a gmap sample I have seen in the past. What you do with it is up to you.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
    <title>Marker Tracker Code</title>

    <script src="http://maps.google.com/maps?file=api&amp;amp;v=3"
        type="text/javascript"></script>

    <style type="text/css">
        .map
        {
            height: 450px;
            width: 500px;
        }
    </style>

    <script type="text/javascript">

        var map;

        function load() {
            if (GBrowserIsCompatible()) {

                var latlng = new GLatLng(37.4419, -122.1419);

                map = new GMap2(document.getElementById("map"));
                map.setCenter(latlng, 13);


                // create a marker
                var marker = new GMarker(latlng);
                map.addOverlay(marker);

                // create a tracker for marker
                var tracker = new Pointer(marker, map);
            }
        }


        /*
        Pointer creates an intelligent 'minimarker' that shows with a compass arrow pointing to 
        the marker passed in to the constructor when the parent marker is off screen
        */

        // Creates a Pointer for the given marker and displays it on the map as needed.     
        function Pointer(marker, map) {
            this.map_ = map;
            this.marker_ = marker;
            this.enabled_ = true;
            this.arrowDisplayed_ = false;
            this.arrow_ = null;
            this.oldArrow_ = null;
            this.control_ = null;

            this.iconScale_ = 0.6;
            this.padding_ = 65;
            this.color_ = '#0000ff';
            this.weight_ = 10;
            this.length_ = 10
            this.opacity_ = 0.6
            this.updateEvent_ = 'move';
            this.panEvent_ = 'click';
            this.quickPanEnabled_ = true;

            //replicate a different sized icon 
            var babyIcon = new GIcon(marker.getIcon());
            babyIcon.iconSize = new GSize(
            marker.getIcon().iconSize.width * this.iconScale_,
            marker.getIcon().iconSize.height * this.iconScale_);
            babyIcon.iconAnchor = new GPoint(
            marker.getIcon().iconAnchor.x * this.iconScale_,
            marker.getIcon().iconAnchor.y * this.iconScale_ / 2);
            // kill the shadow
            babyIcon.shadow = null;
            this.babyMarker_ = new GMarker(new GPoint(0, 0), babyIcon);

            //bind the update task to the event trigger
            GEvent.bind(this.map_, this.updateEvent_, this, this.updateArrow_);
            //update the arrow if the marker moves
            GEvent.bind(this.marker_, 'changed', this, this.updateArrow_);
            if (this.quickPanEnabled_) {
                GEvent.bind(this.babyMarker_, this.panEvent_, this, this.panToMarker_);
            }

            //do an inital check
            this.updateArrow_();
        };

        // Disables the pointer.
        Pointer.prototype.disable = function() {
            this.enabled_ = false;
            this.updateArrow_();
        };

        //Enables the pointer.
        Pointer.prototype.enable = function() {
            this.enabled_ = true;
            this.updateArrow_();
        };

        // Called on on the trigger event to update the arrow. Primary function is to
        // check if the parent marker is in view, if not draw the tracking arrow.
        Pointer.prototype.updateArrow_ = function() {
            if (!this.map_.getBounds().containsLatLng(this.marker_.getLatLng()) && this.enabled_) {
                this.drawArrow_();
            } else if (this.arrowDisplayed_) {
                this.hideArrow_();
            }
        };

        //Draws or redraws the arrow as needed, called when the parent marker is
        //not with in the map view.
        Pointer.prototype.drawArrow_ = function() {
            //convert to pixels
            var bounds = this.map_.getBounds();
            var SE = this.map_.fromLatLngToDivPixel(bounds.getSouthWest());
            var NE = this.map_.fromLatLngToDivPixel(bounds.getNorthEast());
            //include the padding while deciding on the arrow location
            var minX = SE.x + this.padding_;
            var minY = NE.y + this.padding_;
            var maxX = NE.x - this.padding_;
            var maxY = SE.y - this.padding_;

            // find the geometric info for the marker realative to the center of the map
            var center = this.map_.fromLatLngToDivPixel(this.map_.getCenter());
            var loc = this.map_.fromLatLngToDivPixel(this.marker_.getLatLng());

            //get the slope of the line
            var m = (center.y - loc.y) / (center.x - loc.x);
            var b = (center.y - m * center.x);

            // end the line within the bounds
            if (loc.x < maxX && loc.x > minX) {
                var x = loc.x;
            } else if (center.x > loc.x) {
                var x = minX;
            } else {
                var x = maxX;
            }

            //calculate y and check boundaries again  
            var y = m * x + b;
            if (y > maxY) {
                y = maxY;
                x = (y - b) / m;
            } else if (y < minY) {
                y = minY;
                x = (y - b) / m;
            }

            // get the proper angle of the arrow
            var ang = Math.atan(-m);
            if (x > center.x) {
                ang = ang + Math.PI;
            }

            // define the point of the arrow
            var arrowLoc = this.map_.fromDivPixelToLatLng(new GPoint(x, y));

            // left side of marker is at -1,1
            var arrowLeft = this.map_.fromDivPixelToLatLng(
            this.getRotatedPoint_(((-1) * this.length_), this.length_, ang, x, y));

            // right side of marker is at -1,-1
            var arrowRight = this.map_.fromDivPixelToLatLng(
            this.getRotatedPoint_(((-1) * this.length_), ((-1) * this.length_), ang, x, y));


            var center = this.map_.getCenter();
            var loc = this.marker_.getLatLng();

            this.oldArrow_ = this.arrow_;
            this.arrow_ = new GPolyline([arrowLeft, arrowLoc, arrowRight],
        this.color_, this.weight_, this.opacity_);
            this.map_.addOverlay(this.arrow_);

            // move the babyMarker to -1,0
            this.babyMarker_.setLatLng(this.map_.fromDivPixelToLatLng(
            this.getRotatedPoint_(((-2) * this.length_), 0, ang, x, y)));

            if (!this.arrowDisplayed_) {
                this.map_.addOverlay(this.babyMarker_);
                this.arrowDisplayed_ = true;
            }
            if (this.oldArrow_) {
                this.map_.removeOverlay(this.oldArrow_);
            }
        };

        //Hides the arrows.
        Pointer.prototype.hideArrow_ = function() {
            this.map_.removeOverlay(this.babyMarker_);
            if (this.arrow_) {
                this.map_.removeOverlay(this.arrow_);
            }
            if (this.oldArrow_) {
                this.map_.removeOverlay(this.oldArrow_);
            }
            this.arrowDisplayed_ = false;
        };

        //Pans the map to the parent marker.
        Pointer.prototype.panToMarker_ = function() {
            this.map_.panTo(this.marker_.getLatLng());
        };

        //This applies a counter-clockwise rotation to any point.
        Pointer.prototype.getRotatedPoint_ = function(x, y, ang, xoffset, yoffset) {
            var newx = y * Math.sin(ang) - x * Math.cos(ang) + xoffset;
            var newy = x * Math.sin(ang) + y * Math.cos(ang) + yoffset;
            var rotatedPoint = new GPoint(newx, newy);
            return (rotatedPoint);
        };        

    </script>

</head>
<body onload="load()" onunload="GUnload()">
    <div>
        <div id="map" class="map">
        </div>
    </div>
</body>
</html>
Sky Sanders
quite long for a simple functionality, but I'm gonna work on it. Is this in V3? I can't really tell V3 from V2
Ygam
@Ygam - yes this is V3, notice the API url. But I suspect it would also work for V2. In any case, the functionality is not quite simple. Break it down and you will see that the code is actually quite concise for the tasks performed. Just copy the code into an emtpy html file and view it in your favorite browser.
Sky Sanders
Ygam
@YGAM They are all pointing to the same thing. For backwards compatibility the old root level object identifiers (e.g. Gmap2()) are still available in V3, but using google.maps.Map() is a better way to go towards the future. R.E. the url, you will find that there are quite a few URIs and formats that resolve to particular resources. Use what you are comfortable with. As far as this sample goes, you should be able to freely substitute the url and identifiers of your choice with no difficulties.
Sky Sanders
great! because I really was confused when I tried to search for a Pointer object in the V3 API Reference and found none. TIme to start working on it then.
Ygam
@YGAM - Pointer is a custom object - we are defining it in the code above. It is not part of google maps.
Sky Sanders
had the code up in my testing environment but it was asking for an API key whenever I am not in a localhost address. any ideas on why is that? Because v3 need not an API key
Ygam
@YGAM - well, go ahead and use the api script tag you usually use and see what happens
Sky Sanders
does not work too. I just signed up for a key and decided that is what I will use :)
Ygam