如何在Google地图上叠加SVG图表?

Thi*_*hib 17 javascript svg google-maps

我想在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);
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,它适用于Safari 4,但它不适用于Firefox(使用Safari 3,背景不透明).

有没有人知道如何覆盖SVG?

PS1:我喜欢读一些作品或swa.ethz.ch/googlemaps的源代码,但似乎他们必须使用JavaScript代码来分析SVG并添加一个所有元素一个(但我没有理解所有来源...).

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

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

但我真的不喜欢第一种解决方案,因为位图的质量很差,而且生成抗锯齿的时间也是如此.

对于第二种解决方案,弧,椭圆和圆必须分解成小的折线.为了取得好成绩,很多都是必要的.但是我有大约3000个圆弧和圆圈来绘制,所以......

Thi*_*hib 6

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

我的问题如下:

var oldmap = new GGroundOverlay("test.svg", boundaries);
map.addOverlay(oldmap);
Run Code Online (Sandbox Code Playgroud)

没有在Safari 3,Firefox和Opera上运行(IE无法绘制SVG).

实际上,此代码生成<div>以下元素的插入(在a中)

<img src="test.svg" style=".....">
Run Code Online (Sandbox Code Playgroud)

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

...
Run Code Online (Sandbox Code Playgroud)

draw功能尚未编写.

我仍然有一个问题(我进展缓慢,感谢我在任何地方阅读/学习,也感谢回答我问题的人).

现在,问题如下:使用<object>标记,地图不可拖动.在整个<object>元素中,鼠标指针不是拖动地图的"手形图标",而只是普通指针.

我没有找到如何纠正这一点.我应该添加一个新的鼠标事件(我只是在点击或双击附加时看到鼠标事件,但不是用于拖动地图......)?

或者是否有另一种方法来添加此图层以保持拖动能力?

感谢您的意见和解答.

PS:我也尝试逐个添加SVG的元素,但实际上......我不知道如何在DOM树中添加它们.在此示例中,读取并解析SVG GXml.parse(),并获取具有给定标记名称的所有元素(xml.documentElement.getElementsByTagName)并将其添加到SVG节点(svgNode.appendChild(node)).但对我来说,我需要直接添加SVG/XML树(添加其所有元素),并有不同的标记(<defs>,<g>,<circle>,<path>,等).它可能更简单,但我不知道该怎么办.. :(


Thi*_*hib 6

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

这并不困难.

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

为了简化,我认为所有SVG元素都放在一个名为"mainGroup"的大组中.我还假设某些元素可以在文件中.

这是基于Google地图自定义叠加层的库:

// 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";
}
Run Code Online (Sandbox Code Playgroud)

并且,您可以使用以下代码:

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);
}   
Run Code Online (Sandbox Code Playgroud)

因此,您可以完全按照使用该GGroundOverlay功能的方式使用它,除了您的SVG文件应该使用墨卡托投影创建(但如果您将其应用于小区域,例如一个城市或更小的区域,您将看不到差异).

这适用于Safari,Firefox和Opera.你可以在这里尝试我的小例子

告诉我你怎么看待它.