2009-06-28 23 views
17

Me gustaría agregar una imagen de superposición en un mapa de Google. La imagen es un archivo SVG que he generado (Python con SVGFig).¿Cómo puedo superponer diagramas SVG en Google Maps?

estoy usando el siguiente código:

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, funciona con Safari 4, pero no funciona con Firefox (con Safari 3, el fondo no es transparente).

¿Alguien tiene una idea sobre cómo podría superponer un SVG?

PS1: leo algunos trabajos como this o el código fuente de swa.ethz.ch/googlemaps, pero parece que tienen que usar código JavaScript para analizar el SVG y agregar uno por uno todos los elementos (pero yo no entendió toda la fuente ...).

PS2: El SVG se compone de diferentes rutas y círculos rellenos, con transparencia. Si no hay una solución para superponer mi SVG, puedo usar 2 soluciones alternativas:

  • Rasterice el SVG
  • convertir los caminos y los círculos en GPolygons

pero no me gusta mucho la Primera solución debido a la mala calidad del mapa de bits y el tiempo para generarlo con antialiasing.

Y para la segunda solución, los arcos, elipses y círculos tendrán que descomponerse en pequeñas polilíneas. Muchos de ellos serán necesarios para un buen resultado. Pero tengo alrededor de 3000 arcos y círculos para dibujar, entonces ...

+0

¡Qué gran pregunta. Mi intuición es que su segundo enfoque no funcionará, pero dudan en responder sin confirmar cómo funciona gmaps con ese volumen de polilíneas. Espero ver cómo va esto. – RedBlueThing

+0

¿Podría ser que GGroundOverly haga uso de imágenes de fondo CSS? FF no maneja (sin embargo, 3.5 lo hará) SVG como fondos. – Boldewyn

+0

Acabo de probar con FF 3.5, pero tampoco funciona. De hecho, cuando busco en los medios descargados (Herramientas/Información de página/Medios), mi SVG no se carga en absoluto ... – ThibThib

Respuesta

6

Aquí hay algunas noticias (espero que sea mejor ponerlas aquí en una respuesta, en lugar de editar mis preguntas o crear una nueva pregunta. Siéntase libre de moverla si es necesario, o de decirme, para que yo puede rectificar):

Mi problema era el siguiente:

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

no trabajar en Safari 3, Firefox y Opera (IE no se permiten dibujar SVG).

De hecho, este código generar la inserción (en un <div>) del elemento siguiente

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

y Safari 4 es capaz de arrastrar un archivo SVG como una imagen, pero esta no es la manera de hacerlo para el otro navegador. Entonces la idea ahora es crear una superposición personalizada para SVG, como se explica en here.

Esa es la razón por la que solicité this question (Lo siento, pero HTML/javascript no son mis puntos más fuertes).

Y puesto que hay un pequeño error con Webkit para la prestación de un SVG con el fondo transparente con <object> elemento, necesito utilizar <object> o <img> en consecuencia para el navegador (no me gusta esto, pero ... por el momento , sigue siendo los experimentos rápida y sucia-)

así que empecé con este código (todavía trabajo en curso):

// 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 función draw aún no está escrito.

Todavía tengo un problema (progreso lentamente, gracias a lo que leo/aprendo en todas partes, y también gracias a las personas que responden mis preguntas).

Ahora, el problema es el siguiente: con la etiqueta <object>, el mapa no se puede arrastrar. En todo el elemento <object>, el puntero del mouse no es "el icono de la mano" para arrastrar el mapa, sino solo el puntero normal.

Y no he encontrado cómo corregir esto. ¿Debo agregar un nuevo evento de mouse (acabo de ver el evento del mouse cuando se hace clic en un clic o en un doble clic, pero no para arrastrar el mapa ...)?

O hay otra forma de agregar esta capa con el fin de preservar la capacidad de arrastrar?

Gracias por sus comentarios y respuestas.

PD: También trato de agregar uno por uno los elementos de mi SVG, pero ... de hecho ... no sé cómo agregarlos al árbol DOM. En this example, el SVG se lee y se analiza con GXml.parse(), y todos los elementos con un nombre de etiqueta dado se obtienen (xml.documentElement.getElementsByTagName) y se agregan al nodo SVG (svgNode.appendChild(node)). Pero en mi caso, necesito agregar directamente el árbol SVG/XML (agregar todos sus elementos), y hay diferentes etiquetas (<defs>, <g>, <circle>, <path>, etc.). Es puede ser más simple, pero no sé cómo hacerlo .. :(

2

Esta pregunta fue brevemente discutida en el Google Maps API Group. Esto es lo que dijeron:

yo no lo he probado, pero SVG es un subconjunto de XML, para que pueda leer con GDownloadUrl() y analizarlos con GXml.parse(). En algunos servidores web wonky puede que tenga que cambiar la extensión del archivo a XML.

A continuación, tiene que arrastrarse a través del DOM XML , escribiendo el SVG que se encuentra con document.createElementNS() y .setAttribute() llama ...

Hay también un poco de Google son Mapas SVG ejemplos here y here.

¡Buena suerte!

+0

Ok, gracias por el enlace. Sí, tal vez pueda cargar mi archivo, analizarlo e insertar uno por uno todos mis elementos SVG. Lo intentaré, incluso si esta solución no me convence ... Y ya puedo cargar en un solo paso con GGroundOverlay ("test.svg", límites) pero solo con Safari 4 ... Voy a contar cómo esto va – ThibThib

6

que pasar la última noche en este problema, y ​​finalmente he encontrado la solución a mi problema.

No fue tan difícil.

la idea es, como Chris B. dijo, para cargar el archivo SVG con GDownloadUrl, analizarlo con GXml.parse() y añadir en el árbol DOM cada elementos SVG que necesito

para simplificar, Supongo que todos los elementos de SVG se pusieron en un gran grupo llamado "grupo principal". También he supuesto que algunos elementos pueden estar en el archivo.

Así que aquí es la biblioteca, en base a la 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"; 
} 

Y, que se puede utilizar con el siguiente código:

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

Por lo tanto, se puede usar tal y como se utiliza la función GGroundOverlay, excepto que su archivo SVG debe crearse con la proyección de Mercator (pero si lo aplica en un área pequeña, como una ciudad o más pequeña, no verá la diferencia).

Esto debería funcionar con Safari, Firefox y Opera. Puedes probar mi pequeño ejemplo here

Dime lo que piensas al respecto.

+0

¡Ejemplo impresionante! –