diff --git a/.gitignore b/.gitignore index 58b6496..bffcf98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea/ -lib/ \ No newline at end of file +node_modules/ +example/angular/ +ya-map.min.js \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..8184d57 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,23 @@ +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + uglify: { + options: { + banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' + }, + dist: { + files: { + 'ya-map.min.js': ['example/ya-map.js'] + } + } + } + }); + + + // Load the plugin that provides the "uglify" task. + grunt.loadNpmTasks('grunt-contrib-uglify'); + + // Default task(s). + grunt.registerTask('default', ['uglify']); +}; \ No newline at end of file diff --git a/README.md b/README.md index 1f17e4b..cc08919 100644 --- a/README.md +++ b/README.md @@ -152,3 +152,4 @@ yaMap - `ya-key` - ключ для дальнейшего обращения к шаблону - `ya-overrides` - объект, который задает переопределяемые функции. + diff --git a/example/index.html b/example/index.html index de51799..21b1c5f 100644 --- a/example/index.html +++ b/example/index.html @@ -104,6 +104,6 @@

Примеры использования Яндекс карт через - + \ No newline at end of file diff --git a/example/ya-map.min.js b/example/ya-map.min.js new file mode 100644 index 0000000..8b8eb45 --- /dev/null +++ b/example/ya-map.min.js @@ -0,0 +1,2 @@ +/*! yaMap 13-11-2013 */ +"use strict";angular.module("yaMap",[]).constant("GEOMETRY_TYPES",{POINT:"Point",LINESTRING:"LineString",RECTANGLE:"Rectangle",POLYGON:"Polygon",CIRCLE:"Circle"}).value("yaMapSettings",{lang:"ru-RU",order:"longlat"}).factory("mapApiLoad",["yaMapSettings",function(a){var b=!1,c=[],d=function(){b=!0;for(var a;c.length;)a=c.splice(0,1),a[0]()},e="http://api-maps.yandex.ru/2.0/?load=package.full&lang="+(a.lang||"ru-RU")+"&coordorder="+(a.order||"longlat"),f=!1,g=function(a,b){if(!f){f=!0;var c=document.createElement("script");c.type="text/javascript",c.readyState?c.onreadystatechange=function(){("loaded"==c.readyState||"complete"==c.readyState)&&(c.onreadystatechange=null,f=!1,b())}:c.onload=function(){f=!1,b()},c.src=a,document.getElementsByTagName("head")[0].appendChild(c)}};return function(a){c.push(a),b?d():g(e,function(){ymaps.ready(function(){d()})})}}]).service("yaLayer",[function(){this.create=function(a){return new ymaps.Layer(a)}}]).service("yaMapType",[function(){this.create=function(a,b){return new ymaps.MapType(a,b)}}]).service("layerStorage",["mapApiLoad",function(a){this.get=function(b){if(this._storage)b(this._storage);else{var c=this;a(function(){c._storage=ymaps.layer.storage,b(c._storage)})}}}]).service("mapTypeStorage",["mapApiLoad",function(a){this.get=function(b){if(this._storage)b(this._storage);else{var c=this;a(function(){c._storage=ymaps.mapType.storage,b(c._storage)})}}}]).service("yaSubscriber",function(){var a=/^yaEvent([A-Z]{1}[a-z]+)([A-Z]{1}[a-z]+)?$/;this.subscribe=function(b,c,d,e){var f=a.exec(d),g=(f[2]||f[1]).toLowerCase(),h=f[2]?f[1]:void 0;"geoobjects"===h&&(h="geoObjects"),e[d]=function(a){return c(e.$parent||e,a)};var i=h?b[h].events:b.events;i.add(g,function(a){setTimeout(function(){e.$apply(function(){e[d]({$event:a})})})})}}).service("templateLayoutFactory",[function(){this._cache={},this.get=function(a){return this._cache[a]},this.create=function(a,b,c){this._cache[a]||(this._cache[a]=ymaps.templateLayoutFactory.createClass(b,c))}}]).directive("yaTemplateLayout",["templateLayoutFactory",function(a){return{restrict:"E",priority:1001,scope:{overrides:"=yaOverrides"},compile:function(b){var c=b.html();return b.html(""),function(b,d,e){if(!e.yaKey)throw new Error('not require attribute "key"');var f=e.yaKey;a.create(f,c,b.overrides)}}}}]).controller("YaMapCtrl",["$scope","mapApiLoad",function(a,b){var c=this;b(function(){c.addGeoObjects=function(b){a.map.geoObjects.add(b)},c.removeGeoObjects=function(b){a.map.geoObjects.remove(b)},c.addControl=function(b,c){a.map.controls.add(b,c)},c.getMap=function(){return a.map},c.addImageLayer=function(b,c){var d=new ymaps.Layer(b,c);a.map.layers.add(d)},c.addHotspotLayer=function(b,c,d){var e=new ymaps.hotspot.ObjectSource(b,c),f=new ymaps.hotspot.Layer(e,d);a.map.layers.add(f)},c.addToolbar=function(b){a.map.controls.add(b)}})}]).directive("yaMap",["$compile","mapApiLoad","yaMapSettings","$window","yaSubscriber","$parse",function(a,b,c,d,e,f){return{restrict:"E",scope:{yaCenter:"@",yaType:"@",yaBeforeInit:"&",yaAfterInit:"&"},compile:function(g){var h=g.contents();return g.html(""),function(g,i,j){for(var k,l=function(a){try{return g.$eval(a)}catch(b){return a}},m=l(j.yaCenter),n=Number(j.yaZoom),o=j.yaBehaviors?j.yaBehaviors.split(" "):["default"],p=[],q=[],r=0,s=o.length;s>r;r++)k=o[r],"-"===k[0]?p.push(k.substring(1)):q.push(k);n=0>n?0:n,n=n>23?23:n;var t=function(a){m?angular.isArray(m)?b(a):angular.isString(m)&&b(function(){ymaps.geocode(m,{results:1}).then(function(b){var c=b.geoObjects.get(0);m=c.geometry.getCoordinates(),a&&a()},function(a){d.alert(a.message)})}):b(function(){m="longlat"===c.order?[ymaps.geolocation.longitude,ymaps.geolocation.latitude]:[ymaps.geolocation.latitude,ymaps.geolocation.longitude],a&&a()})},u=function(){g.yaBeforeInit();var b=j.yaOptions?g.$eval(j.yaOptions):void 0;b&&b.projection&&(b.projection=new ymaps.projection[b.projection.type](b.projection.bounds)),g.map=new ymaps.Map(i[0],{center:m,zoom:n,type:j.yaType||"yandex#map",behaviors:q},b),g.map.behaviors.disable(p);for(var c in j)if(0===c.indexOf("yaEvent")){var d=f(j[c]);e.subscribe(g.map,d,c,g)}g.yaAfterInit({$target:g.map}),i.append(h),setTimeout(function(){g.$apply(function(){a(h)(g.$parent)})})};g.$watch("yaCenter",function(a){m=l(a),t(function(){g.map.setCenter(m)})}),g.$watch("yaType",function(a){a&&g.map.setType(a)}),g.$on("$destroy",function(){g.map&&g.map.destroy()}),t(u)}},controller:"YaMapCtrl"}}]).controller("MapToolbarCtrl",["$scope",function(a){this.add=function(b){a.toolbar.add(b)}}]).directive("yaToolbar",["$compile","$parse","yaSubscriber",function(a,b,c){return{require:"^yaMap",restrict:"E",scope:{yaAfterInit:"&"},compile:function(d){var e=d.contents();return d.html(""),function(d,f,g,h){if(!g.yaName)throw new Error('not pass attribute "name"');var i=g.yaOptions?d.$eval(g.yaOptions):void 0,j=g.yaParams?d.$eval(g.yaParams):void 0,k=g.yaName[0].toUpperCase()+g.yaName.substring(1);d.toolbar=new ymaps.control[k](j);for(var l in g)if(0===l.indexOf("yaEvent")){var m=b(g[l]);c.subscribe(d.toolbar,m,l,d)}h.addControl(d.toolbar,i),d.yaAfterInit({$target:d.toolbar}),f.append(e),a(e)(d.$parent)}},controller:"MapToolbarCtrl"}}]).directive("yaControl",["yaSubscriber","templateLayoutFactory","$parse",function(a,b,c){return{restrict:"E",require:"^yaToolbar",scope:{yaAfterInit:"&"},link:function(d,e,f,g){var h=f.yaType[0].toUpperCase()+f.yaType.substring(1),i=function(a){try{return d.$eval(a)}catch(b){return a}},j=i(f.yaParams),k=f.yaOptions?d.$eval(f.yaOptions):void 0;k&&k.layout&&(k.layout=b.get(k.layout)),k&&k.itemLayout&&(k.itemLayout=b.get(k.itemLayout));var l,m=["SearchControl","SmallZoomControl","ScaleLine","ZoomControl"];if(m.indexOf(h)>-1)l=new ymaps.control[h](k);else{if(j&&j.items){for(var n,o=[],p=0,q=j.items.length;q>p;p++)n=j.items[p],o.push(new ymaps.control.ListBoxItem(n));j.items=o}l=new ymaps.control[h](j,k)}for(var r in f)if(0===r.indexOf("yaEvent")){var s=c(f[r]);a.subscribe(l,s,r,d)}g.add(l),d.yaAfterInit({$target:l})}}}]).controller("CollectionCtrl",["$scope",function(a){this.addGeoObjects=function(b){a.collection.add(b)},this.removeGeoObjects=function(b){a.collection.remove(b)}}]).directive("yaCollection",["$compile","yaMapSettings","$timeout","yaSubscriber","$parse",function(a,b,c,d,e){return{require:"^yaMap",restrict:"E",scope:{yaAfterInit:"&"},compile:function(b){var f=b.contents();return b.html(""),function(b,g,h,i){var j=h.yaOptions?b.$eval(h.yaOptions):{},k=angular.isDefined(h.showAll)&&"false"!=h.showAll;if(k){var l,m=i.getMap(),n=function(){l&&c.cancel(l),l=c(function(){m.geoObjects.events.remove("add",n);var a=m.geoObjects.getBounds();a&&m.setBounds(a)},300)};m.geoObjects.events.add("add",n)}b.collection=new ymaps.GeoObjectCollection({},j);for(var o in h)if(0===o.indexOf("yaEvent")){var p=e(h[o]);d.subscribe(b.collection,p,o,b)}i.addGeoObjects(b.collection),b.yaAfterInit({$target:b.collection}),b.$on("$destroy",function(){b.collection&&i.removeGeoObjects(b.collection)}),g.append(f),a(f)(b.$parent)}},controller:"CollectionCtrl"}}]).directive("yaCluster",["yaMapSettings","yaSubscriber","$compile","templateLayoutFactory","$parse",function(a,b,c,d,e){return{require:"^yaMap",restrict:"E",scope:{yaAfterInit:"&"},compile:function(a){var f=a.contents();return a.html(""),function(a,g,h,i){var j=h.yaOptions?a.$eval(h.yaOptions):{};j&&j.clusterBalloonMainContentLayout&&(j.clusterBalloonMainContentLayout=d.get(j.clusterBalloonMainContentLayout)),j&&j.clusterBalloonSidebarItemLayout&&(j.clusterBalloonSidebarItemLayout=d.get(j.clusterBalloonSidebarItemLayout)),j&&j.clusterBalloonContentItemLayout&&(j.clusterBalloonContentItemLayout=d.get(j.clusterBalloonContentItemLayout)),j&&j.clusterBalloonAccordionItemContentLayout&&(j.clusterBalloonAccordionItemContentLayout=d.get(j.clusterBalloonAccordionItemContentLayout)),a.collection=new ymaps.Clusterer(j);for(var k in h)if(0===k.indexOf("yaEvent")){var l=e(h[k]);b.subscribe(a.collection,l,k,a)}i.addGeoObjects(a.collection),a.yaAfterInit({$target:a.collection}),a.$on("$destroy",function(){a.collection&&i.removeGeoObjects(a.collection)}),g.append(f),c(f)(a.$parent)}},controller:"CollectionCtrl"}}]).directive("yaGeoObject",["GEOMETRY_TYPES","yaSubscriber","templateLayoutFactory","$parse",function(a,b,c,d){return{restrict:"E",require:["^yaMap","?^yaGeoObjects","?^yaCluster"],scope:{yaSource:"=",yaShowBalloon:"=",yaAfterInit:"&"},link:function(e,f,g,h){var i,j=h[2]||h[1]||h[0],k=g.yaOptions?e.$eval(g.yaOptions):void 0;k&&k.balloonContentLayout&&(k.balloonContentLayout=c.get(k.balloonContentLayout));var l=function(a,c){i=new ymaps.GeoObject(a,c);for(var f in g)if(0===f.indexOf("yaEvent")){var h=d(g[f]);b.subscribe(i,h,f,e)}j.addGeoObjects(i),e.yaAfterInit({$target:i}),m(g.yaEdit),n(g.yaDraw),o(e.yaShowBalloon)};e.$watch("yaSource",function(b){if(b)if(i){i.geometry.setCoordinates(b.geometry.coordinates),i.geometry.getType()===a.CIRCLE&&i.geometry.setRadius(b.geometry.radius);var c=b.properties;for(var d in c)c.hasOwnProperty(d)&&i.properties.set(d,c[d])}else l(b,k);else i&&j.removeGeoObjects(i)},angular.equals);var m=function(a){angular.isDefined(a)&&"false"!==a?i&&i.editor.startEditing():angular.isDefined(a)&&i&&i.editor.stopEditing()},n=function(a){angular.isDefined(a)&&"false"!==a?i&&i.editor.startDrawing():angular.isDefined(a)&&i&&i.editor.stopDrawing()},o=function(a){a?i&&i.balloon.open():i&&i.balloon.close()};g.$observe("yaEdit",m),g.$observe("yaDraw",n),e.$watch("yaShowBalloon",o),e.$on("$destroy",function(){i&&j.removeGeoObjects(i)})}}}]).directive("yaHotspotLayer",[function(){return{restrict:"E",require:"^yaMap",link:function(a,b,c,d){if(!c.yaUrlTemplate)throw new Error('not exists required attribute "url-template"');if(!c.yaKeyTemplate)throw new Error('not exists required attribute "key-template"');var e=c.yaOptions?a.$eval(c.yaOptions):void 0;d.addHotspotLayer(c.yaUrlTemplate,c.yaKeyTemplate,e)}}}]).directive("yaImageLayer",[function(){return{restrict:"E",require:"^yaMap",link:function(a,b,c,d){if(!c.yaUrlTemplate)throw new Error('not exists required attribute "url-template"');var e=c.yaOptions?a.$eval(c.yaOptions):void 0;d.addImageLayer(c.yaUrlTemplate,e)}}}]); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..f9b8dcf --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "yaMap", + "version": "1.0.0", + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-uglify": "~0.2.2" + } +} diff --git a/ya-map.js b/ya-map.js new file mode 100644 index 0000000..ee41ae9 --- /dev/null +++ b/ya-map.js @@ -0,0 +1,655 @@ +"use strict"; +angular.module('yaMap',[]). + constant('GEOMETRY_TYPES', { + POINT:'Point', + LINESTRING:'LineString', + RECTANGLE: 'Rectangle', + POLYGON: 'Polygon', + CIRCLE: 'Circle' + }). + + value('yaMapSettings',{ + lang:'ru-RU', + order:'longlat' + }). + + factory('mapApiLoad',['yaMapSettings',function(yaMapSettings){ + var loaded = false; + var callbacks = []; + var runCallbacks = function(){ + loaded = true; + var callback; + while(callbacks.length){ + callback = callbacks.splice(0,1); + callback[0](); + } + }; + var loadUrl = 'http://api-maps.yandex.ru/2.0/?load=package.full&lang=' + + (yaMapSettings.lang || 'ru-RU') +'&coordorder=' +(yaMapSettings.order || 'longlat'); + var _loading = false; + var loadScript = function(url, callback){ + if(_loading){ + return; + } + _loading=true; + var script = document.createElement("script"); + script.type = "text/javascript"; + if (script.readyState){ // IE + script.onreadystatechange = function(){ + if (script.readyState=="loaded" || script.readyState=="complete"){ + script.onreadystatechange = null; + _loading=false; + callback(); + } + }; + } else { // Другие броузеры + script.onload = function(){ + _loading=false; + callback(); + }; + } + script.src = url; + document.getElementsByTagName("head")[0].appendChild(script); + }; + + return function(callback){ + callbacks.push(callback); + if(loaded){ + runCallbacks(); + }else{ + loadScript(loadUrl, function(){ + ymaps.ready(function(){ + runCallbacks(); + }); + }); + } + }; + }]). + + service('yaLayer',[function(){ + this.create = function(tileZoomFn){ + return new ymaps.Layer(tileZoomFn); + }; + }]). + + service('yaMapType',[function(){ + this.create = function(name, layers){ + return new ymaps.MapType(name,layers); + }; + }]). + + service('layerStorage',['mapApiLoad',function(mapApiLoad){ + this.get = function(callback){ + if(this._storage){ + callback(this._storage); + }else{ + var self = this; + mapApiLoad(function(){ + self._storage = ymaps.layer.storage; + callback(self._storage); + }); + } + }; + }]). + + service('mapTypeStorage',['mapApiLoad',function(mapApiLoad){ + this.get = function(callback){ + if(this._storage){ + callback(this._storage); + }else{ + var self = this; + mapApiLoad(function(){ + self._storage = ymaps.mapType.storage; + callback(self._storage); + }); + } + }; + }]). + + service('yaSubscriber',function(){ + var eventPattern = /^yaEvent([A-Z]{1}[a-z]+)([A-Z]{1}[a-z]+)?$/; + this.subscribe = function(target, parentGet, attrName, scope){ + var res = eventPattern.exec(attrName); + var eventName = (res[2] || res[1]).toLowerCase(); + var propertyName = res[2] ? res[1] : undefined; + if(propertyName==='geoobjects'){ + propertyName='geoObjects'; + } + scope[attrName]=function(locals){ + return parentGet(scope.$parent || scope, locals); + }; + var events = propertyName ? target[propertyName].events : target.events; + events.add(eventName,function(event){ + setTimeout(function(){ + scope.$apply(function(){ + scope[attrName]({ + $event:event + }); + }); + }); + }); + }; + }). + service('templateLayoutFactory',[function(){ + this._cache = {}; + this.get=function(key){ + return this._cache[key]; + }; + this.create = function(key, template, overadice){ + if(this._cache[key]){ + return; + } + this._cache[key] = ymaps.templateLayoutFactory.createClass(template,overadice); + }; + }]). + + directive('yaTemplateLayout',['templateLayoutFactory',function(templateLayoutFactory){ + return{ + restrict:'E', + priority:1001, + scope:{ + overrides:'=yaOverrides' + }, + compile: function(tElement) { + var html = tElement.html(); + tElement.html(''); + return function(scope,elm,attrs){ + if(!attrs.yaKey){ + throw new Error('not require attribute "key"'); + } + var key = attrs.yaKey; + templateLayoutFactory.create(key, html, scope.overrides); + }; + } + }; + }]). + + controller('YaMapCtrl',['$scope','mapApiLoad',function($scope,mapApiLoad){ + var self = this; + mapApiLoad(function(){ + self.addGeoObjects = function(obj){ + $scope.map.geoObjects.add(obj); + }; + self.removeGeoObjects = function(obj){ + $scope.map.geoObjects.remove(obj); + }; + + self.addControl = function(name, options){ + $scope.map.controls.add(name,options); + }; + self.getMap = function(){ + return $scope.map; + }; + self.addImageLayer = function(urlTemplate, options){ + var imgLayer = new ymaps.Layer(urlTemplate, options); + $scope.map.layers.add(imgLayer); + }; + self.addHotspotLayer = function(urlTemplate, keyTemplate, options){ + // Создадим источник данных слоя активных областей. + var objSource = new ymaps.hotspot.ObjectSource(urlTemplate,keyTemplate); + var hotspotLayer = new ymaps.hotspot.Layer(objSource, options); + $scope.map.layers.add(hotspotLayer); + }; + self.addToolbar = function(toolbar){ + $scope.map.controls.add(toolbar); + }; + }); + }]). + directive('yaMap',['$compile','mapApiLoad','yaMapSettings','$window','yaSubscriber','$parse',function($compile, mapApiLoad,yaMapSettings,$window,yaSubscriber,$parse){ + return { + restrict:'E', + scope: { + yaCenter:'@', + yaType:'@', + yaBeforeInit:'&', + yaAfterInit:'&' + }, + compile: function(tElement) { + var childNodes = tElement.contents(); + tElement.html(''); + return function(scope, element,attrs) { + var getEvalOrValue = function(value){ + try{ + return scope.$eval(value); + }catch(e){ + return value; + } + }; + var center = getEvalOrValue(attrs.yaCenter), + zoom = Number(attrs.yaZoom), + behaviors = attrs.yaBehaviors ? attrs.yaBehaviors.split(' ') : ['default']; + var disableBehaviors=[], enableBehaviors=[], behavior; + for (var i = 0, ii = behaviors.length; i < ii; i++) { + behavior = behaviors[i]; + if(behavior[0]==='-'){ + disableBehaviors.push(behavior.substring(1)); + }else{ + enableBehaviors.push(behavior); + } + } + + zoom = zoom <0 ? 0 : zoom; + zoom = zoom>23 ? 23 : zoom; + var setCenter = function(callback){ + if(!center){ + //устанавливаем в качестве центра местоположение пользователя + mapApiLoad(function(){ + if(yaMapSettings.order==='longlat'){ + center = [ymaps.geolocation.longitude, ymaps.geolocation.latitude]; + }else{ + center = [ymaps.geolocation.latitude, ymaps.geolocation.longitude]; + } + if(callback){ + callback(); + } + }); + }else if(angular.isArray(center)){ + mapApiLoad(callback); + }else if(angular.isString(center)){ + //проводим обратное геокодирование + mapApiLoad(function(){ + ymaps.geocode(center, { results: 1 }).then(function (res) { + var firstGeoObject = res.geoObjects.get(0); + center = firstGeoObject.geometry.getCoordinates(); + if(callback){ + callback(); + } + }, function (err) { + // Если геокодирование не удалось, сообщаем об ошибке + $window.alert(err.message); + }) + }); + } + }; + + var mapInit = function(){ + scope.yaBeforeInit(); + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + if(options && options.projection){ + options.projection = new ymaps.projection[options.projection.type](options.projection.bounds); + } + scope.map = new ymaps.Map(element[0],{ + center: center, + zoom:zoom, + type:attrs.yaType || 'yandex#map', + behaviors:enableBehaviors + }, options); + scope.map.behaviors.disable(disableBehaviors); + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(scope.map, parentGet,key,scope); + } + } + + scope.yaAfterInit({$target:scope.map}); + element.append(childNodes); + setTimeout(function(){ + scope.$apply(function() { + $compile(childNodes)(scope.$parent); + }); + }); + }; + + scope.$watch('yaCenter',function(newValue){ + center = getEvalOrValue(newValue); + setCenter(function(){ + scope.map.setCenter(center); + }); + }); + scope.$watch('yaType',function(newValue){ + if(newValue){ + scope.map.setType(newValue); + } + }); + + scope.$on('$destroy',function(){ + if(scope.map){ + scope.map.destroy(); + } + }); + + setCenter(mapInit); + }; + }, + controller: 'YaMapCtrl' + }; + }]). + + controller('MapToolbarCtrl',['$scope',function($scope){ + this.add = function(control){ + $scope.toolbar.add(control); + }; + }]). + directive('yaToolbar',['$compile','$parse','yaSubscriber',function($compile,$parse,yaSubscriber){ + return { + require:'^yaMap', + restrict:'E', + scope:{ + yaAfterInit:'&' + }, + compile:function(tElement){ + var childNodes = tElement.contents(); + tElement.html(''); + return function(scope, element,attrs,yaMap) { + if(!attrs.yaName){ + throw new Error('not pass attribute "name"'); + } + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + var params = attrs.yaParams ? scope.$eval(attrs.yaParams) : undefined; + var className = attrs.yaName[0].toUpperCase() + attrs.yaName.substring(1); + scope.toolbar = new ymaps.control[className](params); + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(scope.toolbar, parentGet,key,scope); + } + } + yaMap.addControl(scope.toolbar,options); + scope.yaAfterInit({$target:scope.toolbar}); + element.append(childNodes); + $compile(childNodes)(scope.$parent); + }; + }, + controller:'MapToolbarCtrl' + }; + }]). + + directive('yaControl',['yaSubscriber','templateLayoutFactory','$parse',function(yaSubscriber,templateLayoutFactory,$parse){ + return { + restrict:'E', + require:'^yaToolbar', + scope:{ + yaAfterInit:'&' + }, + link:function(scope,elm,attrs,mapToolbar){ + var className = attrs.yaType[0].toUpperCase() + attrs.yaType.substring(1); + var getEvalOrValue = function(value){ + try{ + return scope.$eval(value); + }catch(e){ + return value; + } + }; + var params = getEvalOrValue(attrs.yaParams); + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + if(options && options.layout){ + options.layout = templateLayoutFactory.get(options.layout); + } + if(options && options.itemLayout){ + options.itemLayout = templateLayoutFactory.get(options.itemLayout); + } + var withoutParams = ['SearchControl','SmallZoomControl','ScaleLine','ZoomControl']; + var obj; + if(withoutParams.indexOf(className)>-1){ + obj = new ymaps.control[className](options); + }else{ + if(params && params.items){ + var items = []; + var item; + for (var i = 0, ii = params.items.length; i < ii; i++) { + item = params.items[i]; + items.push(new ymaps.control.ListBoxItem(item)); + } + params.items=items; + } + obj = new ymaps.control[className](params,options); + } + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(obj, parentGet,key,scope); + } + } + mapToolbar.add(obj); + scope.yaAfterInit({$target:obj}); + } + }; + }]). + + controller('CollectionCtrl',['$scope',function($scope){ + this.addGeoObjects = function(geoObject){ + $scope.collection.add(geoObject); + }; + this.removeGeoObjects = function(geoObject){ + $scope.collection.remove(geoObject); + }; + }]). + directive('yaCollection',['$compile','yaMapSettings','$timeout','yaSubscriber','$parse', + function($compile,yaMapSettings,$timeout,yaSubscriber,$parse){ + return { + require:'^yaMap', + restrict:'E', + scope:{ + yaAfterInit:'&' + }, + compile:function(tElement){ + var childNodes = tElement.contents(); + tElement.html(''); + return function(scope, element,attrs,yaMap) { + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : {}; + + var showAll = angular.isDefined(attrs.showAll) && attrs.showAll!='false'; + if(showAll){ + var map = yaMap.getMap(); + var timeout; + var addEventHandler = function(){ + if(timeout){ + $timeout.cancel(timeout); + } + timeout = $timeout(function(){ + map.geoObjects.events.remove('add',addEventHandler); + var bounds = map.geoObjects.getBounds(); + if(bounds){ + map.setBounds(bounds); + } + }, 300); + }; + map.geoObjects.events.add('add',addEventHandler); + } + scope.collection = new ymaps.GeoObjectCollection({},options); + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(scope.collection, parentGet,key,scope); + } + } + + yaMap.addGeoObjects(scope.collection); + scope.yaAfterInit({$target:scope.collection}); + scope.$on('$destroy', function () { + if (scope.collection) { + yaMap.removeGeoObjects(scope.collection); + } + }); + element.append(childNodes); + $compile(childNodes)(scope.$parent); + }; + }, + controller:'CollectionCtrl' + }; + }]). + + directive('yaCluster',['yaMapSettings','yaSubscriber','$compile','templateLayoutFactory','$parse',function(yaMapSettings,yaSubscriber,$compile,templateLayoutFactory,$parse){ + return { + require:'^yaMap', + restrict:'E', + scope:{ + yaAfterInit:'&' + }, + compile:function(tElement){ + var childNodes = tElement.contents(); + tElement.html(''); + return function(scope, element,attrs,yaMap) { + var collectionOptions = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : {}; + if(collectionOptions && collectionOptions.clusterBalloonMainContentLayout){ + collectionOptions.clusterBalloonMainContentLayout = + templateLayoutFactory.get(collectionOptions.clusterBalloonMainContentLayout) + } + if(collectionOptions && collectionOptions.clusterBalloonSidebarItemLayout){ + collectionOptions.clusterBalloonSidebarItemLayout = + templateLayoutFactory.get(collectionOptions.clusterBalloonSidebarItemLayout); + } + if(collectionOptions && collectionOptions.clusterBalloonContentItemLayout){ + collectionOptions.clusterBalloonContentItemLayout = + templateLayoutFactory.get(collectionOptions.clusterBalloonContentItemLayout); + } + if(collectionOptions && collectionOptions.clusterBalloonAccordionItemContentLayout){ + collectionOptions.clusterBalloonAccordionItemContentLayout = + templateLayoutFactory.get(collectionOptions.clusterBalloonAccordionItemContentLayout); + } + //включение кластеризации + scope.collection = new ymaps.Clusterer(collectionOptions); + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(scope.collection, parentGet,key,scope); + } + } + + yaMap.addGeoObjects(scope.collection); + scope.yaAfterInit({$target:scope.collection}); + scope.$on('$destroy', function () { + if (scope.collection) { + yaMap.removeGeoObjects(scope.collection); + } + }); + element.append(childNodes); + $compile(childNodes)(scope.$parent); + }; + }, + controller:'CollectionCtrl' + }; + }]). + + directive('yaGeoObject',['GEOMETRY_TYPES','yaSubscriber','templateLayoutFactory','$parse',function(GEOMETRY_TYPES,yaSubscriber,templateLayoutFactory,$parse){ + return { + restrict:'E', + require:['^yaMap','?^yaGeoObjects','?^yaCluster'], + scope:{ + yaSource:'=', + yaShowBalloon:'=', + yaAfterInit:'&' + }, + link:function(scope,elm,attrs,ctrls){ + var ctrl = ctrls[2] || ctrls[1] || ctrls[0], + obj; + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + if(options && options.balloonContentLayout){ + options.balloonContentLayout = templateLayoutFactory.get(options.balloonContentLayout); + } + var createGeoObject = function(from, options){ + obj = new ymaps.GeoObject(from, options); + //подписка на события + for(var key in attrs){ + if(key.indexOf('yaEvent')===0){ + var parentGet=$parse(attrs[key]); + yaSubscriber.subscribe(obj, parentGet,key,scope); + } + } + ctrl.addGeoObjects(obj); + scope.yaAfterInit({$target:obj}); + checkEditing(attrs.yaEdit); + checkDrawing(attrs.yaDraw); + checkShowBalloon(scope.yaShowBalloon); + }; + scope.$watch('yaSource',function(newValue){ + if(newValue){ + if(obj){ + obj.geometry.setCoordinates(newValue.geometry.coordinates); + if (obj.geometry.getType() === GEOMETRY_TYPES.CIRCLE) { + obj.geometry.setRadius(newValue.geometry.radius); + } + var properties = newValue.properties; + for(var key in properties){ + if(properties.hasOwnProperty(key)){ + obj.properties.set(key, properties[key]); + } + } + }else{ + createGeoObject(newValue,options); + } + }else if(obj){ + ctrl.removeGeoObjects(obj); + } + },angular.equals); + var checkEditing = function(editAttr){ + if(angular.isDefined(editAttr) && editAttr!=='false'){ + if(obj){ + obj.editor.startEditing() + } + }else if(angular.isDefined(editAttr)){ + if(obj){ + obj.editor.stopEditing(); + } + } + }; + var checkDrawing = function(drawAttr){ + if(angular.isDefined(drawAttr) && drawAttr!=='false'){ + if(obj){ + obj.editor.startDrawing() + } + }else if(angular.isDefined(drawAttr)){ + if(obj){ + obj.editor.stopDrawing(); + } + } + }; + var checkShowBalloon = function(newValue){ + if(newValue){ + if(obj){ + obj.balloon.open(); + } + }else{ + if(obj){ + obj.balloon.close(); + } + } + }; + attrs.$observe('yaEdit',checkEditing); + attrs.$observe('yaDraw',checkDrawing); + scope.$watch('yaShowBalloon',checkShowBalloon); + scope.$on('$destroy', function () { + if (obj) { + ctrl.removeGeoObjects(obj); + } + }); + } + }; + }]). + + directive('yaHotspotLayer',[function(){ + return { + restrict:'E', + require:'^yaMap', + link:function(scope,elm,attrs,yaMap){ + if(!attrs.yaUrlTemplate){ + throw new Error('not exists required attribute "url-template"'); + } + if(!attrs.yaKeyTemplate){ + throw new Error('not exists required attribute "key-template"'); + } + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + yaMap.addHotspotLayer(attrs.yaUrlTemplate, attrs.yaKeyTemplate, options); + } + } + }]). + + directive('yaImageLayer',[function(){ + return { + restrict:'E', + require:'^yaMap', + link:function(scope,elm,attrs,yaMap){ + if(!attrs.yaUrlTemplate){ + throw new Error('not exists required attribute "url-template"'); + } + var options = attrs.yaOptions ? scope.$eval(attrs.yaOptions) : undefined; + yaMap.addImageLayer(attrs.yaUrlTemplate, options); + } + } + }]);