Как я могу накладывать диаграммы SVG на Картах Google?

17

Я хотел бы добавить оверлейное изображение на карте Google. Изображение - это SVG-файл, который я сгенерировал (Python с SVGFig).

Я использую следующий код:

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

Удивительно, но он работает с Safari 4, но он не работает с Firefox (с Safari 3, фон не прозрачен).

Есть ли у кого-нибудь идея о том, как я могу наложить SVG?

PS1: Я прочитал некоторые работы, такие как это или исходный код swa.ethz.ch/ googlemaps, но кажется, что они должны использовать JavaScript-код для синтаксического анализа SVG и добавлять по одному все элементы (но я не понял весь источник ...).

PS2: SVG состоит из разных заполненных дорожек и кругов с прозрачностью. Если нет решения для наложения моего SVG, я могу использовать 2 альтернативных решения:

  • растрировать SVG
  • преобразовать пути и круги в GPolygons

Но мне не очень нравится первое решение из-за низкого качества растрового изображения и времени его создания с помощью сглаживания.

И для второго решения дуги, эллипсы и круги должны быть разложены на небольшие полилинии. Многие из них будут необходимы для хорошего результата. Но у меня есть около 3000 дуг и кругов, чтобы ...

    
задан ThibThib 28.06.2009 в 19:49
источник
  • Какой замечательный вопрос. Я чувствую, что ваш второй подход не будет выполняться, но не решайтесь ответить, не подтверждая, как gmaps выполняет этот объем полилиний. Я с нетерпением жду, чтобы посмотреть, как это происходит. –  RedBlueThing 29.06.2009 в 00:43
  • Может ли быть так, что GGroundOverly использует фоновые изображения CSS? FF не обрабатывает (пока 3.5) SVG в качестве фона. –  Boldewyn 30.06.2009 в 11:18
  • Я просто пробовал с FF 3.5, но он тоже не работает. Фактически, когда я просматриваю загруженные носители (Tools / Info / Media), мой SVG не загружается вообще ... –  ThibThib 30.06.2009 в 12:24
  • GGroundOverlays не использует фоновые изображения CSS. Просто регулярные img. Я не знаю, почему они не работают. –  Chris B 30.06.2009 в 16:42
  • Вы можете (попытаться) увидеть результат здесь –  ThibThib 30.06.2009 в 17:04

3 ответа

6

Вот некоторые новости (надеюсь, что лучше поставить их здесь в ответ, вместо того, чтобы редактировать мои вопросы или создавать новый вопрос. Пожалуйста, не стесняйтесь перемещать его, если нужно, или рассказывать мне, чтобы я мог исправить):

Моя проблема заключалась в следующем:

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

не работал в Safari 3, Firefox и Opera (IE не позволяет рисовать SVG).

Фактически, этот код создает вставку (в <div> ) следующего элемента

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

И Safari 4 может нарисовать SVG-файл в качестве изображения, но это не способ сделать для другого браузера. Поэтому идея состоит в создании пользовательского наложения для SVG, как описано здесь .

Вот почему я попросил этот вопрос (извините, но HTML / javascript не мои самые сильные стороны).

И поскольку есть небольшая ошибка с Webkit для рендеринга SVG с прозрачным фоном с элементом <object> , мне нужно использовать <object> или <img> соответственно браузеру (мне это не нравится, но. .. на данный момент это все еще быстрые и грязные эксперименты)

Итак, я начал с этого кода (все еще работает):

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

...

Функция draw еще не написана.

У меня все еще есть проблема (я прогрессирую медленно, благодаря тому, что я читаю / учил везде, а также благодаря людям, которые отвечают на мои вопросы).

Теперь проблема заключается в следующем: с тегом <object> карта не перетаскивается. Во всем элементе <object> указатель мыши не является «символом руки», чтобы перетащить карту, а просто обычным указателем.

И я не нашел, как исправить это. Должен ли я добавить новое событие мыши (я только что увидел событие мыши при щелчке или добавлении двойного щелчка, но не для перетаскивания карты ...)?

Или есть ли другой способ добавить этот слой, чтобы сохранить возможность перетаскивания?

Спасибо за ваши комментарии и ответы.

PS: Я также пытаюсь добавить один за другим элементы моего SVG, но ... на самом деле ... Я не знаю, как их добавить в дерево DOM. В этом примере SVG считывается и анализируется GXml.parse() , и все элементы с заданным именем тега получаются ( xml.documentElement.getElementsByTagName ) и добавлен в узел SVG ( svgNode.appendChild(node) ). Но в моем случае мне нужно добавить непосредственно дерево SVG / XML (добавить все его элементы), и есть разные теги ( <defs> , <g> , <circle> , <path> и т. Д.). Это может быть проще, но я не знаю, как это сделать ..: (

    
ответ дан ThibThib 02.07.2009 в 23:59
6

Я провожу последний вечер по этой проблеме, и я наконец нашел решение своей проблемы.

Это было не так сложно.

Идея заключается в том, что, как сказал Крис Б., загрузить файл SVG с помощью GDownloadUrl, проанализировать его с помощью GXml.parse () и добавить в дерево DOM все элементы SVG, которые мне нужны

Чтобы упростить, я предположил, что все элементы SVG были помещены в большую группу под названием «mainGroup». Я также предположил, что некоторые элементы могут быть в файле.

Итак, вот библиотека, на основе пользовательских надписей 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";
}

И вы можете использовать его со следующим кодом:

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

Таким образом, вы можете использовать его точно так же, как вы используете функцию GGroundOverlay , за исключением того, что ваш SVG-файл должен быть создан с проекцией Меркатора (но если вы примените его на небольшой территории, например, в одном городе или меньше, вы не будете см. разницу).

Это должно работать с Safari, Firefox и Opera. Вы можете попробовать мой небольшой пример здесь

Расскажите мне, что вы думаете об этом.

    
ответ дан ThibThib 05.07.2009 в 02:01
  • Удивительный пример! –  Joseph Lust 09.06.2012 в 06:44
2

Этот вопрос был кратко обсужден на странице Группа API Карт Google . Вот что они сказали:

  

Я не пробовал, но SVG - это подмножество   XML, поэтому вы можете прочитать их с помощью   GDownloadUrl () и проанализировать их с помощью   GXml.parse (). На некоторых неуклюжих веб-серверах   вам может потребоваться изменить файл   расширение для XML.

     

Затем вам нужно просканировать через XML   DOM, написание SVG, который вы найдете   с document.createElementNS () и   .setAttribute () вызывает ...

Также есть несколько примеров SVG для Google Maps здесь и here .

Удачи!

    
ответ дан Chris B 29.06.2009 в 16:41
  • Хорошо, спасибо за ссылку. Да, возможно, я могу загрузить файл, проанализировать его и вставить по одному все мои элементы SVG. Я попытаюсь, даже если это решение не убедит меня ... И я уже могу загрузить в один шаг GGroundOverlay («test.svg», границы), но только с Safari 4 ... Я расскажу вам, как это идет –  ThibThib 29.06.2009 в 18:02