AngularJS与LeafletJS的结合

8

以下是来自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);
            }
        }
    };
});
4个回答

13

我不太了解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;
     });
   }
}

1
上面的回答非常有帮助。我只想实现一个目标,就是清除函数中的所有标记。有什么想法吗? - MomentH
Angular并不总是会触发,如果您只是通过重新初始化来重置数组,我相信您已经尝试过了。因此,首先您可以尝试这样做:$scope.pointsFromController = []; 这可能不起作用... 如果这样不起作用,那么您可以通过手动删除项目来实现:$scope.pointsFromController.splice(0, $scope.pointsFromController.length); - Ben Lesh

5

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

以下是基本过程。

在我的页面之一上有一个<map>元素。然后我有一个指令来替换<map>元素与Leaflet地图。我的设置略有不同,因为我在Factory中加载JSON数据,但我已经适应了您的用例(如果有错误,请谅解)。在指令内部,加载您的JSON文件,然后循环遍历每个位置(您需要以兼容的方式设置JSON文件)。然后在每个lat/lng处显示一个标记。

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
    }
]} 

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();

我希望这可以帮到你,干杯


1
指令和 MVC 在 AngularJS 中是不同的技术。指令通常在页面加载时执行。指令更多地用于处理/使用 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存在问题,建议避免使用<ng-form><ng-model>。替代方案为

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接