Skip to main content
WolfShade
Legend
August 6, 2019
Question

How does Google [maps] do it?

  • August 6, 2019
  • 6 replies
  • 1780 views

Hello, all,

On Google Maps, if you type in a location and hit enter you are directed to that location on the map.  If you zoom in and out, the URI will change; if you slide the map in any direction, the URI will change.  That way, you can copy the URI, paste it into another browser, and you get the same everything in the other browser (map or satellite; zoomed in status; etc.)

How does Google do that?  Just curious.

V/r,

^ _ ^

    This topic has been closed for replies.

    6 replies

    WolfShade
    WolfShadeAuthor
    Legend
    August 13, 2019

    Okay.. I've just finished putting together a small test case.  Sadly, this does not work in IE11 due to something about forward and backward cache being disabled.  I have not tested it in Chrome (it's not on our desktops), but it works in FireFox.

    Well, drat.. I was going to upload a zip file, but can't seem to be able to do that.  So, I'll just paste my code, here.  You'll have to use your own image (I used a .gif) and supply your own jQuery.  The layout of the zip file is:

    /img

       └-AdobeTrackerNOISSUES.gif  (This file is 1141px by 805px)

    /script

       └-jquery-3.2.1.min.js

    historyTest.html

    Here are the contents of historyTest.html:

    <!DOCTYPE HTML>

    <html>

        <head>

    <!--

    SITES USED FOR EXAMPLE CODE:

    http://usefulangle.com/post/1/jquery-dragging-image-within-div

    -->

            <meta charset="utf-8">

            <title>History Test</title>

            <style type="text/css">

                #image-container {

                    display: block;

                    height: 500px;

                    width: 700px;

                    margin: 40px auto;

                    overflow: hidden;

                    border: 1px solid #cccccc;

                    box-sizing: border-box;

                    position: relative;

                    cursor: move;

                    }

                #drag-image {

                    left: 0;

                    pointer-events: none;

                    position: relative;

                    top: 0;

                    -moz-user-select: none;

                    }

            </style>

        </head>

        <body>

            <div id="image-container">

                <img id="drag-image" src="img/AdobeTrackerNOISSUES.gif" />

            </div>

            <script src="script/jquery-3.2.1.min.js"></script>

            <script>

                var queryString = document.URL ? document.URL.split('?')[1] : window.location.search.slice(1),

                    tempName, tempVal, x = null, y = null, stateObj = {foo:"bar"};

                if(!!queryString){

                    var nameValueArray = queryString.split('&');

                    nameValueArray.map(function(v,i){

                        tempName = v.split('=')[0]; tempVal = v.split('=')[1];

                        window[tempName] = tempVal;

                        });

                    }

                if(!!window['t']){x=window['t'];}

                if(!!window['l']){y=window['l'];}

                var _DRAGGGING_STARTED = 0;

                var _LAST_MOUSEMOVE_POSITION = { x: null, y: null };

                var _DIV_OFFSET = $('#image-container').offset();

                var _CONTAINER_WIDTH = $("#image-container").outerWidth();

                var _CONTAINER_HEIGHT = $("#image-container").outerHeight();

                var _IMAGE_WIDTH;

                var _IMAGE_HEIGHT;

                var _IMAGE_LOADED = 0;

                    $('#drag-image').on('load', function() {

                        ImageLoaded();

                        });

                // Image is loaded

                function ImageLoaded() {

                    _IMAGE_WIDTH = $("#drag-image").width();

                    _IMAGE_HEIGHT = $("#drag-image").height();

                    _IMAGE_LOADED = 1;

                    if((x != null) && (y != null)){

                        $("#drag-image").css({top:x + "px", left: y + "px"});

                        }

                    }

                $('#image-container').on('mousedown', function(event) {

                    /* Image should be loaded before it can be dragged */

                    if(_IMAGE_LOADED === 1) {

                        _DRAGGGING_STARTED = 1;

                        /* Save mouse position */

                        _LAST_MOUSE_POSITION = { x: event.pageX - _DIV_OFFSET.left, y: event.pageY - _DIV_OFFSET.top };

                        }

                    });

                $('#image-container').on('mouseup', function() {

                    _DRAGGGING_STARTED = 0;

                    });

                $('#image-container').on('mousemove', function(event) {

                    if(_DRAGGGING_STARTED == 1) {

                        var current_mouse_position = { x: event.pageX - _DIV_OFFSET.left, y: event.pageY - _DIV_OFFSET.top };

                        var change_x = current_mouse_position.x - _LAST_MOUSE_POSITION.x;

                        var change_y = current_mouse_position.y - _LAST_MOUSE_POSITION.y;

                        /* Save mouse position */

                        _LAST_MOUSE_POSITION = current_mouse_position;

                        var img_top = parseInt($("#drag-image").css('top'), 10);

                        var img_left = parseInt($("#drag-image").css('left'), 10);

                        var img_top_new = img_top + change_y;

                        var img_left_new = img_left + change_x;

                        /* Validate top and left do not fall outside the image, otherwise white space will be seen */

                        if(img_top_new > 0)

                            img_top_new = 0;

                        if(img_top_new < (_CONTAINER_HEIGHT - _IMAGE_HEIGHT))

                            img_top_new = _CONTAINER_HEIGHT - _IMAGE_HEIGHT;

                        if(img_left_new > 0)

                            img_left_new = 0;

                        if(img_left_new < (_CONTAINER_WIDTH - _IMAGE_WIDTH))

                            img_left_new = _CONTAINER_WIDTH - _IMAGE_WIDTH;

                        $("#drag-image").css({ top: img_top_new + 'px', left: img_left_new + 'px' });

                        window.history.replaceState(stateObj,"newPos","historyTest.html?t=" + img_top_new + "&l=" +img_left_new)

                        }

                    });

            </script>

        </body>

    </html>

    When the page first loads, the image (which is larger than the containing div) is top 0 and left 0.  You can drag the image around, which will use window.history.replaceState() to real-time update the URI field of the browser with the new top and left positions.  You can drag the image to a spot, copy the URI, open a new tab, and paste the URI in the new tab and when the page loads, the image will be 'dragged' to the same spot.

    Okay.. new tab doesn't work because FF is caching the content and just gives you the original loading page.  You can use CTRL-F5, though.  Or close the browser, open it, and try that.  Or try it in Chrome and let me know if it is working in Chrome. 

    Now, I'm _NOT_ saying this is how Google did it.  But this is how _I_ would do it.. er, did do it. 

    V/r,

    ^ _ ^

    UPDATE:  I should have provided the image, as well. 

    B i r n o u
    Legend
    August 7, 2019

    matthijsm57424665  a écrit

    This can be accomplished with window.history.pushState(). This is client-site (Javascript/HTML5) functionality and has nothing to do with server-side technology.

    well if you carrefully read the OP's question,

    WolfShade  a écrit

    ... you can copy the URI, paste it into another browser, and you get the same everything in the other browser

    How does Google do that?  Just curious.

    it has nothing to do with the first browser navigation history...

    matthijsm57424665
    Participant
    August 7, 2019

    It actually has very much do to with this: window.history.pushState() changes the URL in the browser bar, so that users can copy the URL without actually requiring a reload of the page.

    B i r n o u
    Legend
    August 7, 2019

    matthijsm57424665  a écrit

    It actually has very much do to with this: window.history.pushState() changes the URL in the browser bar, so that users can copy the URL without actually requiring a reload of the page.

    sorry... I didn't knew that window.history.pushState() was working in between two different browsers.

    So could you please just send me a Javascript snippet to handle it... and makes communicate the two browsers together ?

    I'm very interested.

    matthijsm57424665
    Participant
    August 7, 2019

    This can be accomplished with window.history.pushState(). This is client-site (Javascript/HTML5) functionality and has nothing to do with server-side technology.

    WolfShade
    WolfShadeAuthor
    Legend
    August 7, 2019

    Thank you for the tip, Matt.  I've never worked with history, but I'm for sure going to look into pushState().

    V/r,

    ^ _ ^

    mbk28
    Known Participant
    August 6, 2019

    Hi,

    for me, Google, is banned from all my computer and devices

    B i r n o u
    Legend
    August 6, 2019

    to better understand how maps are working...

    you have on one side the map, by itself... you have different choice, like ... google map, here, openstreetmap , carto, bing, ign... and so on... some are free, some are proprietary, some are almost free (but eat all your datas and those of your visitors... ) ...

    then you have an API... here too, you can use what ever API that you prefer... you can acess multiple choice as Google map (again), tom tom, open layers, leaflet, and so on... (same politics than for the maps)

    once you choice your tools... map and API... you will have three majors action

    - the map position (latlng)

    - the zoom level

    - the layer(s)... the layer can be multiple, it (or they) contain(s)... the map, but also all the objects that can illustrate the map, the most famous are the markers, but you can also have, polygon, area (weather), svg, and so on...

    all those informations can be send and asked as URL param (if the API doesn't handle it directly, you will always find a plugin that will)...

    now most of the code is done on client side... so it is JavaScript...

    the server side is the map... and it just serve what you ask for...

    but... there is a but... some server allows you to create a geojson object https://geojson.org/ from the server side...

    leaftlet, help you to create it from the client side (at least format it, to add your own properties on the object)

    B i r n o u
    Legend
    August 6, 2019

    it works the same way that every PHP page that use URL variables adapt them selves to the context.

    in the URL you will find all the parameters displaying the map, zoom, latlng, surfaces, and so on... (some times you can have it on human readable form, some on hex encode format (to avoid any URL artefact)

    Personnaly I don't use Google map and its internal API, I use OpenStreet Map (https://www.openstreetmap.fr/ ) and Leaftlet JS as API to pilot the map (https://leafletjs.com/ )... and it works exactly the same way (in a free open mind... )

    WolfShade
    WolfShadeAuthor
    Legend
    August 6, 2019

    Thanks for the information, Birnou.  So is this a strictly PHP thing, then?  No other server-side language can accomplish this?

    Which is weird seeing the separation between client and server.  But I guess that's getting smaller, what with things like JavaScript being able to get file meta data before upload, and the like.


    V/r,

    ^ _ ^

    pziecina
    Legend
    August 6, 2019

    You can do it with most server side languages.

    MS do it with C# in their earth view plug-in for .net. NASA have a similar 'space view' that uses gif images with .net.

    I have even looked at a js api for doing it, that required no server side, (cannot remember if that one transfered to another browser though).