2009-06-28 6 views
17

Chciałbym dodać obraz nakładki na mapie Google. Obraz to wygenerowany przeze mnie plik SVG (Python z SVGFig).Jak mogę nakładać diagramy SVG w Mapach Google?

używam następujący kod:

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

Niespodziewanie współpracuje z Safari 4, ale to nie działa z Firefoksem (z Safari 3, tło nie jest przezroczysty).

Czy ktoś ma pomysł, w jaki sposób mogę nałożyć SVG?

PS1: Czytam niektóre utwory takie jak this lub kod źródłowy swa.ethz.ch/googlemaps, ale wygląda na to, że muszą używać kodu JavaScript do parsowania SVG i dodawać jeden po drugim wszystkie elementy (ale ja nie rozumiem całego źródła ...).

PS2: SVG składa się z różnych wypełnionych ścieżek i okręgów, z przezroczystością. Jeśli nie ma rozwiązania nakładka mój SVG, mogę użyć 2 rozwiązań alternatywnych:

  • rasteryzację SVG
  • konwertowania ścieżki i okręgi w GPolygons

ale nie bardzo podoba mi się Pierwsze rozwiązanie ze względu na słabą jakość bitmapy i czas jej wygenerowania za pomocą antyaliasingu.

A dla drugiego rozwiązania, łuki, elipsy i okręgi będą musiały zostać rozłożone na małe polilinie. Wiele z nich będzie potrzebnych do dobrego wyniku. Ale mam około 3000 łuków i kółek do rysowania, więc ...

+0

Co za świetne pytanie. Mam przeczucie, że twoje drugie podejście się nie sprawdzi, ale wahasz się odpowiedzieć bez potwierdzenia, jak wygląda gmaps przy tej objętości polilinii. Nie mogę się doczekać, aby zobaczyć, jak to się dzieje. – RedBlueThing

+0

Czy GGroundOverly może wykorzystywać obrazy tła CSS? FF nie obsługuje (jeszcze 3.5 woli) SVG jako tła. – Boldewyn

+0

Próbowałem tylko z FF 3.5, ale to też nie działa. W rzeczywistości, gdy patrzę na pobrane media (Narzędzia/Informacje o stronie/Media), mój SVG nie jest w ogóle załadowany ... – ThibThib

Odpowiedz

6

Oto kilka nowości (mam nadzieję, że lepiej jest umieścić je tutaj w odpowiedzi, zamiast edytować moje pytania lub utworzyć nowe pytanie.) W razie potrzeby możesz je przenieść lub powiedzieć, tak jak ja można skorygować):

Mój problem był następujący:

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

nie działa na Safari 3, Firefox i Opera (IE nie pozwalają wyciągnąć SVG).

W rzeczywistości, to kod produkują wstawiania (w <div>) następujących elementów

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

i Safari 4 jest w stanie wyciągnąć plik SVG jako obraz, ale nie jest to sposób, aby zrobić dla drugiej przeglądarki. Więc pomysł polega teraz na stworzeniu niestandardowej nakładki na SVG, jak wyjaśnił here.

To jest powód, dla którego poprosiłem o this question (Przykro mi, ale HTML/javascript nie są moje najsilniejsze punkty).

A ponieważ jest tam mały błąd z Webkit do renderowania SVG z przezroczystym tłem z <object> elementu, muszę korzystać <object> lub <img> odpowiednio do przeglądarki (nie lubię tego, ale w tej chwili ... , to nadal szybki i brzydka eksperymenty)

zacząłem więc z tego kodu (wciąż w toku):

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

... 

funkcja draw nie jest jeszcze napisane.

Nadal mam problem (postępuję powoli, dzięki temu, co czytam/uczę się wszędzie, a także dzięki ludziom, którzy odpowiadają na moje pytania).

Problem jest następujący: z tagiem <object> mapa nie jest przeciągalna. W całym elemencie <object> wskaźnik myszy nie jest "ikoną ręki", aby przeciągnąć mapę, ale zwykłym wskaźnikiem.

I nie znalazłem sposobu, aby to poprawić. Czy powinienem dodać nowe zdarzenie myszy (widziałem zdarzenie myszy po kliknięciu lub dwukrotnym kliknięciu, ale nie w celu przeciągnięcia mapy ...)?

Czy istnieje inny sposób dodania tej warstwy, aby zachować zdolność przeciągania?

Dziękuję za uwagi i odpowiedzi.

PS: Próbuję też dodawać po jednym elementy mojego SVG, ale ... w rzeczywistości ... Nie wiem, jak dodać je do drzewa DOM. W pliku this example, SVG jest odczytywany i analizowany przy pomocy GXml.parse(), a wszystkie elementy o danej nazwie znacznika są uzyskiwane (xml.documentElement.getElementsByTagName) i dodawane do węzła SVG (svgNode.appendChild(node)). Ale w moim przypadku muszę dodać bezpośrednio drzewo SVG/XML (dodać wszystkie jego elementy) i istnieją różne znaczniki (<defs>, <g>, <circle>, <path> itd.). To może być prostsze, ale nie wiem jak to zrobić .. :(

2

To pytanie zostało krótko omówione na Google Maps API Group. Oto co powiedział:

Ja nie próbowałem, ale SVG jest podzbiorem XML, dzięki czemu można je odczytać z GDownloadUrl() i analizować je z GXml.parse(). Na niektórych chytrych serwerach internetowych może być konieczna zmiana rozszerzenia pliku na na XML.

Następnie trzeba przedzierać się przez XML DOM, pisanie SVG, które można znaleźć z document.createElementNS() i .setAttribute() wywołuje ...

Istnieje również niektóre Google Mapy Przykłady SVG: here i here.

Powodzenia!

+0

OK, dzięki za link. Tak, może mogę załadować mój plik, przeanalizować go i wstawić jeden po drugim wszystkie moje elementy SVG. Spróbuję, nawet jeśli to rozwiązanie mnie nie przekona ... I już jestem w stanie załadować w jednym kroku z GGroundOverlay ("test.svg", granice), ale tylko z Safari 4 ... Powiem jak to idzie – ThibThib

6

I spędzić ostatni wieczór na ten problem, a ja w końcu znaleźć rozwiązanie mojego problemu.

To nie było tak trudne.

Chodzi o to, jak Chris B. powiedział, aby załadować plik SVG z GDownloadUrl, analizować je z GXml.parse() i dodać w drzewie DOM elementów SVG co muszę

w celu uproszczenia, Przypuszczam, że wszystkie elementy SVG zostały umieszczone w dużej grupie o nazwie "mainGroup" .Myślę też, że niektóre elementy mogą znajdować się w pliku.

Więc tutaj jest biblioteka, w oparciu o 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"; 
} 

I można go używać z następującego kodu:

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

więc można go używać dokładnie jak używać funkcja GGroundOverlay, z tym że twój plik SVG powinien zostać utworzony z projekcją Mercator (ale jeśli zastosujesz go na małym obszarze, takim jak jedno miasto lub mniej, nie zobaczysz różnicy).

Powinno to działać z przeglądarkami Safari, Firefox i Opera. Możesz wypróbować mój mały przykład: here

Powiedz mi, co o tym myślisz.

+0

Doskonały przykład! –