【问题标题】:AngularJS + ArcGISAngularJS + ArcGIS
【发布时间】:2013-07-07 00:15:43
【问题描述】:

我正在尝试在 Angular 应用程序中使用 ArcGIS JavaScript API。如我所见,它使用 Dojo。因此,我正在尝试从 Angular 指令初始化 ArcGIS,如下所示:

  link: function (scope, element, attrs) {
    dojo.require('esri.map');
    var init = function () {
      console.log('dojo is ready');
      var map = new esri.Map("map-container", {
        center: [-111.3797, 56.7266 ],
        zoom: 16,
        basemap: "streets"
      });
      map.enableScrollWheelZoom()

    };
    dojo.addOnLoad(init);
  }

看起来这种方式不是 100% 正确,因为当我尝试通过滚动鼠标滚轮进行缩放时,我收到了这个错误:

Uncaught TypeError: Cannot call method 'apply' of null 

我的问题是如何在 Angular 应用程序中正确注入 ArcGIS 功能?

【问题讨论】:

    标签: javascript angularjs dojo arcgis arcgis-js-api


    【解决方案1】:

    我认为一个非常“AngularJS”风格的方法将类似于以下内容。 (这里小提琴http://jsfiddle.net/technicolorenvy/2Ke62/4/

    我喜欢使用angular-ui-router,但这种方法也适用于 Angular 的$routeProvider。这里的神奇之处在于 resolve 对象,它可以选择“等待”直到 promise 被解决后再继续。

    angular.module('webApp', ['ui.router'])
        // module (app) config
        .config(function ($stateProvider, $urlRouterProvider) {
    
            $urlRouterProvider.otherwise('/map');
    
            $stateProvider.state('map', {
                url: '/map',
                template: '<div id="map"></div>',
                controller: 'MapCtrl',
                resolve: {
                    promiseObj: function ($q, $rootScope, wish) {
                        var deferred = $q.defer(),
                            deps = {
                                Map: 'esri/map',
                                FeatureLayer: 'esri/layers/FeatureLayer',
                                InfoTemplate: 'esri/InfoTemplate',
                                SimpleFillSymbol: 'esri/symbols/SimpleFillSymbol',
                                SimpleRenderer: 'esri/renderers/SimpleRenderer',
                                SimpleMarkerSymbol: 'esri/symbols/SimpleMarkerSymbol',
                                ScaleDependentRenderer: 'esri/renderers/ScaleDependentRenderer',
                                Color: 'dojo/_base/Color'
                            };
    
                        wish.loadDependencies(deps, function () {
                            deferred.resolve();
                            if (!$rootScope.$$phase) {
                                $rootScope.$apply();
                            }
                        });
    
                        return deferred.promise;
                    }
                }
            });
        });
    

    正如您在上面看到的,我们有一个 map 状态,它有一个 resolve 属性。然后,您可以构建一个表示您的 ArcGIS/Dojo 依赖项的对象并将其传递给您的 wish.loadDependencies(见下文)。

    使用q,我们将返回一个承诺,一旦通过dojo的require加载所有依赖项,该承诺就会得到解决

    angular.module('webApp')
         // service that deals w/ our dojo require
        .service('wish', function () {
    
            // it's not require... it's a wish?
            var wish = {};
    
            function _loadDependencies(deps, next) {
                var reqArr = _.values(deps),
                    keysArr = _.keys(deps);
    
                // use the dojo require (required by arcgis + dojo) && save refs
                // to required obs
                require(reqArr, function () {
                    var args = arguments;
    
                    _.each(keysArr, function (name, idx) {
                        wish[name] = args[idx];
                    });
    
                    next();
                });
            }
    
            return {
                loadDependencies: function (deps, next) {
                    _loadDependencies(deps, next);
                },
    
                get: function () {
                    return wish;
                }
            };
        });
    

    之后,在您的MapCtrl 中,您可以通过在应用程序配置期间构建的deps 对象中使用的键直接调用所有ArcGIS/Dojo fns(就像您通常那样),因为它们是现在附加到 wish.get() 返回的对象上。

    以下是此处 (https://developers.arcgis.com/en/javascript/jssamples/renderer_proportional_scale_dependent.html) 示例的修改版本

    angular.module('webApp')
        // our map controller
        .controller('MapCtrl', function ($rootScope, $scope, wish) {
    
            var w = wish.get(),
                greenFill = new w.Color([133, 197, 133, 0.75]),
                greenOutline = new w.Color([133, 197, 133, 0.25]),
                layer,
                markerSym,
                renderer1,
                renderer2,
    
                CROPS_URL = 'http://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/USA_County_Crops_2007/FeatureServer/0';
    
            $scope.map = new w.Map('map', {
                center: [-98.579, 39.828],
                zoom: 4,
                basemap: 'gray'
            });
    
            layer = new w.FeatureLayer(CROPS_URL, {
                outFields: ['STATE', 'COUNTY', 'M086_07', 'AREA'],
                infoTemplate: new w.InfoTemplate('${COUNTY}, ${STATE}', '<div style="font: 18px Segoe UI">The percentage of the area of the county that represents farmland is <b>${M086_07}%</b>.</div>')
            });
            layer.setDefinitionExpression('AREA>0.01 and M086_07>0');
    
    
            markerSym = new w.SimpleMarkerSymbol();
            markerSym.setColor(greenFill);
            markerSym.setOutline(markerSym.outline.setColor(greenOutline));
            renderer1 = new w.SimpleRenderer(markerSym);
            renderer1.setProportionalSymbolInfo({
                field: 'M086_07',
                minSize: 1,
                maxSize: 10,
                minDataValue: 0,
                maxDataValue: 100
            });
    
            //for the second renderer increase the dot sizes and set a backgroundFillSymbol
            renderer2 = new w.SimpleRenderer(markerSym);
            renderer2.setProportionalSymbolInfo({
                field: 'M086_07',
                minSize: 5,
                maxSize: 15,
                minDataValue: 0,
                maxDataValue: 100
            });
    
            layer.setRenderer(new w.ScaleDependentRenderer({
                rendererInfos: [{
                    'renderer': renderer1,
                        'minScale': 50000000,
                        'maxScale': 10000000
                }, {
                    'renderer': renderer2,
                        'minScale': 0,
                        'maxScale': 5000000
                }]
            }));
    
            $scope.map.addLayer(layer);
        });
    

    演示上述代码的工作小提琴,在这里找到http://jsfiddle.net/technicolorenvy/2Ke62/4/

    【讨论】:

    • 我喜欢你的解决方案,但我有一个小问题。我正在使用角度翻译,从“//js.arcgis.com/3.14”加载init.js需要一秒钟,导致角度翻译显示为{{'something'|translate}}而不是呈现的文本,直到init.js 加载以加载“require”。你知道有一种方法可以删除 wish 服务中的 require 依赖吗?
    • 我会通过预加载器或“数据加载”标志在您的 UI 中处理此问题。这里对问题和可能的解决方案进行了相当不错的解释code-hound.com/add-a-preloader-to-your-website-using-angularjs
    • 谢谢,我试试看。
    【解决方案2】:

    看起来您正在尝试在指令元素内构建地图。这是一个合法的用途,但我会确保您使用 Dojo 的 AMD 加载程序来加载您的模块,然后在所有 Dojo 优点准备好之后 bootstrap 您的 Angular 应用程序。

    我最近整理了一篇关于 Angular/Esri 开发的文章,示例项目的源代码可以在 here 找到。

    我实际做的是从 Controller 构建地图,但过程应该类似于在指令中构建它。

    define([
        'angular',
        'esri/map'
    ], function(angular, Map) {
        function mapConfigs() {
            return {
                basemap: 'streets',
                center: [-118.1704035141802,34.03597014510993],
                zoom: 15
            };
        }
        function mapGen(elem) {
            return new Map(elem, mapConfigs());
        }
        function AppController($scope) {
            $scope.map = mapGen('map');
        }
        function init(App) {
            App.controller('AppCtrl', ['$scope', AppController]);
            return AppController;
        }
        return { start: init };
    });
    

    在引导 Angular 应用程序之前,我使用引导模块使用 Esri/Dojo 位构建我的所有 Angular 位。

    define([
        'angular',
        'controllers/AppController',
        'widgets/search/SearchBootstrap'
    ], function(angular, AppController, SearchBootstrap) {
        function init() {
            var App = angular.module('app', ['ui.bootstrap']);
            AppController.start(App);
            SearchBootstrap.start(App);
            // need to bootstrap angular since we wait for dojo/DOM to load
            angular.bootstrap(document.body, ['app']);
            return App;
        }
        return { start: init };
    });
    

    希望能有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-12
      • 2012-10-11
      • 2011-01-07
      • 2013-05-26
      • 2022-07-08
      • 2021-11-11
      • 2013-11-24
      相关资源
      最近更新 更多