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.

Sponge Bob
  • 377
  • 1
  • 5
  • 12
  • possible duplicate of [How to save array contains objects (Google map overlays) in database?](http://stackoverflow.com/questions/19615298/how-to-save-array-contains-objects-google-map-overlays-in-database) – AlexB Oct 27 '13 at 10:47
  • i had a same problem save polygon from google maps to postgresql this is what i did https://stackoverflow.com/a/39438476/924300 – Dimitris Kougioumtzis Sep 11 '16 at 17:03

4 Answers4

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/

Dr.Molle
  • 116,463
  • 16
  • 195
  • 201
  • 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? – Sponge Bob Oct 28 '13 at 15:45
  • 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? – Sponge Bob Oct 28 '13 at 16:11
  • 1
    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`](http://dev.mysql.com/doc/refman/5.0/en/mysql-spatial-datatypes.html), 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) – Dr.Molle Oct 29 '13 at 22:11
  • 1
    Your JSON method is perfect! Thank you so much! – pmrotule Jan 30 '14 at 16:17
  • @Dr.Molle 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? – alex Aug 24 '15 at 19:33
  • 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) – Dr.Molle Aug 25 '15 at 00:50
  • This answer is outdated – Jesse Parker Jul 04 '17 at 20:06
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

intotecho
  • 4,925
  • 3
  • 39
  • 54
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"}]"
Vavania M
  • 11
  • 1
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.

trainmaster
  • 145
  • 10