2009-06-28 16 views
17

Vorrei aggiungere un'immagine di sovrapposizione su una mappa di Google. L'immagine è un file SVG che ho generato (Python con SVGFig).Come posso sovrapporre i diagrammi SVG su Google Maps?

Sto usando il seguente codice:

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); 
} 

Sorprendentemente, funziona con Safari 4, ma non funziona con Firefox (con Safari 3, lo sfondo non è trasparente).

Qualcuno ha un'idea su come sovrapporre un SVG?

PS1: Ho letto alcuni lavori come this o il codice sorgente di swa.ethz.ch/googlemaps, ma sembra che debbano usare il codice JavaScript per analizzare l'SVG e aggiungere uno alla volta tutti gli elementi (ma io non ho capito tutta la fonte ...).

PS2: L'SVG è composto da diversi percorsi e cerchi riempiti, con trasparenza. Se non esiste una soluzione per sovrapporre il mio SVG, posso usare 2 soluzioni alternative:

  • rasterizzare la SVG
  • convertire i sentieri e cerchi in GPolygons

ma non mi piace molto il Prima soluzione a causa della scarsa qualità della bitmap e del tempo necessario per generarla con l'antialiasing.

E per la seconda soluzione, gli archi, le ellissi e i cerchi dovranno essere decomposti in piccole polilinee. Molti di loro saranno necessari per un buon risultato. Ma ho circa 3000 archi e cerchi da disegnare, quindi ...

+0

Che bella domanda. Il mio istinto è che il tuo secondo approccio non funzionerà, ma esita a rispondere senza confermare come funziona gmap con quel volume di polilinee. Non vedo l'ora di vedere come va. – RedBlueThing

+0

Potrebbe essere che GGround utilizza le immagini di sfondo CSS? FF non gestisce (ancora, 3.5 saranno) SVG come sfondi. – Boldewyn

+0

Ho appena provato con FF 3.5, ma non funziona, anche. Infatti, quando guardo nel supporto scaricato (Strumenti/Pagina Info/Media), il mio SVG non è stato caricato affatto ... – ThibThib

risposta

6

Ecco alcune notizie (spero sia meglio metterle qui in una risposta, invece di modificare le mie domande o creare una nuova domanda. Per favore sentitevi liberi di spostarlo se necessario, o di dirmelo, così come può rettificare):

il mio problema era il seguente:

var oldmap = new GGroundOverlay("test.svg", boundaries); 
map.addOverlay(oldmap); 

non ha funzionato su Safari 3, Firefox e Opera (IE non è consentono di disegnare SVG).

Infatti, questo codice produce l'inserimento (in un <div>) del seguente elemento

<img src="test.svg" style="....."> 

E Safari 4 è in grado di elaborare un file SVG come immagine, ma questo non è il modo di fare per l'altro browser. Quindi l'idea è ora di creare una sovrapposizione personalizzata per SVG, come spiegato here.

Questo è il motivo per cui ho chiesto this question (Mi dispiace, ma HTML/javascript non sono i miei punti di forza).

E dato che c'è un piccolo bug con Webkit per il rendering di una SVG con sfondo trasparente con <object> elemento, ho bisogno di usare <object> o <img> di conseguenza per il browser (non mi piace, ma ... per il momento , è ancora agli esperimenti veloci-e-sporco)

Così ho iniziato con questo codice (ancora work in progress):

// create the object 
function myOverlay(SVGurl, bounds) 
{ 
    this.url_ = SVGurl; 
    this.bounds_ = bounds; 
} 

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

// initialize 
myOverlay.prototype.initialize = function(map) 
{ 
    // create the div 
    var div = document.createElement("div"); 
    div.style.position = "absolute"; 
    div.setAttribute('id',"SVGdiv"); 
    div.setAttribute('width',"900px"); 
    div.setAttribute('height',"900px"); 

    // add it with the same z-index as the map 
    this.map_ = map; 
    this.div_ = div; 

    //create new svg root element and set attributes 
    var svgRoot; 
    if (BrowserDetect.browser=='Safari') 
    { 
     // Bug in webkit: with <objec> element, Safari put a white background... :-(
     svgRoot = document.createElement("img"); 
     svgRoot.setAttribute("id", "SVGelement"); 
     svgRoot.setAttribute("type", "image/svg+xml"); 
     svgRoot.setAttribute("style","width:900px;height:900px"); 
     svgRoot.setAttribute("src", "test.svg"); 
    } 
    else //if (BrowserDetect.browser=='Firefox') 
    { 
     svgRoot = document.createElement("object"); 
     svgRoot.setAttribute("id", "SVGelement"); 
     svgRoot.setAttribute("type", "image/svg+xml"); 
     svgRoot.setAttribute("style","width:900px;height:900px;"); 
     svgRoot.setAttribute("data", "test.svg"); 
    } 


    div.appendChild(svgRoot); 
    map.getPane(G_MAP_MAP_PANE).appendChild(div); 

    //this.redraw(true); 
} 

... 

La funzione draw non è stato ancora scritto.

Ho ancora un problema (progredisco lentamente, grazie a ciò che leggo/apprendo ovunque, e anche grazie alle persone che rispondono alle mie domande).

Ora, il problema è il seguente: con il tag <object>, la mappa non è trascinabile. In tutto l'elemento <object>, il puntatore del mouse non è "l'icona della mano" per trascinare la mappa, ma solo il puntatore normale.

E non ho trovato come correggere questo. Dovrei aggiungere un nuovo evento del mouse (ho appena visto l'evento del mouse quando un clic o un doppio clic accodano, ma non per trascinare la mappa ...)?

Oppure c'è un altro modo per aggiungere questo livello in modo da preservare la capacità di trascinamento?

Grazie per i vostri commenti e risposte.

PS: Cerco anche di aggiungere uno ad uno gli elementi del mio SVG, ma ... in effetti ... non so come aggiungerli nell'albero DOM. In this example, l'SVG viene letto e analizzato con GXml.parse() e tutti gli elementi con un determinato nome di tag vengono ottenuti (xml.documentElement.getElementsByTagName) e aggiunti al nodo SVG (svgNode.appendChild(node)). Ma nel mio caso, ho bisogno di aggiungere direttamente l'albero SVG/XML (aggiungere tutti i suoi elementi), e ci sono diversi tag (<defs>, <g>, <circle>, <path>, ecc.). E 'potrebbe essere più semplice, ma non so come fare .. :(

2

Questa domanda è stata brevemente discussa su Google Maps API Group. Ecco cosa hanno detto:

io non ho provato, ma SVG è un sottoinsieme di XML, in modo da poterli leggere con GDownloadUrl() e analizzarli con GXml.parse(). Su alcuni fastidiosi web server potrebbe essere necessario modificare l'estensione del file in XML.

È quindi necessario strisciare attraverso l'XML DOM, scrivendo la SVG che trovate con document.createElementNS() e .setAttribute() chiama ...

ci sono anche un po 'di Google Esempi di mappe SVG here e here.

Buona fortuna!

+0

Ok, grazie per il link. Sì, forse posso caricare il mio file, analizzarlo e inserire uno per uno tutti i miei elementi SVG. Ci proverò, anche se questa soluzione non mi convince ... E sono già in grado di caricare in un passo con GGroundOverlay ("test.svg", i confini) ma solo con Safari 4 ... Dirò come va questo – ThibThib

6

ho trascorrere l'ultima sera su questo problema, e ho finalmente trovato la soluzione al mio problema.

Non è stato così difficile.

l'idea è, come Chris B. ha detto, per caricare il file in formato SVG con GDownloadUrl, analizza con GXml.parse() e aggiungere nell'albero DOM ogni elementi SVG ho bisogno

per semplificare, Ho supposto che tutti gli elementi SVG fossero inseriti in un grosso gruppo chiamato "mainGroup", e ho anche supposto che alcuni elementi potessero essere nel file.

ecco la biblioteca, in base alla 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"; 
} 

E, lo si può utilizzare con il seguente codice:

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); 
} 

Quindi, è possibile utilizzarlo esattamente come si usa la funzione GGroundOverlay, tranne per il fatto che il file SVG deve essere creato con la proiezione di Mercator (ma se lo si applica su un'area piccola, come una città o più piccola, non si vedrà la differenza).

Questo dovrebbe funzionare con Safari, Firefox e Opera. Puoi provare il mio piccolo esempio here

Dimmi cosa ne pensi.

+0

Fantastico esempio! –