2009-06-28 8 views
17

Je voudrais ajouter une image de superposition sur une carte Google. L'image est un fichier SVG que j'ai généré (Python avec SVGFig).Comment superposer des diagrammes SVG sur Google Maps?

J'utilise le code suivant:

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

Étonnamment, cela fonctionne avec Safari 4, mais il ne fonctionne pas avec Firefox (avec Safari 3, l'arrière-plan est pas transparent).

Est-ce que quelqu'un a une idée sur la façon dont je pourrais superposer un SVG? PS1: J'ai lu quelques travaux comme this ou le code source de swa.ethz.ch/googlemaps, mais il semble qu'ils doivent utiliser du code JavaScript pour analyser le SVG et ajouter un par un tous les éléments (mais je n'a pas compris toute la source ...). PS2: Le SVG est composé de différents chemins et cercles remplis, avec transparence. S'il n'y a pas de solution pour superposer mon SVG, je peux utiliser deux solutions alternatives:

  • pixelliser SVG
  • convertir les chemins et les cercles en GPolygons

Mais je ne aime pas vraiment la 1ère solution en raison de la mauvaise qualité du bitmap et du temps nécessaire pour le générer avec antialiasing.

Et pour la 2ème solution, les arcs, les ellipses et les cercles devront être décomposés en petites polylignes. Beaucoup d'entre eux seront nécessaires pour un bon résultat. Mais j'ai environ 3000 arcs et cercles à dessiner, donc ...

+0

Quelle bonne question. Mon instinct est que votre deuxième approche ne fonctionnera pas, mais hésiter à répondre sans confirmer comment fonctionne gmaps avec ce volume de polylignes. Je suis impatient de voir comment cela se passe. – RedBlueThing

+0

Se pourrait-il que GGroundOverly utilise des images de fond CSS? FF ne gère pas (encore, 3.5) les SVG comme arrière-plans. – Boldewyn

+0

J'ai juste essayé avec FF 3.5, mais ça ne marche pas aussi. En fait, quand je regarde dans les médias téléchargés (Outils/Page Info/Media), mon SVG n'est pas chargé du tout ... – ThibThib

Répondre

6

Voici quelques nouvelles (j'espère qu'il est préférable de les mettre ici dans une réponse, au lieu de modifier mes questions ou de créer une nouvelle question.) N'hésitez pas à la déplacer si nécessaire, ou à me le dire, peut rectifier):

Mon problème est le suivant:

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

ne fonctionne pas sur Safari 3, Firefox et Opera (IE permettent pas de tirer SVG).

En fait, ce code produire l'insertion (dans un <div>) de l'élément suivant

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

Et Safari 4 est capable de dessiner un fichier SVG comme une image, mais ce n'est pas la façon de le faire pour l'autre navigateur. Donc, l'idée est maintenant de créer une superposition personnalisée pour le SVG, comme expliqué here.

C'est la raison pour laquelle j'ai demandé this question (Je suis désolé, mais HTML/javascript ne sont pas mes points forts).

Et comme il y a un petit bug avec Webkit pour le rendu d'un SVG avec un fond transparent avec l'élément <object>, je dois utiliser <object> ou <img> en conséquence au navigateur (je ne l'aime pas, mais ... pour le moment , il est encore des expériences rapides et sale)

Alors j'ai commencé avec ce code (encore en cours):

// 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 fonction draw est pas encore écrit.

J'ai encore un problème (je progresse lentement, grâce à ce que je lis/apprends partout, et aussi grâce aux personnes qui répondent à mes questions).

Maintenant, le problème est le suivant: avec la balise <object>, la carte ne peut pas être déplacée. Sur l'élément <object>, le pointeur de la souris n'est pas "l'icône de la main" pour faire glisser la carte, mais seulement le pointeur normal.

Et je n'ai pas trouvé comment corriger cela. Dois-je ajouter un nouvel événement de souris (je viens de voir l'événement de souris quand un clic ou un double-clic s'ajoute, mais pas pour faire glisser la carte ...)?

Ou existe-t-il une autre façon d'ajouter cette couche afin de préserver la capacité de traînée?

Merci pour vos commentaires et réponses. PS: J'essaie aussi d'ajouter un à un les éléments de mon SVG, mais ... en fait ... je ne sais pas comment les ajouter dans l'arborescence DOM. Dans , le SVG est lu et analysé avec GXml.parse(), et tous les éléments avec un nom de point donné sont obtenus (xml.documentElement.getElementsByTagName) et ajoutés au nœud SVG (svgNode.appendChild(node)). Mais dans mon cas, j'ai besoin d'ajouter directement l'arbre SVG/XML (ajouter tous ses éléments), et il y a différents tags (<defs>, <g>, <circle>, <path>, etc.). Il est peut-être plus simple, mais je ne sais pas comment faire .. :(

2

Cette question a été discutée brièvement sur le Google Maps API Group. Voici ce qu'ils ont dit:

Je ne l'ai pas essayé, mais SVG est un sous-ensemble de XML, afin que vous puissiez les lire avec GDownloadUrl() et les analyser avec GXml.parse(). Sur certains serveurs Web bancables , vous devrez peut-être modifier l'extension du fichier en XML.

Vous avez alors à ramper à travers le XML DOM, écrire le SVG que vous trouvez avec document.createElementNS() et .setAttribute() appelle ...

Il y a aussi quelques-uns Google Mappe les exemples SVG here et here.

Bonne chance!

+0

Ok, merci pour le lien. Oui, peut-être puis-je charger mon fichier, l'analyser et insérer un par un tous mes éléments SVG. Je vais essayer, même si cette solution ne me convainc pas ... Et je suis déjà capable de charger en une étape avec GGroundOverlay ("test.svg", limites) mais seulement avec Safari 4 ... Je dirai comment ça va – ThibThib

6

Je passe le dernier soir sur ce problème, et j'ai finalement trouvé la solution à mon problème.

Ce n'était pas difficile.

l'idée est, comme Chris B. dit, pour charger le fichier SVG avec GDownloadUrl, parse avec GXml.parse() et ajouter dans l'arborescence DOM tous les éléments SVG dont j'ai besoin

pour simplifier, J'ai supposé que tous les éléments SVG étaient placés dans un grand groupe appelé "mainGroup" et j'ai supposé que certains éléments pouvaient être dans le fichier.

Voici donc la bibliothèque, sur la base 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"; 
} 

Et, vous pouvez l'utiliser avec le code suivant:

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

Ainsi, vous pouvez l'utiliser exactement comme vous utilisez la fonction GGroundOverlay, sauf que votre fichier SVG doit être créé avec la projection Mercator (mais si vous l'appliquez sur une petite zone, comme une ville ou moins, vous ne verrez pas la différence).

Cela devrait fonctionner avec Safari, Firefox et Opera. Vous pouvez essayer mon petit exemple here

Dites-moi ce que vous en pensez.

+0

Super exemple! –