代码之家  ›  专栏  ›  技术社区  ›  ThibThib

如何在Google地图上覆盖SVG图表?

  •  17
  • ThibThib  · 技术社区  · 15 年前

    我想在谷歌地图上添加一个覆盖图。该图像是我生成的一个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

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

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

    对于第二种解决方案,圆弧、椭圆和圆必须分解为小的多段线。要想取得好的成绩,他们中的很多人都是必不可少的。但我有大约3000个弧和圆要画,所以。。。

    3 回复  |  直到 13 年前
        1
  •  6
  •   Community Mofi    7 年前

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

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

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

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

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

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

    这就是我为什么要这样做的原因 this question (很抱歉,HTML/javascript不是我的强项)。

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

    我仍然有一个问题(我进步缓慢,这要感谢我在各地读到的东西,也要感谢那些回答我问题的人)。

    <对象> 标记,地图不可拖动。到处 <对象>

    我没有发现如何纠正这一点。我应该添加一个新的鼠标事件(我只是在单击或双击附加时看到鼠标事件,但不是为了拖动地图…)?

    或者是否有其他方法添加此层以保持拖动能力?

    this example ,使用 GXml.parse() ,并获得具有给定标记名的所有元素( xml.documentElement.getElementsByTagName )并添加到SVG节点( svgNode.appendChild(node) )但是在我的例子中,我需要直接添加SVG/XML树(添加其所有元素),并且有不同的标记( <defs> , <g> , <circle> <path> 等)。这可能更简单,但我不知道怎么做(

        2
  •  6
  •   ThibThib    15 年前

    我花了最后一个晚上研究这个问题,终于找到了解决问题的办法。

    这并不难。

    为了简化,我假设所有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

    告诉我你怎么看。

        3
  •  2
  •   Chris B    15 年前

    会议上简要讨论了这个问题 Google Maps API Group . 他们是这么说的:

    我没有尝试过,但是SVG是一个子集 XML,因此您可以使用 GDownloadUrl()并使用 GXml.parse()。在一些不可靠的Web服务器上 您可能必须更改该文件 对XML的扩展。

    然后必须在XML中爬行 DOM,编写您找到的SVG 使用document.createElements()和 .setAttribute()调用。。。

    here here .