17

我想在 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:我看了一些类似这样的作品或者swa.ethz.ch/googlemaps的源代码,但似乎他们必须使用JavaScript代码来解析SVG并将所有元素一一添加(但我没有全部理解来源...)。

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

  • 栅格化 SVG
  • 转换 GPolygons 中的路径和圆

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

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

4

3 回答 3

6

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

我的问题如下:

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

不适用于 Safari 3、Firefox 和 Opera(IE 无法绘制 SVG)。

事实上,这段代码产生了<div>以下元素的插入(在 a 中)

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

Safari 4 能够将 SVG 文件绘制为图像,但这不是其他浏览器的方式。所以现在的想法是为 SVG 创建一个自定义叠加层,如此所述。

这就是我问这个问题的原因(很抱歉,HTML/javascript 不是我的强项)。

而且由于Webkit存在一个小错误,<object>用于渲染具有透明背景的 SVG -肮脏的实验)<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>等)。它可能更简单,但我不知道该怎么做.. :(

于 2009-07-02T21:59:59.820 回答
6

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

这不是那么困难。

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

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

所以这里是图书馆,基于谷歌地图自定义叠加

// 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。你可以在这里试试我的小例子

告诉我你怎么看。

于 2009-07-05T00:01:01.587 回答
2

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

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

然后,您必须遍历 XML DOM,编写使用 document.createElementNS() 和 .setAttribute() 调用找到的 SVG...

这里这里还有一些 Google Maps SVG 示例。

祝你好运!

于 2009-06-29T14:41:15.553 回答