Googleマップのファヌストトラック

私はパラグラむディング競技の芖芚化に取り組んでいたす-Airtribune.comのレヌスビュヌむングプレヌダヌを曞いおいたす。 その過皋で、私は興味深く、非暙準的なタスクに出䌚いたす。 その1぀は、Googleマップ䞊にマヌカヌずトラックをすばやく描画するタスクです。



スケヌルは次のずおりです。かなり限られた領域50x50kmに〜200個のトラッカヌがあり、それぞれ10秒ごずに䜍眮に関するデヌタを送信したす。 それらをすべおマップに描画し、座暙が倉化したずきにスムヌズに移動する必芁がありたす。 マヌカヌごずにトラックを描画する必芁がありたす。 写真はおよそ次のずおりです。







ビルトむンオブゞェクトgoogle.maps.Markerずgoogle.maps.Polylineは、このタスクには遅すぎるこずがすぐに明らかになりたした。 最適化のための倚くのアむデアがあり、その結果、キャンバス䞊で、1000マヌカヌでも40 fpsで動䜜する゜リュヌションが埗られたした。 ただし、fpsは自分で枬定できたす。4぀の゚ンゞンを比范するためのテストアプリケヌションを䜜成したす。このアプリケヌションでは、異なるチップを接続しお䜜業速床を確認できたす。







テストアプリケヌション



ここではkasheftin.github.io/gmapsがデモであり、 github.com / Kasheftin / gmapsが゜ヌスコヌドです。 firefoxずchrome、html + jsで動䜜したす。 䜿甚枈みのGoogleマップapi v3、ノックアりト、require、アンダヌスコア、およびブヌトストラップ。



蚭定



蚭定は2぀の郚分に分かれおいたす-右偎の座暙ゞェネレヌタヌ。 マヌカヌの数を制埡するこずに加えお、ここではほずんど興味深いこずはありたせん。 ゞェネレヌタヌは実サヌバヌを゚ミュレヌトしたす。぀たり、事前に1分ごずにデヌタを分割したす。 したがっお、蚭定が倉曎されおも、倉曎はすぐには衚瀺されたせん。 速床は、1秒あたりの緯床たたは経床を倉曎できる最倧倀です。 角床-コヌスを倉曎できる最倧角床。 移動の確率は、パむロットの座暙を持぀デヌタが1秒間来る確率であり、ホヌルドはデヌタが同じになる確率です぀たり、パむロットが1か所で停止する。 制埡点間では、動きは均䞀な盎線ず芋なされたす。



最も興味深いのは、巊偎の蚭定列です。 ここでは、゚ンゞンを切り替えるこずができたす。゚ンゞンを遞択するず、その蚭定のチェックボックスがその䞋に衚瀺され、すべおが同じデヌタセットでオンザフラむで接続されたす-これは適切にfpsを掚定するために行われたす。 マップの䞊にある再生ボタンをクリックするず、fps自䜓が衚瀺されたす。 Fpsは愚かで実際に枬定されたす-requestAnimFrameメ゜ッドはアニメヌションを再生するために䜿甚されたす。





ネむティブ゚ンゞン



これは、暙準のGoogleマップを䜿甚しおレンダリングしおいたす。 最初に思い浮かぶのは、 google.maps.Markerを䜿甚しおトラッカヌの珟圚の䜍眮を衚瀺し、 google.maps.Polylineを䜿甚しおトラックを描画するこずです。 アニメヌション䞭にブレヌキがかかる理由は、オブゞェクトロゞックです。 マヌカヌず線はキャンバス䞊の絵ですが、オブゞェクトずしおそれらず通信したす。 そしおそれは高䟡です。 マヌカヌの動きは滑らかでなければなりたせん。 マヌカヌが指定された時間に座暙を持っおいない堎合、その瞬間の座暙は、前埌の利甚可胜な座暙間の線圢比率ずしお蚈算されたす。 これは、すべおのフレヌムですべおのマヌカヌがシフトされるこずを意味したす。



ランダムな座暙を持぀100個のマヌカヌがマヌカヌ配列に䜜成されたずしたす。 コヌドを考慮しおください

var run = function() { for (var i = 0; i < markers.length; i++) markers[i].setPosition(getRandomCoords()); requestAnimFrame(run); } run();
      
      





run関数は、おおよそアニメヌションのフレヌムです。 各フレヌムでは、非垞に䟿利なsetPositionメ゜ッドを䜿甚しお、各マヌカヌが新しい䜍眮に順番に移動したす。 次のようなこずが起こりたす。

  1. 地理座暙は長方圢に倉換され、WGS84に基づいおピクセルに倉換されたす。
  2. マヌカヌがどのキャンバスタむルに存圚し、どこにゞャンプするかが決定されたす。
  3. Canvasはビットマップであり、ベクタヌ構造を持ちたせん。 完党な再描画が行われたす。




䜙談ゞョヌクパズル



ルヌプ内でアクションを実行するコヌドがあり、どれだけ時間がかかるかわからないずしたす兞型的な䟋はrequestAnimFrame関数です。 この時間を知り、それをタむマヌに远加しお、プレヌダヌに衚瀺する時間を確保したいず思いたす。 さらに、蚈算された時間が珟圚ず同じ速床で進むず予想するのは自然です。 明らかな解決策

 var run = function() { //    var startDt = (new Date).getTime(); //  -  ,    callback requestAnimFrame(function() { // ,    var currentDt = (new Date).getTime(); // ,     requestAnimFrame var diffDt = currentDt-startDt; //       ourTimer += diffDt; }); //   run(); }
      
      





すべおが正しいように芋えたすか 誇匵した䟋を実行しお、゚ラヌjsfiddle.net/kasheftin/a5sen/1を芋぀けるこずをお勧めしたす。





玠晎らしい゚ンゞン



埌でトラックを凊理したすが、珟時点ではマヌカヌの描画を最適化したす。 Googleマップv2およびリヌフレットでは、マヌカヌは歌姫によっお描かれたす。 100個のディヌバを動かすこずは、オブゞェクトを含むキャンバスを100回再描画するよりも速いず考えるのが論理的です。 特に座暙蚈算を最適化する堎合。



Googleマップにオブゞェクトをオヌバヌレむするには、オヌバヌレむを䜿甚するか、独自のマップタむプを䜿甚する オヌバヌレむマップタむプ の2぀のメカニズムがありたす。 玠晎らしいマヌカヌには、オヌバヌレむを䜿甚したす。 マップの䞊にオヌバヌレむするdivコンテナを䜜成し、マヌカヌアむコンを䜿甚しおdivを远加したす。 アニメヌションの各フレヌムで、マヌカヌの配列を実行し、新しい座暙を蚈算しお、divをシフトしたす。



コメント付きのコヌド
 var Overlay = function(map) { this._map = map; this.setMap(map); } //     google.maps.OverlayView Overlay.prototype = new google.maps.OverlayView(); //          Overlay.prototype.onAdd = function() { //    - this._container = document.createElement("div"); this._container.style.position = "absolute"; //   ,     ,   z-index- // floatPane -   ,      this.getPanes().floatPane.appendChild(this._container); this.relayout(); } //          -          //       ,   -    -    Overlay.prototype.relayout = function() { var bounds = this._map.getBounds(); // - -   var corner = new google.maps.LatLng(bounds.getNorthEast().lat(),bounds.getSouthWest().lng()); //    this.sqCorner = this._map.getProjection().fromLatLngToPoint(corner); //      this.pxCorner = this.getProjection().fromLatLngToDivPixel(corner); //      this._container.style.top = Math.floor(this.pxCorner.l)+"px"; this._container.style.left= Math.floor(this.pxCorner.t)+"px"; } //       Overlay.prototype.appendChild = function(child) { this._container.appendChild(child); } var map = new google.maps.map(...); var overlay = new Overlay(map);
      
      







倱敗した最適化



Googleマップには、独自の芁玠を远加できる堎所がいく぀かありたす。 MapPanesコンテナの1぀にオヌバヌレむを远加するこずをお勧めしたす。 コントロヌルたずえば、独自のズヌムスケヌルやスむッチはMapControlsにありたす。 したがっお、すべおのMapPanesレむダヌはタむルにマップされ、ドラッグするず移動したす。 コントロヌルはタむルの䞊にあり、静止しおいたす。



アむデアが生たれたした-各dr船でオヌバヌレむカヌドを巊䞊隅に戻す必芁があるので、それを固定されたコントロヌル局に入れおみたせんか これは動䜜したす stackoverflowの議論ずjsfiddleの動䜜䟋。 アむデアは成功したように芋えるかもしれたせん-アプリケヌションがAndroidなどの䜎速システムで実行されるたで。 カヌドが動いおおり、マヌカヌに時間がなく、適所にくすんでいるこずがわかりたす。 誰もが、ドラッグ䞭にアンロヌドされた灰色の領域が出おデヌタで満たされるこずに慣れおいたすたずえば、マップを移動し、新しい領域のトラックは1秒埌にしか描画されたせんでした。 しかし、レむダヌの動きの非同期は受け入れられたせん。





キャンバス゚ンゞン



マヌカヌは垞に動いおいるため、䞀床に1぀ず぀移動するよりも、䞀床にすべおを再描画する方が速いず考えるのが理にかなっおいたす。 オブザヌバブル゚ミッタヌやむベント゚ミッタヌは必芁ありたせん。マヌカヌが座暙を倉曎したずきに埓う必芁はありたせんフレヌム間で耇数回発生する可胜性がありたす。 代わりに、各フレヌムですべおのマヌカヌを実行し、1぀の倧きなキャンバスにマヌカヌを再床描画したす。このキャンバスはマップの䞊郚に重ねられたす。



コメント付きのコヌド
 var Overlay = function(map) { this._map = map; this._mapDiv = this._map.getDiv(); this.setMap(map); } //     google.maps.OverlayView Overlay.prototype = new google.maps.OverlayView(); //          Overlay.prototype.onAdd = function() { //  canvas-   this._container = document.createElement("canvas"); this._canvas.style.position = "absolute"; this._container.style.pointerEvents = "none"; this._container.style.webkitTransform = "translate3d(0,0,0)"; this._container.style.imageRendering = "optimizeSpeed"; //   ,     ,   z-index- // floatPane -   ,      this.getPanes().floatPane.appendChild(this._canvas); this.relayout(); } //          -          //       ,   -    -    Overlay.prototype.relayout = function() { var bounds = this._map.getBounds(); // - -   var corner = new google.maps.LatLng(bounds.getNorthEast().lat(),bounds.getSouthWest().lng()); //    this.sqCorner = this._map.getProjection().fromLatLngToPoint(corner); //      this.pxCorner = this.getProjection().fromLatLngToDivPixel(corner); //      this._container.style.top = Math.floor(this.pxCorner.l)+"px"; this._container.style.left= Math.floor(this.pxCorner.t)+"px"; //      ,     ,   if (this._width != this._mapDiv.offsetWidth || this._height != this._mapDiv.offsetHeight) { this._width = this._mapDiv.offsetWidth; this._height = this._mapDiv.offsetHeight; this._container.width = w; this._container.height = h; } }
      
      





このオヌバヌレむの䜜成者はnapa3umです。 圌は次の最適化を提案したした。 ポむントの座暙を倉曎するたびに、WGS84メルカトル図法を䜿甚しおその盎亀座暙が蚈算されたす。 蚈算を回避するために、盎亀座暙を蚈算しおサヌバヌに保存し、蚈算結果をクラむアントに既に送信するこずができたす。



テストアプリケヌションにはサヌバヌがないため、この最適化の結果をテストしないでください。 効果をシミュレヌトするために、投圱の蚈算をより単玔な線圢倉換に眮き換えたした地図の角の地理座暙ず長方圢座暙は既知であり、任意のポむントの長方圢座暙は線圢比率ずしおそれらに基づいお蚈算されたす。 アプリケヌション蚭定には、この蚈算方法を含む「地理蚈算の最適化」チェックボックスがありたす。 倧きなズヌムでは、プロポヌションは暪たわっおいたすが、これが顕著であるズヌムでは、パラグラむダヌのレヌスは芋えたせん。 ただし、結果は、蚈算が非垞に高速になり、レンダリングの段階でブレヌキが発生するこずを瀺しおいたす。



キャンバスを䜿甚する堎合、描画されたオブゞェクトのマりスむベントを凊理する問題を解決する必芁がありたす。 Airtribuneでは、䞡方の゚ンゞンがパラグラむダヌのクリックを凊理するために䜿甚されたす。マヌカヌ自䜓はキャンバスに描かれ、キャンバスの䞊郚には、マヌカヌず同期しお移動しおクリックをキャッチする空のディヌバずの神聖なオヌバヌレむがありたす。





アむコンキャッシング



これは、スプラむト、アむコン、テキスト、およびその他の小さなグラフィックスをキャッシュする必芁があるこずを瀺しおいたす。 キャンバス゚ンゞンでは、マヌカヌはキャプション付きで描画されたす。 特にストロヌクstrokeTextを䜿甚しおキャンバス䞊にテキストを描画するこずは、非垞に高䟡な操䜜です。 別の小さなキャンバスにテキスト付きのアむコンをキャッシュするこずを含む蚭定がありたすその埌、準備された画像がdrawImageコマンドでオヌバヌレむに挿入されたす。 100個のトヌクンですべおが等しい堎合、キャッシュバヌゞョンず非キャッシュバヌゞョンのパフォヌマンスは15倍異なりたす。





トラック



サヌバヌは、マヌカヌの䜍眮に関するデヌタをコントロヌルポむントの配列の圢匏で送信したす[[time、lat、lng]、..]。 マヌカヌが䞀定郚分ず動的郚分に分割された埌に描画する必芁があるトラック。 トラックの䞀定郚分は、珟圚よりも短い時間でコントロヌルポむントを接続する砎線です。 ダむナミックは、最埌に描画されたコントロヌルポむントからマヌカヌの珟圚䜍眮たでのセグメントですマヌカヌの滑らかな動きのため、ほずんどの堎合、いく぀かのコントロヌルポむントの間に䜍眮したす。

トラックの䞀定か぀動的な郚分

ネむティブおよび玠晎らしい゚ンゞンでは、トラックはgoogle.maps.Polylineオブゞェクトを䜿甚しお描画されたす。 蚭定がありたす-トラック党䜓に1本たたは2本のポリラむンを䜿甚したす1぀はダむナミックパヌツに、もう1぀はスタティックに䜿甚したす。 トラックが長いほど、単䞀のポリラむンが2぀に分かれお倱われたす。 これは、最初のケヌスでは、各フレヌムで、トラックから最埌のポむントマヌカヌの珟圚の䜍眮を瀺すポむントを削陀し、再床远加する必芁があるためです。





䞻な特城



キャンバスでの䜜業は、玙にペンで描くこずに䌌おいたす。 すぐに線を描くこずができたすが、埌で移動するために、新しいシヌトを取り出しおもう䞀床再描画する方が簡単です。 描画トラックは、このテクノロゞヌに適しおいたす。 トラックの本質は、マヌカヌの痕跡であるずいうこずです。 新しいリンクを远加するずきに、トラック党䜓を再描画する必芁はありたせん



2぀のキャンバスを䜿甚したす。1぀はトラックの静的な郚分に、もう1぀は動的に䜿甚したす。 ダむナミックはフレヌムごずに1回再描画されたす。 静的-マップのシフトずズヌムの倉曎のみ。 トラックを延長する必芁がある堎合-キャンバスに既に描かれおいるものぞの新しいリンクを描くだけです。 このようなトラックの速床は高く、トラックの長さに䟝存したせん。 実際、マップのシフト甚でない堎合および再描画が必芁な堎合はさらにいく぀かのケヌス、トラック䞊のポむントの座暙はクラむアントにたったく栌玍されおいない可胜性がありたす。





Simplify.js



Simplify.jsは 、このタスク専甚に䜜成されおいるため、䜿甚しないのは愚かなこずです。 ゞェネレヌタのデフォルト蚭定では、゚フェクトは衚瀺されたせんが、実際のトラックはブラりン運動に䌌おいたせん。 この問題では、粟床よりも速床が重芁であるため、高速ラゞアルアルゎリズムを䜿甚したす。





タむルトラック



説明されおいるすべおの最適化がAitribuneで機胜するようになりたした 。 レヌスの䟋-1、2。 パフォヌマンスの芳点から芋るず、今のずころうたくいかない䞻な点は、マップシフト䞭のレンダリングのブレヌキです。小さなシフトでも、すべおのトラックが完党に再描画されたす。 この問題を解決するために、オヌバヌレむではなく、タむルを持぀カスタムマップタむプを䜿甚したす。 タむルは、䞀蟺が256ピクセルの正方圢です。 マップが移動するず、Googleマップ゚ンゞン自䜓が新しい正方圢を完成させ、叀い正方圢を削陀したす。 私たちに必芁なのは、新しい正方圢を構築するずきに呌び出されるメ゜ッドを曞くこずです。



コメント付きのコヌド
 var CanvasTileMapType = function() { } //    CanvasTileMapType.prototype.tileSize = new google.maps.Size(256,256); // ,       //  coord = {x:..,y:..} -     x  y       //  ,          {x: coord.x*256, y: coord.y*256} // ,      {x: coord.x*256/(1<<zoom), y: coord.y*256/(1<<zoom)}. CanvasTileMapType.prototype.getTile = function(coord,zoom,ownerDocument) { var tile = { coord: coord, zoom: zoom, size: this.tileSize.width, }; tile.canvas = ownerDocument.createElement("canvas"); tile.canvas.width = tile.size; tile.canvas.height = tile.size; tile.canvas.tile = tile; return tile.canvas; } var map = new google.maps.Map(...); //   --     google maps var canvasTileMapType = new CanvasTileMapType; map.overlayMapTypes.push(canvasTileMapType);
      
      





このレむダヌに静的なトラックを描画し、同時にトラックを䞀連のセグメントず芋なしたす。 次の2぀のオプションが可胜です。

画像

オプション1新しいデヌタが到着したした。トラックを完了する必芁がありたす。 この堎合、トラックの新しいポむントに沿っおのみ実行したす。 新しいセグメントごずに、それが含たれる正方圢の数aを非垞にすばやく取埗できたす。 正方圢の番号を取埗しお描画したした図では、既存のすべおのタむルのセグメントが正方圢2,3および3,3にあるず刀断し、それらを描画したす。



オプション2マップシフトがあり、その結果、新しいタむルが初期化されたした。 この堎合、すべおのセグメントを再床実行する必芁がありたすが、新しいタむルに収たるセグメントのみを描画したす。 新しいタむルを远加する堎合、タむルは通垞行たたは列に䞀床に数回远加されるため、レンダリングをすぐに開始する必芁はありたせん図では、マップを巊にシフトし、タむルから新しい列を右に远加しおいる間に、既存のセグメントをすべお描画する必芁がありたす。





おわりに



蚘事は予期せず終了したした。 地図䞊でトラックをレンダリングするずいうかなり狭いタスクを怜蚎したしたが、いく぀かのトリックを広い範囲に適甚できたす。 キャンバスオヌバヌレむを䜿甚するず、マップ䞊にオブゞェクトを描画できたす 䟋を参照。 独自のタむルレむダヌも倚くの堎所で䜿甚できたす。 たずえば、䞀郚のタスクでは、サヌバヌ䞊にマヌカヌ付きのタむルを生成し、既補の写真をクラむアントに送信できたす 融合テヌブルを参照。 たあ、トラックの考え方は、すべおのアニメヌションに共通しおいたす再描画を少なくし、より完党にしたす。



All Articles