Comment puis-je superposer les diagrammes SVG sur Google Maps?

J'aimerais ajouter une image superposée sur une carte Google. L'image est un fichier SVG que j'ai généré (Python avec SVGFig).

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, il fonctionne avec Safari 4, mais cela ne fonctionne pas avec Firefox (avec Safari 3, le fond n'est pas transparent).

Quelqu'un a-t-il une idée de la façon dont je pourrais superposer un SVG?

PS1: J'ai lu certains travaux comme celui-ci ou le code source de swa.ethz.ch/googlemaps, mais il semble qu'ils doivent utiliser le code JavaScript pour analyser le SVG et ajouter un par un tous les éléments (mais je n'ai pas compris tout 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 2 solutions alternatives:

  • Rasterize le SVG
  • Convertir les chemins et les cercles dans GPolygons

Mais je n'aime pas vraiment la 1ère solution en raison de la mauvaise qualité du bitmap et du temps de la 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 …

Voici quelques nouvelles (j'espère qu'il vaut mieux les mettre ici dans une réponse, au lieu d'éditer mes questions ou de créer une nouvelle question. S'il vous plaît, sentez-vous libre de la déplacer si nécessaire, ou de me le dire, afin de pouvoir la corriger):

Mon problème était le suivant:

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

N'a pas fonctionné sur Safari 3, Firefox et Opera (IE n'est pas autorisé à dessiner SVG).

En fait, ce code produit 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 en tant qu'image, mais ce n'est pas le cas pour l'autre navigateur. L'idée est maintenant de créer une superposition personnalisée pour le SVG, comme expliqué ici .

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

Et comme il y a un petit bogue avec Webkit pour rendre un SVG avec un fond transparent avec un élément <object> , je dois utiliser <object> ou <img> fonction du navigateur (je n'aime pas ça, mais … pour Le moment, ce sont encore les expériences rapides et sales)

J'ai donc commencé avec ce code (toujours 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 de draw n'est pas encore écrite.

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 <object> , la carte n'est pas entraînable. 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 simplement 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 un événement de souris quand un clic ou un double clic apporte, mais pas pour faire glisser la carte …)?

Ou est-ce qu'il y a un autre moyen d'ajouter cette couche afin de préserver la capacité de traînée?

Merci pour vos commentaires et réponses.

PS: j'essaie également d'ajouter un par un les éléments de mon SVG, mais … en fait … Je ne sais pas comment les ajouter dans l'arbre DOM. Dans cet exemple , le SVG est lu et analysé avec GXml.parse() et tous les éléments avec un nom de balise donné sont obtenus ( xml.documentElement.getElementsByTagName ) et ajoutés au nœud SVG ( svgNode.appendChild(node) ). Mais dans mon cas, je dois ajouter directement l'arbre SVG / XML (ajouter tous ses éléments), et il existe différentes variables ( <defs> , <g> , <circle> , <path> , etc.). C'est peut-être plus simple, mais je ne sais pas comment faire … 🙁

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

Ce n'était pas si difficile.

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

Pour simplifier, j'ai supposé que tous les éléments SVG ont été mis dans un grand groupe appelé «groupe principal». J'ai également supposé que certains éléments peuvent être dans le fichier.

Voici donc la bibliothèque, basée sur les superpositions personnalisées de Google Maps :

 // 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 lorsque vous utilisez la fonction GGroundOverlay , sauf que votre fichier SVG devrait être créé avec la projection Mercator (mais si vous l'appliquez sur une petite zone, comme une ville ou une petite taille, vous ne verrez pas la différence).

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

Dites-moi ce que vous en pensez.

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

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

Vous devez ensuite parcourir le DOM XML, en écrivant le SVG que vous trouvez avec les appels document.createElementNS () et .setAttribute () …

Il existe également quelques exemples de SVG Google Maps ici et ici .

Bonne chance!