views:

2368

answers:

4

Hello

I would like to add an overlay image on a google map. This image is a SVG file I have generated (python with svgfig).

I am using the following code

if (GBrowserIsCompatible()) {
    var map = new GMap2(document.getElementById("map_canvas"));
    map.setCenter(new GLatLng(48.8, 2.4), 12);

    // ground overlay
    var boundaries = new GLatLngBounds(new GLatLng(48.283188032632829, 1.9675270369830129), new GLatLng(49.187215000000002, 2.7771877478303999));
    var oldmap = new GGroundOverlay("test.svg", boundaries);
    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());
    map.addOverlay(oldmap);
}

Surprisingly, it works with Safari 4, but it doesn't with Firefox (with Safari 3, the background is not transparent)

Does anyone has an idea on how I could overlay a SVG ?

Thanks

PS1: I read some works like this or the source code of swa.ethz.ch/googlemaps, but it seems that they have to use javascript code to parse the SVG and add one by one all the elements (but I did not understood all the source...)

PS2: The SVG is composed of different filled paths and circles, with transparency. If there is no solution to overlay my SVG, I can use 2 alternative solutions:

  • rasterize the SVG
  • convert the paths and circles in GPolygons

But, I do not really like the 1st solution because of the poor quality of the bitmap and the time to generate it with antialiasing.

And for the 2nd solutions, the arcs, ellipses and circles will have to be decomposed into small polylines. A lot of them will be necessary for a good result. But I have around 3000 arcs and circles to draw, so...

+1  A: 

This question was briefly discussed on the Google Maps API Group. Here's what they said:

I've not tried it, but SVG is a subset of XML, so you can read them with GDownloadUrl() and analyse them with GXml.parse(). On some wonky webservers you may have to change the file extension to XML.

You then have to crawl through the XML DOM, writing the SVG that you find with document.createElementNS() and .setAttribute() calls...

There are also a some Google Maps SVG examples here and here.

Good luck!

Chris B
Ok, thanks for the link. Yes, maybe can I load my file, parse it and insert one by one all my SVG elements. I will try, even if this solution doesn't convince me...And I am already able to load in one step with GGroundOverlay("test.svg", boundaries) but only with Safari 4...I will tell you how this goes
ThibThib
+1  A: 
ThibThib
+1  A: 

Hello

I spend the last evening on this problem, and I finally found the solution to my problem.

It was not so difficult.

The idea is, as Chris B. said, to load the SVG file with GDownloadUrl, parse it with GXml.parse() and add in the DOM tree every SVG elements I need

To simplify, I have supposed that all the SVG elements was put in a big group called "mainGroup". I have also supposed that some elements can be in the file.

So here is the library, based on the Google Maps Custom Overlays:

// create the object
function overlaySVG( svgUrl, bounds)
{
    this.svgUrl_ = svgUrl;
    this.bounds_ = bounds;
}


// prototype
overlaySVG.prototype = new GOverlay();


// initialize
overlaySVG.prototype.initialize = function( map)
{
    //create new div node 
    var svgDiv = document.createElement("div");
    svgDiv.setAttribute( "id", "svgDivison");
    //svgDiv.setAttribute( "style", "position:absolute");
    svgDiv.style.position = "absolute";
    svgDiv.style.top = 0;
    svgDiv.style.left = 0;
    svgDiv.style.height = 0;
    svgDiv.style.width = 0;
    map.getPane(G_MAP_MAP_PANE).appendChild(svgDiv);

    // create new svg element and set attributes
    var svgRoot = document.createElementNS( "http://www.w3.org/2000/svg", "svg");
    svgRoot.setAttribute( "id", "svgRoot");
    svgRoot.setAttribute( "width", "100%");
    svgRoot.setAttribute( "height","100%");
    svgDiv.appendChild( svgRoot);

    // load the SVG file
    GDownloadUrl( this.svgUrl_, function( data, responseCode)
    {
     var xml = GXml.parse(data);
     // specify the svg attributes
     svgRoot.setAttribute("viewBox", xml.documentElement.getAttribute("viewBox"));
     // append the defs
     var def = xml.documentElement.getElementsByTagName("defs");
     //for( var int=0; i<def.length; i++)
      svgRoot.appendChild(def[0].cloneNode(true));
     //append the main group
     var nodes = xml.documentElement.getElementsByTagName("g");
     for (var i = 0; i < nodes.length; i++)
      if (nodes[i].id=="mainGroup")
       svgRoot.appendChild(nodes[i].cloneNode(true));
    });

    // keep interesting datas
    this.svgDiv_ = svgDiv;
    this.map_ = map;

    // set position and zoom
    this.redraw(true);
}



// remove from the map pane
overlaySVG.prototype.remove = function()
{
    this.div_.parentNode.removeChild( this.div_);
}


// Copy our data to a new overlaySVG...
overlaySVG.prototype.copy = function()
{
    return new overlaySVG( this.url_, this.bounds_, this.center_);
}


// Redraw based on the current projection and zoom level...
overlaySVG.prototype.redraw = function( force)
{
    // We only need to redraw if the coordinate system has changed
    if (!force) return;
    // get the position in pixels of the bound
    posNE = map.fromLatLngToDivPixel(this.bounds_.getNorthEast());  
    posSW = map.fromLatLngToDivPixel(this.bounds_.getSouthWest());
    // compute the absolute position (in pixels) of the div ...
    this.svgDiv_.style.left = Math.min(posNE.x,posSW.x) + "px";
    this.svgDiv_.style.top = Math.min(posSW.y,posNE.y) + "px";
    // ... and its size
    this.svgDiv_.style.width = Math.abs(posSW.x - posNE.x) + "px";
    this.svgDiv_.style.height = Math.abs(posSW.y - posNE.y) + "px";
}

And, you can use it with the following code:

if (GBrowserIsCompatible())
{
    //load map
    map = new GMap2(document.getElementById("map"), G_NORMAL_MAP);
    // create overlay 
    var boundaries = new GLatLngBounds( new GLatLng(48.2831, 1.9675), new GLatLng(49.1872, 2.7774));
    map.addOverlay( new overlaySVG( "test.svg", boundaries ));
    //add control and set map center
    map.addControl(new GLargeMapControl());
    map.setCenter(new GLatLng(48.8, 2.4), 12);
}

So, you can use it exactly as you use the GGroundOverlay function, except that your SVG file should be created with the Mercator projection (but if you apply it on small area, like one city or smaller, you will not see the difference).

This should work with Safari, Firefox and Opera. You can try my small example here

Tell me what do you think about it.

ThibThib
A: 

if there are some events using script or style tag, how do we make it work?

van nguyen