Клуб API Карт

Пользовательский макет балуна для ObjectManager

Игорь Чамин
10 мая 2017, 15:32

Мне нужно сформировать карту следующим образом, метки делятся на две категории (район, медицинское учреждение). Сначало на карту выводятся метки районов. При выборе метки с районом текущие метки удаляются и прорисовываются метки медицинских учреждений относящихся к этому району. Любая метка содержит информацию которую нужно вывести в балун при выборе. Пример того что я уже сделал miac58.ru/maps_lpu Сейчас информацию меток региона я вывожу в хинт, что бы клик по метки использовать как событие для "открытия" региона.  Я хочу сделать везде балун, а событие назначить на ссылку типа "Подробнее" в подвале балуна. Проблема в том что я не увижу объекты из события onclick ссылки. Ознакомившись с документацией, с примерами я вроде понял что мне нужно описать шаблон балуна а там я смогу описать событие клика по ссылке. Правильно? Вот этим примером я пользовался.  У меня не получается(  Помогите.

var myMap;
var his, hisZoom, hisCenter;
var listBoxControl;
ymaps.ready(
function (){
myMap = new ymaps.Map (
	"map",{
		center: [53.19, 44.43],
		zoom: 8, 
		controls: ['zoomControl', 'typeSelector', 'fullscreenControl']
	}
);
var MyBalloonLayout = ymaps.templateLayoutFactory.createClass(
	'<div class="popover top">' +
		'<a class="more" href="#">Подробнее</a>' +
		'<div class="arrow"></div>' +
		'<div class="popover-inner">' +
			'$[[options.contentLayout observeSize minWidth=235 maxWidth=235 maxHeight=350]]' +
		'</div>' +
	'</div>'
	,
	{
	build: function () {
		this.constructor.superclass.build.call(this);
		this._$element = $('.popover', this.getParentElement());
		this.applyElementOffset();
		this._$element.find('.more')
			.on('click', $.proxy(this.onMoreClick, this));
	},
	onSublayoutSizeChange: function () {
		MyBalloonLayout.superclass.onSublayoutSizeChange.apply(this, arguments);

		if(!this._isElement(this._$element)) {
			return;
		}

		this.applyElementOffset();

		this.events.fire('shapechange');
	},
	applyElementOffset: function () {
		this._$element.css({
			left: -(this._$element[0].offsetWidth / 2),
			top: -(this._$element[0].offsetHeight + this._$element.find('.arrow')[0].offsetHeight)
		});
	},
	onMoreClick: function (e) {
				   
		alert('УРА!');
	},
	getShape: function () {
		if(!this._isElement(this._$element)) {
			return MyBalloonLayout.superclass.getShape.call(this);
		}

		var position = this._$element.position();

		return new ymaps.shape.Rectangle(new ymaps.geometry.pixel.Rectangle([
			[position.left, position.top], [
				position.left + this._$element[0].offsetWidth,
				position.top + this._$element[0].offsetHeight + this._$element.find('.arrow')[0].offsetHeight
			]
		]));
	},
	_isElement: function (element) {
		return element && element[0] && element.find('.arrow')[0];
	}
	}
);

var MyBalloonContentLayout = ymaps.templateLayoutFactory.createClass(
	'<h3 class="popover-title">$[properties.balloonContentHeader]</h3>' +
	'<div class="popover-content">$[properties.balloonContentBody]</div>'
);

var objectManager = new ymaps.ObjectManager({geoObjectBalloonLayout: MyBalloonLayout, geoObjectBalloonContentLayout:  MyBalloonContentLayout});
$.ajax({
	url: "/maps_lpu/json"
}).done(function(data) {
	objectManager.add(data);
});
myMap.geoObjects.add(objectManager);
button = new ymaps.control.Button({
	data : {
		content : 'Назад',
		title : 'Назад'
	},
	options : {
		visible: false
	}
});				
button.events.add('click', function () {
	button.options.set('visible', false);
	myMap.setCenter(hisCenter, hisZoom); 
	objectManager.objects.removeAll();
	objectManager.add(his);
	myMap.geoObjects.add(objectManager);
});
	
myMap.controls.add(button, {float:'left'})




var myListBoxItems = [];

//здесь вырезано заполнение списка (php)

    var listBoxItems =  myListBoxItems.map(function(title) {
            return new ymaps.control.ListBoxItem({
                data: {
                    content: title
                },
                state: {
                    selected: true
                }
            })
        }),
        // Теперь создадим список, содержащий 5 пунктов.
        listBoxControl = new ymaps.control.ListBox({
            data: {
                content: 'Фильтр',
                title: 'Фильтр'
            },
            items: listBoxItems,
            state: {
                // Признак, развернут ли список.
                expanded: false,
                filters: listBoxItems.reduce(function(filters, filter) {
                    filters[filter.data.get('content')] = filter.isSelected();
                    return filters;
                }, {})
            }
        });
    myMap.controls.add(listBoxControl);
	
    // Добавим отслеживание изменения признака, выбран ли пункт списка.
    listBoxControl.events.add(['select', 'deselect'], function(e) {
        var listBoxItem = e.get('target');
        var filters = ymaps.util.extend({}, listBoxControl.state.get('filters'));
        filters[listBoxItem.data.get('content')] = listBoxItem.isSelected();
        listBoxControl.state.set('filters', filters);
    });

    var filterMonitor = new ymaps.Monitor(listBoxControl.state);
    filterMonitor.add('filters', function(filters) {
        // Применим фильтр.
        objectManager.setFilter(getFilterFunction(filters));
    });

    function getFilterFunction(categories){
        return function(obj){
            var content = obj.properties.typeTitle;
            return categories[content]
        }
    }




});

7 комментариев
Зачем вам пример с автопозиционированием? у вас же нет изменяющегося по высоте содержимого.
Можно посмотреть простой пример макета содержимого балуна
https://tech.yandex.ru/maps/jsbox/2.1/placemark_balloon_layout
Игорь Чамин
11 мая 2017, 09:23
dimik,
Да, я сделал как в этом примере, балун пустой и при изменения масштаба карта подвисает.  Дело в том что они показывают пример на геообъекте а я менеджер объектов использую. Мне кажется из за этого.
вот код
var myMap;
var his, hisZoom, hisCenter;
var listBoxControl;
ymaps.ready(
function (){
myMap = new ymaps.Map (
"map",{
center: [53.19, 44.43],
zoom: 8,
controls: ['zoomControl', 'typeSelector', 'fullscreenControl']
}
);
var MyBalloonContentLayout = ymaps.templateLayoutFactory.createClass(
'<h3 class="popover-title">$[properties.balloonContentHeader]</h3>' +
'<div class="popover-content">$[properties.balloonContentBody]</div>'+
'<div class="popover-footer"> <a href="#" id="more">Подробнее</a></div>',
{
build: function() {
BalloonContentLayout.superclass.build.call(this);
$('#more').bind('click', this.onMoreClick);
},
clear: function() {
$('#more').unbind('click', this.onMoreClick);
BalloonContentLayout.superclass.clear.call(this);
},
onMoreClick: function() {
alert('УРА');
}
}
);
var objectManager = new ymaps.ObjectManager({geoObjectBalloonContentLayout: MyBalloonContentLayout});
$.ajax({
url: "/maps_lpu/json"
}).done(function(data) {
objectManager.add(data);
});
myMap.geoObjects.add(objectManager);
button = new ymaps.control.Button({
data : {
content : 'Назад',
title : 'Назад'
},
options : {
visible: false
}
});    
Игорь Чамин,
у вас опечатка в build - пропущен "My"
var MyBalloonContentLayout = ...
BalloonContentLayout.superclass.build.call(this);
Игорь Чамин
11 мая 2017, 16:13
dimik,
Спасибо!
А как в onMoreClick получить ссылку на выбранную метку?

то есть я раньше делал это так
function onObjectEvent (e) {
.....
objectId = e.get(\'objectId\');
.......
myMap.setCenter(objectManager.objects.getById(objectId).geometry.coordinates, 10);
а как теперь? 
Обновлено 11 мая 2017, 16:13
Игорь Чамин,
посмотрите в this.getData()
Игорь Чамин
12 мая 2017, 09:20
dimik,
 alert(this.getData()); не выводит ничего... даже окна нет, наверное потому что нет такого метода. Я оставил событие по клику на метки, в глобальную переменную записываю идентификатор метки, а при обработки события по нажатии ссылки пользуюсь этой переменной, костыль какой то получился) 
Игорь Чамин,
Дайте ссылку на этот код или соберите пример на jsfiddle, по коду в посте сложно сказать