17

Google マップにオーバーレイ画像を追加したいと考えています。画像は、私が生成した SVG ファイルです (Python with 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 を解析し、すべての要素を 1 つずつ追加する必要があるようです (ただし、すべてを理解したわけではありません)。起源...)。

PS2: SVG は、透明度のあるさまざまな塗りつぶされたパスと円で構成されています。SVG をオーバーレイするソリューションがない場合は、2 つの代替ソリューションを使用できます。

  • SVG をラスタライズする
  • GPolygons のパスと円を変換します

しかし、ビットマップの品質が悪く、アンチエイリアシングで生成する時間がかかるため、最初のソリューションはあまり好きではありません。

2 番目のソリューションでは、円弧、楕円、および円を小さなポリラインに分解する必要があります。良い結果を得るには、それらの多くが必要になります。でも描く円弧や円は3000くらいあるので…

4

3 に答える 3

6

私はこの問題に最後の夜を費やし、ついに私の問題の解決策を見つけました。

それほど難しくありませんでした。

Chris B. が言ったように、アイデアは、GDownloadUrl で SVG ファイルをロードし、GXml.parse() で解析し、必要なすべての SVG 要素を DOM ツリーに追加することです。

簡単にするために、すべての 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);
}   

そのため、SVG ファイルをメルカトル図法で作成する必要があることを除いて、関数を使用するのとまったく同じように使用できますGGroundOverlay(ただし、1 つの都市またはそれよりも小さい領域などの小さな領域に適用する場合、違いはわかりません)。

これは、Safari、Firefox、Opera で動作するはずです。ここで私の小さな例を試すことができます

それについてどう思うか教えてください。

于 2009-07-05T00:01:01.587 に答える
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 は私の得意分野ではありません)。

<object>また、要素を持つ透明な背景を持つ SVG をレンダリングするための Webkit には小さなバグがあるため、ブラウザーに応じて<object>orを使用する必要があります<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 の要素を 1 つずつ追加しようとしていますが、実際には... DOM ツリーにそれらを追加する方法がわかりません。このでは、SVG が で読み取られて解析され、指定さGXml.parse()れたタグ名を持つすべての要素が取得され ( xml.documentElement.getElementsByTagName)、SVG ノードに追加されます ( svgNode.appendChild(node))。しかし、私の場合は、SVG/XML ツリーを直接追加する (すべての要素を追加する) 必要があり、さまざまなタグ ( <defs><g><circle><path>など) があります。もっと簡単かもしれませんが、やり方がわかりません.. :(

于 2009-07-02T21:59:59.820 に答える
2

この質問は、 Google Maps API Groupで簡単に議論されました。彼らが言ったことは次のとおりです。

試したことはありませんが、SVG は XML のサブセットであるため、GDownloadUrl() で読み取り、GXml.parse() で分析できます。一部の不安定な Web サーバーでは、ファイル拡張子を XML に変更する必要がある場合があります。

次に、XML DOM をクロールし、document.createElementNS() および .setAttribute() 呼び出しで見つけた SVG を作成する必要があります...

Google マップの SVG の例もここここにあります。

幸運を!

于 2009-06-29T14:41:15.553 に答える