How to save a Google maps overlay shape in the database?
Asked Answered
V

4

17

I want to save a Google maps overlay shape in the database. This is my code. It works perfectly but I just need to save all_shapes array in the database.

<html>
<head>

<style type="text/css">
  #map, html, body
  {
      padding: 0;
      margin: 0;
      height: 100%;
  }
</style>

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true&libraries=drawing,geometry"></script>

<script>
var coordinates = [];
var all_shapes = [];

var selectedShape;
</script>

<script>
function draw_shape()
{
    for(var i = 0; i < all_shapes.length; i++)
    {
        all_shapes[i].setMap(null);
    }

    for(var i = 0; i < all_shapes.length; i++)
    {
        all_shapes[i].setMap(map);
    }
}
</script>

<script>
function clearSelection()
{
    if(selectedShape)
    {
        selectedShape.setEditable(false);
        selectedShape = null;
    }
}

function setSelection(shape)
{
    clearSelection();
    selectedShape = shape;
    shape.setEditable(true);
}

function deleteSelectedShape()
{
    if (selectedShape)
    {
        selectedShape.setMap(null);
    }
}
</script>

<script>
function save_coordinates_to_array(newShapeArg)
{
    if(newShapeArg.type == google.maps.drawing.OverlayType.POLYGON)
    {
        var polygonBounds = newShapeArg.getPath();

        for(var i = 0 ; i < polygonBounds.length ; i++)
        {
            coordinates.push(polygonBounds.getAt(i).lat(), polygonBounds.getAt(i).lng());
        }
    }
    else
    {
        //alert("Not polygon");/////////////
    }   
}
</script>

<script>
var map;

function initialize()
{
    map = new google.maps.Map(document.getElementById('map'), {zoom: 12, center: new google.maps.LatLng(32.344, 51.048)});

    var drawingManager = new google.maps.drawing.DrawingManager();
    drawingManager.setMap(map);

    google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
        var newShape = e.overlay;
        newShape.type = e.type;

        all_shapes.push(newShape);

        setSelection(newShape);

        save_coordinates_to_array(newShape);

        google.maps.event.addListener(newShape, 'click', function() {setSelection(newShape)});
      });

    google.maps.event.addListener(map, 'click', function(e) {clearSelection();});
}

google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>

<body>
<table border="1">
  <tr>
    <td>Name</td>
    <td><input name="name" id="name" type="text"></td>
  </tr>
  <tr>
    <td>Color</td>
    <td>
      <table border="1" width="100%">
        <tr>
          <td bgcolor="#FF0000">&nbsp;</td>
          <td bgcolor="#00FF00">&nbsp;</td>
          <td bgcolor="#0000FF">&nbsp;</td>
        </tr>
      </table>
    </td>
  </tr>
  <tr>
    <td colspan="2"><input name="save" type="button" value="Save" onClick="draw_shape()"></td>
  </tr>
  <tr>
    <td colspan="2"><input name="delete" type="button" value="Delete" onClick="deleteSelectedShape()"></td>
  </tr>  
</table>

<div id="map"></div>
</body>

</html>

Where and how can I save the created overlay shapes in the database. All shapes are saved in the var all_shapes = []; array. What kind of type I have to choose for the field in database? I mean for example int, char, etc. I'm going to use MySQL and PHP.

Vincents answered 27/10, 2013 at 5:3 Comment(2)
possible duplicate of How to save array contains objects (Google map overlays) in database?Mallis
i had a same problem save polygon from google maps to postgresql this is what i did https://mcmap.net/q/743361/-save-google-map-polygon-to-postgresql-databaseChloromycetin
S
37

When you simply want to store the shapes somehow, you may use a JSON-string, store it in e.g. a Text-column(char would be to small to store detailed polygons/polylines )

Note: when you create the JSON-string, you must convert the properties(e.g. to native arrays or objects), you cannot store for example LatLng's directly, because the prototype will be lost when saving it. Pathes of polylines/polygons may be stored encoded

Another approach: use multiple columns, e.g.

  1. a column(varchar) where you store the type(LatLng, Circle,Polyline,etc.)
  2. a column(geometry) where you store the geometric features(LatLng,Polygon or Polyline)
  3. a column(int) where you store a radius(used when you insert a circle)
  4. optionally column(text) where you store the style-options(when needed)

The first suggestion would be sufficient when you simply want to store it.

When you must be able to select particular shapes, e.g for a given area, use the 2nd suggestion. See http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html for details of the spatial extensions


2 functions that either remove the circular references and create storable objects, or restore the overlays from these stored objects.

var IO={
  //returns array with storable google.maps.Overlay-definitions
  IN:function(arr,//array with google.maps.Overlays
              encoded//boolean indicating if pathes should be stored encoded
              ){
      var shapes     = [],
          goo=google.maps,
          shape,tmp;

      for(var i = 0; i < arr.length; i++)
      {   
        shape=arr[i];
        tmp={type:this.t_(shape.type),id:shape.id||null};


        switch(tmp.type){
           case 'CIRCLE':
              tmp.radius=shape.getRadius();
              tmp.geometry=this.p_(shape.getCenter());
            break;
           case 'MARKER': 
              tmp.geometry=this.p_(shape.getPosition());   
            break;  
           case 'RECTANGLE': 
              tmp.geometry=this.b_(shape.getBounds()); 
             break;   
           case 'POLYLINE': 
              tmp.geometry=this.l_(shape.getPath(),encoded);
             break;   
           case 'POLYGON': 
              tmp.geometry=this.m_(shape.getPaths(),encoded);

             break;   
       }
       shapes.push(tmp);
    }

    return shapes;
  },
  //returns array with google.maps.Overlays
  OUT:function(arr,//array containg the stored shape-definitions
               map//map where to draw the shapes
               ){
      var shapes     = [],
          goo=google.maps,
          map=map||null,
          shape,tmp;

      for(var i = 0; i < arr.length; i++)
      {   
        shape=arr[i];       

        switch(shape.type){
           case 'CIRCLE':
             tmp=new goo.Circle({radius:Number(shape.radius),
                                  center:this.pp_.apply(this,shape.geometry)});
            break;
           case 'MARKER': 
             tmp=new goo.Marker({position:this.pp_.apply(this,shape.geometry)});
            break;  
           case 'RECTANGLE': 
             tmp=new goo.Rectangle({bounds:this.bb_.apply(this,shape.geometry)});
             break;   
           case 'POLYLINE': 
             tmp=new goo.Polyline({path:this.ll_(shape.geometry)});
             break;   
           case 'POLYGON': 
             tmp=new goo.Polygon({paths:this.mm_(shape.geometry)});

             break;   
       }
       tmp.setValues({map:map,id:shape.id})
       shapes.push(tmp);
    }
    return shapes;
  },
  l_:function(path,e){
    path=(path.getArray)?path.getArray():path;
    if(e){
      return google.maps.geometry.encoding.encodePath(path);
    }else{
      var r=[];
      for(var i=0;i<path.length;++i){
        r.push(this.p_(path[i]));
      }
      return r;
    }
  },
  ll_:function(path){
    if(typeof path==='string'){
      return google.maps.geometry.encoding.decodePath(path);
    }
    else{
      var r=[];
      for(var i=0;i<path.length;++i){
        r.push(this.pp_.apply(this,path[i]));
      }
      return r;
    }
  },

  m_:function(paths,e){
    var r=[];
    paths=(paths.getArray)?paths.getArray():paths;
    for(var i=0;i<paths.length;++i){
        r.push(this.l_(paths[i],e));
      }
     return r;
  },
  mm_:function(paths){
    var r=[];
    for(var i=0;i<paths.length;++i){
        r.push(this.ll_.call(this,paths[i]));

      }
     return r;
  },
  p_:function(latLng){
    return([latLng.lat(),latLng.lng()]);
  },
  pp_:function(lat,lng){
    return new google.maps.LatLng(lat,lng);
  },
  b_:function(bounds){
    return([this.p_(bounds.getSouthWest()),
            this.p_(bounds.getNorthEast())]);
  },
  bb_:function(sw,ne){
    return new google.maps.LatLngBounds(this.pp_.apply(this,sw),
                                        this.pp_.apply(this,ne));
  },
  t_:function(s){
    var t=['CIRCLE','MARKER','RECTANGLE','POLYLINE','POLYGON'];
    for(var i=0;i<t.length;++i){
       if(s===google.maps.drawing.OverlayType[t[i]]){
         return t[i];
       }
    }
  }

}

The array returned by IO.IN may be sended to a serverside script. The serverside script should iterate over this array and INSERT a JSON-string into the table:

<?php
$mysqli = new mysqli(/*args*/);
$stmt = $mysqli->prepare('INSERT INTO `tableName`(`columnName`) VALUES (?)');
$stmt->bind_param('s', $json);

foreach($_POST['shapes'] as $value){
  $json = json_encode($value);
  $stmt->execute();
}
?>

to restore the shapes fetch them:

<?php
$json=array();
$res=$mysqli->query('SELECT `columnName` from `tableName`');
while ($row = $res->fetch_assoc()) {
        $json[]=json_decode($row['columnName']);
    }
$res->close();
$json=json_encode($json);
?>

and pass the result to IO.OUT():

IO.OUT(<?php echo $json;?>, someGoogleMapsInstance);

Demo: http://jsfiddle.net/doktormolle/EdZk4/show/

Schaab answered 27/10, 2013 at 16:48 Comment(6)
I'm interested in using JSON method but there is a circular refrence. By using JSON we just need one column containig string. Is it possible to use JSON?Vincents
And about using your second method to use some columns. To save all points of a polygon how should I save it? I mean I have to use a string column or a lot of int columnt?Vincents
I've added some details above(related to the first method). The 2nd method is much more complex, I'm not sure if I'll have the time for a detailed explanation in the next days. But to answer the question related to the column-type: it's GEOMETRY, this type may be used to store points,lines and polygons, sufficient to store any type of google.maps.Overlay(except CIRCLE, here you need the additional column for the radius)Schaab
@Schaab could you give me some advice about saving lat lng points in a sqlite db. I am developing a track-my-run app and now i am wondering if i should save each point as a separate row or collect all points in an array and store the array? Any thoughts?Zapateado
when you only want to store LatLngs I would store each LatLng in a separate row.....you would be able to select particular LatLngs(e.g in a given area or even based on other details ...e.g. you may store a time in the row and select points for a particular day)Schaab
This answer is outdatedHauler
M
5

Simple GeoJson Editor is an example of drawing, editing, dropping and saving shapes as geoJson on google maps. The author ( a Google intern) described the project in this post.

The Javascript and HTML are not minified.

An even better opensource tool can be found at Geojson.io

Mouseear answered 12/9, 2015 at 2:25 Comment(0)
B
1

Strange behavior I found in the code http://jsfiddle.net/doktormolle/EdZk4/show/
I added next code to IN function:

         if (tmp.type != 'MARKER') {
             tmp.strokeColor = shape.strokeColor;
             tmp.strokeWeight = shape.strokeWeight;
             tmp.fillColor = shape.fillColor;
             tmp.fillOpacity = shape.fillOpacity;
             tmp.editable = shape.getEditable();
             if (tmp.type == 'POLYLINE' || tmp.type == 'POLYGON')
                 tmp.infoWindowContent = shape.infoWindow.content;
         }

All shapes are editable, but only the last shows editable as true. For example, I add one editable polyline and it is editable in the result.

    "[{"type":"POLYLINE","id":null,"draggable":false,"geometry":["gn_sFwt`eEvmd@ig|B"],
"strokeColor":"red","strokeWeight":3,"fillOpacity":0.35,"editable":true,
"infoWindowContent":"Polyline Length: 58.80  kms"}]"

I add second editable polyline, but in the result the first is uneditable and second editable.

    "[{"type":"POLYLINE","id":null,"draggable":false,"geometry":["gn_sFwt`eEvmd@ig|B"],
"strokeColor":"red","strokeWeight":3,"fillOpacity":0.35,"editable":false,
"infoWindowContent":"Polyline Length: 58.80  kms"},
    {"type":"POLYLINE","id":null,"draggable":false,"geometry":["qoiqFgvheEcsw@ygz@"],
"strokeColor":"red","strokeWeight":3,"fillOpacity":0.35,"editable":true,
"infoWindowContent":"Polyline Length: 41.41  kms"}]"
Borchert answered 17/5, 2021 at 21:56 Comment(0)
A
0

If you need to store the path just to restore it later on a map, you can also use Google Maps Encoding Utility. It is not as powerful as Dr.Molle's answer but can be useful for storing polygons and polylines.

Afoot answered 24/11, 2017 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.