【问题标题】:How can I overlay SVG diagrams on Google Maps?如何在 Google 地图上叠加 SVG 图?
【发布时间】:2010-11-06 12:33:00
【问题描述】:

我想在 Google 地图上添加叠加图像。该图像是我生成的 SVG 文件(带有 SVGFig 的 Python)。

我正在使用以下代码:

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:我读过一些像this或swa.ethz.ch/googlemaps的源代码的作品,但似乎他们必须使用JavaScript代码来解析SVG并一一添加所有元素(但我不明白所有的来源......)。

PS2:SVG 由不同的填充路径和圆圈组成,具有透明度。 如果没有解决方案来覆盖我的 SVG,我可以使用 2 个替代解决方案:

  • 光栅化 SVG
  • 在 GPolygons 中转换路径和圆

但我不太喜欢第一种解决方案,因为位图的质量很差,而且使用抗锯齿生成它需要时间。

对于第二种解决方案,圆弧、椭圆和圆必须分解为小折线。为了获得良好的结果,其中很多都是必要的。但是我有大约 3000 个圆弧和圆要画,所以...

【问题讨论】:

  • 真是个好问题。我的直觉是,您的第二种方法将无法执行,但在没有确认 gmaps 如何使用该数量的折线执行的情况下犹豫回答。我期待着看看这是怎么回事。
  • GGroundOverly 会不会使用 CSS 背景图片? FF 不处理(目前,3.5 将)SVG 作为背景。
  • 我刚刚尝试使用 FF 3.5,但它也不起作用。事实上,当我查看下载的媒体(工具/页面信息/媒体)时,我的 SVG 根本没有加载...
  • GGroundOverlays 不使用 CSS 背景图像。只是普通的img。我不知道为什么它们不起作用。
  • 你可以(尝试)看到结果here

标签: javascript google-maps svg


【解决方案1】:

Google Maps API Group 上简要讨论了这个问题。他们是这样说的:

我没试过,但 SVG 是一个子集 XML的,所以你可以阅读它们 GDownloadUrl() 并用 GXml.parse()。在一些不稳定的网络服务器上 您可能需要更改文件 XML 的扩展。

然后您必须通过 XML 进行爬网 DOM,编写你找到的 SVG 与 document.createElementNS() 和 .setAttribute() 调用...

还有一些 Google Maps SVG 示例 herehere

祝你好运!

【讨论】:

  • 好的,谢谢你的链接。是的,也许我可以加载我的文件,解析它并一一插入我所有的 SVG 元素。我会尝试,即使这个解决方案不能说服我......而且我已经能够使用 GGroundOverlay("test.svg", bounds) 一步加载,但只能使用 Safari 4......我会告诉你如何就这样
【解决方案2】:

这里有一些新闻(我希望最好将它们放在答案中,而不是编辑我的问题或创建一个新问题。如果需要,请随时移动它,或者告诉我,以便我可以纠正):

我的问题如下:

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 创建一个自定义叠加层,正如 here 所解释的那样。

这就是我要求this question 的原因(很抱歉,HTML/javascript 不是我的强项)。

由于 Webkit 存在一个小错误,用于使用 &lt;object&gt;element 渲染具有透明背景的 SVG,我需要根据浏览器使用 &lt;object&gt;&lt;img&gt;(我不喜欢这样,但是。 .. 目前,它仍然是快速而肮脏的实验)

所以我从这段代码开始(仍在进行中):

// 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 函数尚未编写。

我仍然有一个问题(我进步缓慢,这要感谢我到处阅读/学习的内容,也感谢回答我问题的人)。

现在,问题如下:使用&lt;object&gt; 标签,地图不可拖动。在&lt;object&gt;元素上,鼠标指针不是拖动地图的“手形图标”,而是普通的指针。

我没有找到解决方法。我应该添加一个新的鼠标事件吗(我只是在单击或双击追加时看到了鼠标事件,而不是用于拖动地图...)?

或者有没有其他方法可以添加这个层以保持可拖动性?

感谢您的 cmets 和回答。

PS:我也尝试将我的 SVG 的元素一一添加,但是……实际上……我不知道如何将它们添加到 DOM 树中。在this example 中,使用GXml.parse() 读取和解析SVG,并获取所有具有给定标签名称的元素(xml.documentElement.getElementsByTagName)并添加到SVG 节点(svgNode.appendChild(node))。但就我而言,我需要直接添加 SVG/XML 树(添加其所有元素),并且有不同的标签(&lt;defs&gt;&lt;g&gt;&lt;circle&gt;&lt;path&gt; 等)。它可能更简单,但我不知道该怎么做.. :(

【讨论】:

    【解决方案3】:

    我在这个问题上度过了最后一个晚上,我终于找到了解决问题的方法。

    没那么难。

    正如 Chris B. 所说,这个想法是用 GDownloadUrl 加载 SVG 文件,用 GXml.parse() 解析它,然后在 DOM 树中添加我需要的每个 SVG 元素

    为简化起见,我假设所有 SVG 元素都放在一个名为“mainGroup”的大组中。我还假设某些元素可以在文件中。

    所以这里是库,基于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";
    }
    

    而且,您可以将其与以下代码一起使用:

    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。你可以试试我的小例子here

    告诉我你对此有何看法。

    【讨论】:

      猜你喜欢
      • 2019-01-30
      • 1970-01-01
      • 2013-09-08
      • 1970-01-01
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多