使用 angularjs 扩展 leaflet 的控件
leaflet提供了扩展控件的方法,可以自定义control,但现在想在自定义控件中使用angular的模板(templateUrl)和控制器(controller)机制绑定控件的属性和行为,类似于这种ui-router中定义路由或ui-bootstrap中定义弹出模态窗口的方式:
this.$modal.open({
templateUrl: 'modules/acc/components/gis/equipmentFilter.html',
controller: 'modules/acc/components/gis/equipmentFilter',
controllerAs: 'vm'
});
想达到的效果是,按钮的 ng-click 能绑定 controller 的方法以及能使用 ng-model 绑定属性,而且是以 leaflet 扩展控件的方式加到地图中
点击控件按钮,执行方法弹出一个窗口
用到的技术点和具体思路如下:
- 定义好一个对象,包含templateUrl、template、controller、controllerAs…等相关属性
- 使用 $http 服务获取 templateUrl 定义的模板,或直接使用template定义的模板
- 使用 $rootScope 和 $controller 服务处理 controller 以及创建 scope 对象
- 使用 $compile 服务编译模板获取的模板,传递 scope
- 使用 L.DomUtil.create 创建一个用于 leaflet 的 Dom 元素
- 将编译好的模板对象加到 Dom 元素中
- 在 leaflet 自定义控件 L.Control.extend 时使用该元素
这里使用typescript实现,先定义一个 factory 返回一个创建 leaflet 控件的方法,具体代码如下:
import mod = require('modules/acc/module');
import angular = require('angular');
import L = require('leaflet');
function factory(
$compile: ng.ICompileService,
$rootScope: ng.IRootScopeService,
$controller,
$q,
$http,
$templateCache,
$injector
) {
function getTemplatePromise(options) {
return options.template
? $q.when(options.template)
: $http
.get(
angular.isFunction(options.templateUrl)
? options.templateUrl()
: options.templateUrl,
{ cache: $templateCache }
)
.then(function(result) {
return result.data;
});
}
function getResolvePromises(resolves) {
var promisesArr = [];
angular.forEach(resolves, value => {
if (angular.isFunction(value) || angular.isArray(value)) {
promisesArr.push($q.when($injector.invoke(value)));
}
});
return promisesArr;
}
return (controlOptions: acc.IMapControlOptions) => {
var controlElm = L.DomUtil.create('div', 'leaflet-control-clegend');
var templateAndResolvePromise = $q.all(
[getTemplatePromise(controlOptions)].concat(
getResolvePromises(controlOptions.resolve)
)
);
templateAndResolvePromise.then(tplAndVars => {
var controlScope = (controlOptions.scope || $rootScope).$new();
//
if (controlOptions.controller) {
var ctrlInstance,
ctrlLocals = {
$scope: controlScope
};
var resolveIter = 1;
angular.forEach(controlOptions.resolve, (value, key) => {
ctrlLocals[key] = tplAndVars[resolveIter++];
});
ctrlInstance = $controller(controlOptions.controller, ctrlLocals);
if (controlOptions.controllerAs) {
controlScope[controlOptions.controllerAs] = ctrlInstance;
}
}
// 定义一个控件最外层元素
var angularDomEl = $(angular.element('<div></div>'));
// 将元素添加到 leaflet 的 Dom 元素里,可能不定义最外层元素也行
angularDomEl.attr('template-url', controlOptions.templateUrl);
angularDomEl.html(tplAndVars[0]);
controlElm.appendChild(angularDomEl.get(0));
// 传递scope,编译整个新加入的元素
$compile(controlElm)(controlScope);
});
// 这里是 leaflet 扩展控件的定义
var t = L.Control.extend({
options: {
position: 'topright'
},
initialize: function(options) {
L.Util.extend(this.options, options);
},
onAdd: function(map: L.Map) {
// 最后元素要加到控件的 _container 中
this._container = controlElm;
return this._container;
}
});
// 将 control 对象返回,可加到地图中
return new t(controlOptions.options);
};
}
factory.$inject = [
'$compile',
'$rootScope',
'$controller',
'$q',
'$http',
'$templateCache',
'$injector'
];
mod.factory('modules/acc/factories/mapControl', factory);
实现一个模板
<div>
<div class="btn-group leaflet-bar dropdown">
<button class="btn btn-primary" ng-click="vm.test()">
<i class="glyphicon glyphicon-cog"></i>
</button>
<button class="btn btn-default" ng-click="vm.test()">
<i class="glyphicon glyphicon-search"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li>
<a href="">显示1</a>
</li>
<li>
<a href="">显示1</a>
</li>
<li>
<a href="">显示1</a>
</li>
</ul>
<button class="btn btn-success" data-toggle="dropdown">
<i class="glyphicon glyphicon-road"></i>
</button>
</div>
<div class="btn-group leaflet-bar">
<button class="btn btn-default" ng-click="vm.test()">
<i class="glyphicon glyphicon-refresh"></i>
</button>
<button class="btn btn-warning" ng-click="vm.test()">
<i class="glyphicon glyphicon-volume-up"></i>
</button>
<button class="btn btn-default" ng-click="vm.eqFilter()">
<i class="glyphicon glyphicon-filter"></i>
</button>
</div>
</div>
在加载 leaflet 的地方使用这个 factory,并将对象加到地图中
import mod = require('modules/acc/module');
import { MapBuilder } from 'modules/acc/extend/leaflet/mapBuilder';
class Controller {
static $inject = ['$scope', '$element', 'modules/acc/factories/mapControl'];
constructor(
private $scope,
private $element: JQLite,
private mapControl: acc.IMapLayerFactory // 这里是刚才定义的 factory
) {
$scope.vm = this;
// 这个是另外定义的地图控件类,实际上返回的就是一个 leaflet 地图对象
$scope.map = new MapBuilder(
$($element)
.find('.map-area')
.get(0)
).map();
// 这里创建控件,并加到地图中
mapControl({
templateUrl: 'modules/acc/views/gisTools.html',
controller: 'modules/acc/controllers/gisTools',
controllerAs: 'vm'
}).addTo($scope.map);
}
}
mod.controller('modules/acc/components/gis/index', Controller);
具体 controller 里的定义就是最常规的方法,没什么可说的
转载自:https://blog.csdn.net/weixin_38687913/article/details/81102479