【问题标题】:angularjs with Leafletjsangularjs 与 Leafletjs
【发布时间】:2012-10-09 15:28:56
【问题描述】:

以下指令代码来自http://jsfiddle.net/M6RPn/26/ 我想获得一个包含许多经纬度的 json 提要。我可以在 Angular 中轻松获得一个带有 $resource 或 $http 的 json,但是如何将它提供给该指令以在地图上映射事物?

module.directive('sap', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function(scope, element, attrs) {
            var map = L.map(attrs.id, {
                center: [40, -86],
                zoom: 10
            });
            //create a CloudMade tile layer and add it to the map
            L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/997/256/{z}/{x}/{y}.png', {
                maxZoom: 18
            }).addTo(map);

            //add markers dynamically
            var points = [{lat: 40, lng: -86},{lat: 40.1, lng: -86.2}];
            for (var p in points) {
                L.marker([points[p].lat, points[p].lng]).addTo(map);
            }
        }
    };
});

【问题讨论】:

    标签: angularjs leaflet


    【解决方案1】:

    假设在你的控制器中你得到了

    $scope.points = // here goes your retrieved data from json
    

    你的指令模板是:

    <sap id="nice-map" points="points"/>
    

    然后在您的指令定义中,您可以使用“=”符号在指令范围和父范围之间设置双向绑定

    module.directive('sap', function() {
    return {
        restrict: 'E',
        replace: true,
        scope:{
          points:"=points"
        },
        link: function(scope, element, attrs) {
            var map = L.map(attrs.id, {
                center: [40, -86],
                zoom: 10
            });
            L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/997/256/{z}/{x}/{y}.png', {
                maxZoom: 18
            }).addTo(map);
    
            for (var p in points) {
                L.marker([p.lat, p.lng]).addTo(map);
            }
        }
    };
    });
    

    另外,建议先将标记添加到 L.featureGroup,然后再将该 L.featureGroup 添加到地图,而不是将标记直接添加到地图中,因为它有 clearLayers() 方法,这样可以节省您的时间更新标记时有些头疼。

    grupo = L.featureGroup();
    grupo.addTo(map);
    
    for (var p in points) {
        L.marker([p.lat, p.lng]).addTo(grupo);
    }
    
    
    // remove all markers
    grupo.clearLayers();
    

    希望对你有帮助,干杯

    【讨论】:

      【解决方案2】:

      angularJs 中的指令和 mvc 是不同的技术。指令通常在页面加载时执行。指令更多地用于处理/使用 html 和 xml。一旦你有了 JSON,那么最好使用 mvc 框架来工作。

      页面渲染后,要应用指令,您通常需要执行 $scope.$apply() 或 $compile 来注册页面上的更改。

      无论哪种方式,将服务放入指令的最佳方法是使用依赖注入框架。

      我注意到您的指令中缺少 scope:true 或 scope:{}。这对指令与父控制器的配合有很大影响。

      app.directive('mapThingy',['mapSvc',function(mapSvc){
        //directive code here.
      
      }]);
      
      app.service('mapSvc',['$http',function($http){
       //svc work here.
      }])
      

      指令通过驼峰匹配来应用。我会避免使用或因为 IE 的问题。替代方案是

      <div map-thingy=""></div>
      

      【讨论】:

        【解决方案3】:

        我最近使用Angular JSLeaflet 构建了一个应用程序。与您所描述的非常相似,包括来自 JSON 文件的位置数据。我的解决方案类似于blesh

        这是基本过程。

        我的一个页面上有一个&lt;map&gt; 元素。然后我有一个指令,用 Leaflet 映射替换 &lt;map&gt; 元素。我的设置略有不同,因为我在工厂中加载了 JSON 数据,但我已经针对您的用例进行了调整(如果有错误,我们深表歉意)。在指令中,加载您的 JSON 文件,然后遍历您的每个位置(您需要以兼容的方式设置您的 JSON 文件)。然后在每个纬度/经度处显示一个标记。

        HTML

        <map id="map" style="width:100%; height:100%; position:absolute;"></map>
        

        指令

        app.directive('map', function() {
        return {
            restrict: 'E',
            replace: true,
            template: '<div></div>',
            link: function(scope, element, attrs) {
        
                var popup = L.popup();
                var southWest = new L.LatLng(40.60092,-74.173508);
                var northEast = new L.LatLng(40.874843,-73.825035);            
                var bounds = new L.LatLngBounds(southWest, northEast);
                L.Icon.Default.imagePath = './img';
        
                var map = L.map('map', {
                    center: new L.LatLng(40.73547,-73.987856),
                    zoom: 12,
                    maxBounds: bounds,
                    maxZoom: 18,
                    minZoom: 12
                });
        
        
        
                // create the tile layer with correct attribution
                var tilesURL='http://tile.stamen.com/terrain/{z}/{x}/{y}.png';
                var tilesAttrib='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.';
                var tiles = new L.TileLayer(tilesURL, {
                    attribution: tilesAttrib, 
                    opacity: 0.7,
                    detectRetina: true,
                    unloadInvisibleTiles: true,
                    updateWhenIdle: true,
                    reuseTiles: true
                });
                tiles.addTo(map);
        
                // Read in the Location/Events file 
                $http.get('locations.json').success(function(data) {
                    // Loop through the 'locations' and place markers on the map
                    angular.forEach(data.locations, function(location, key){
        
                        var marker = L.marker([location.latitude, location.longitude]).addTo(map);
        
                    });
                });
            }
        };
        

        示例 JSON 文件

        {"locations": [     
        {   
            "latitude":40.740234, 
            "longitude":-73.995715
            }, 
        {   
            "latitude":40.74277, 
            "longitude":-73.986654
            },
        {   
            "latitude":40.724592, 
            "longitude":-73.999679
            }
        ]} 
        

        【讨论】:

          【解决方案4】:

          我不太了解 Leaflet 或您想要做什么,但我假设您想将一些坐标从您的控制器传递给您的指令?

          实际上有很多方法可以做到这一点...其中最好的方法是利用范围。

          这是将数据从控制器传递到指令的一种方法:

          module.directive('sap', function() {
              return {
                  restrict: 'E',
                  replace: true,
                  template: '<div></div>',
                  link: function(scope, element, attrs) {
                      var map = L.map(attrs.id, {
                          center: [40, -86],
                          zoom: 10
                      });
                      //create a CloudMade tile layer and add it to the map
                      L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/997/256/{z}/{x}/{y}.png', {
                          maxZoom: 18
                      }).addTo(map);
          
                      //add markers dynamically
                      var points = [{lat: 40, lng: -86},{lat: 40.1, lng: -86.2}];
                      updatePoints(points);
          
                      function updatePoints(pts) {
                         for (var p in pts) {
                            L.marker([pts[p].lat, pts[p].lng]).addTo(map);
                         }
                      }
          
                      //add a watch on the scope to update your points.
                      // whatever scope property that is passed into
                      // the poinsource="" attribute will now update the points
                      scope.$watch(attr.pointsource, function(value) {
                         updatePoints(value);
                      });
                  }
              };
          });
          

          这是标记。在这里,您将添加链接函数正在寻找的 pointsource 属性来设置 $watch。

          <div ng-app="leafletMap">
              <div ng-controller="MapCtrl">
                  <sap id="map" pointsource="pointsFromController"></sap>
              </div>
          </div>
          

          然后在您的控制器中,您有一个可以更新的属性。

          function MapCtrl($scope, $http) {
             //here's the property you can just update.
             $scope.pointsFromController = [{lat: 40, lng: -86},{lat: 40.1, lng: -86.2}];
          
             //here's some contrived controller method to demo updating the property.
             $scope.getPointsFromSomewhere = function() {
               $http.get('/Get/Points/From/Somewhere').success(function(somepoints) {
                   $scope.pointsFromController = somepoints;
               });
             }
          }
          

          【讨论】:

          • 以上答案非常有帮助。我想要实现的一件事就是清除函数中的所有标记。有什么想法吗?
          • angular 并不总是触发,如果你只是通过重新初始化来重置一个数组,我相信你已经尝试过了。因此,首先您可以尝试:$scope.pointsFromController = []; 这可能不起作用...如果这不起作用,那么您可以通过手动删除项目来做到这一点:$scope.pointsFromController.splice(0, $scope.pointsFromController.length);
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多