1

LeafletJS を使用してマップを操作する AngularJS でアプリを構築しています。これは、私がフェーズと呼ぶものに分かれたさまざまな可能な操作を提供します。これらの各フェーズには、UIRouterコントローラーとテンプレートを備えた状態があります。

私は現在、サービスを通じてリーフレット機能を提供しています。アイデアは、そのサービスが Leaflet マップを初期化し、状態のコントローラーへの制限されたアクセスを提供することでした。setupMarkersInteractionsしたがって、これらのコントローラーは、たとえばマップ上にマーカーを配置できるようにするコールバックをセットアップするなどのサービス関数を呼び出します。

ただし、Leaflet のleaflet.map()関数を使用してマップを初期化するときに問題が発生していますError: Map container not found。これは、Leaflet がマップを関連付ける HTML 要素を見つけられないことに関連しています。

現在、私はちょっとこれをやっています:

function mapService() { 
  var map;

  return {
    initializeMap : initializeMap,
    setupMarkersInteractions : setupMarkersInteractions
  };

  function initializeMap() {
    map = leaflet.map('map');
  }

  function setupMarkersInteractions() {
    map.on('click', markerPlacementCallback);
  }
}

このinitializeMap関数は、状態のテンプレートで宣言されている をleaflet.map含む HTML 要素を探すように指示します。id='map'

さて、実際の質問ですが、これはある種のAngularJS サービスが HTML テンプレートにアクセスできないことに関連していますか? 問題については何も見つかりませんでしたが、サービスがビューに直接アクセスしないことは理にかなっていると思いました...
もしそうなら、どのような回避策を探るべきですか? を調べましたがleaflet-directive、希望する柔軟性でカスタム コールバックを追加および削除する可能性はないようです (たとえば、Leaflet-Freedraw を使用して無料の描画機能を追加すると、複雑になります)。

leaflet.map要素の引数を使用して直接使用することを検討しHTMLElementましたが、それでも機能させることができませんでした-想定されているものを渡していない可能性があります.

4

1 に答える 1

5

何が起こっているかというL.Mapと、サービスから DOM にアクセスしようとしている時点で、テンプレートはまだ利用可能です。通常、サービスはコントローラに読み込まれて挿入され、コントローラはそのスコープを初期化し、その後テンプレートが初期化されて DOM に追加されます。マップの初期化に大きなタイムアウトを設定すると、それが DOM 要素であることがわかります。しかし、それは非常に醜いハックです。Angular では、ディレクティブを使用してロジックを DOM 要素に追加する必要があります。

たとえば、 template: は<leaflet></leaflet>非常に基本的なディレクティブです:

angular.module('app').directive('leaflet', [
  function () {
    return {
      replace: true,
      template: '<div></div>',
      link: function (scope, element, attributes) {
        L.map(element[0]);
      }
    };
  }
]);

それをサービスにフックして、要素を初期化メソッドに渡すことができます。

angular.module('app').directive('leaflet', [
           'mapService'
  function (mapService) {
    return {
      replace: true,
      template: '<div></div>',
      link: function (scope, element, attributes) {
        mapService.initializeMap(element[0]);
      }
    };
  }
]);

そうinitializeMapすれば、実際の DOM 要素が利用可能になったときにのみメソッドが呼び出されます。しかし、それは別の問題を提示します。コントローラーが初期化された時点では、サービスはまだ準備ができていません。promise を使用してこれを解決できます。

angular.module('app').factory('leaflet', [
             '$q',
    function ($q) {
        var deferred = $q.defer();
        return {
          map: deferred.promise,
          resolve: function (element) {
            deferred.resolve(new L.Map(element));
          }
        }
    }
]);

angular.module('app').directive('leaflet', [
           'leaflet',
  function (leaflet) {
    return {
      replace: true,
      template: '<div></div>',
      link: function (scope, element, attributes) {
        leaflet.resolve(element[0]);
      }
    };
  }
]);

コントローラーでマップ インスタンスを使用する場合は、解決されるまで待つことができます。

angular.module('app').controller('rootController', [
           '$scope', 'leaflet',
  function ($scope,   leaflet) {
    leaflet.map.then(function (map) {
      var tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
        maxZoom: 18
      }).addTo(map);
      map.setView([0, 0], 1);
      L.marker([0, 0]).addTo(map);
    });
  }
]);

Plunker の概念の例を次に示します: http://plnkr.co/edit/DoJpGqtR7TWmKAeBZiYJ?p=preview

于 2015-11-30T14:23:37.477 に答える