Клуб API Карт

не работает перетаскивание маршрута

ya.bodim
18 октября 2013, 13:31

Добрый день.

Сделал на примере рассчета стоимости из песочницы Яндекс API. Не могу понять почему не работает перетаскивание маршрута. Что делаю не так? Код ниже:

 

  function init() {
    myMap = new ymaps.Map('map', {
            center: [55.76, 37.64],
            zoom: 10,
            type: 'yandex#map',
            behaviors: ['scrollZoom', 'drag']
        }),
        search = new ymaps.control.SearchControl({
            useMapBounds: true,
            noCentering: true,
            noPlacemark: true
        }),
            search2 = new ymaps.control.SearchControl({
            useMapBounds: true,
            noCentering: true,
            noPlacemark: true
        }),

        calculator = new DeliveryCalculator(myMap, myMap.getCenter());

    myMap.controls.add(search, { right: 5, top: 5 });
    myMap.controls.add(search2, { right: 260, top: 5 });
            myMap.controls
        // Кнопка изменения масштаба.
        .add('zoomControl', { left: 5, top: 5 })
        // Список типов карты
        .add('typeSelector', { left: 229, top: 5 })
        .add('mapTools', { left: 35, top: 5 });
          var trafficControl = new ymaps.control.TrafficControl();
        myMap.controls
        .add('trafficControl', {left: 131, top: 5})
        .add(new ymaps.control.MiniMap({
            type: 'yandex#publicMap'
        }));
    search.events.add('resultselect', function (e) {
        var results = search.getResultsArray(),
            selected = e.get('resultIndex'),
            point = results[selected].geometry.getCoordinates();
        calculator.setStartPoint(point);
    });
     search2.events.add('resultselect', function (e2) {
        var results2 = search2.getResultsArray(),
            selected2 = e2.get('resultIndex'),
            point2 = results2[selected2].geometry.getCoordinates();
        calculator.setFinishPoint(point2);
    });

}
var start = null;
var finish = null;

function DeliveryCalculator(map, finish) {
    this._map = map;
    this._start = null;
    this._finish = null;
    this._route = null;
    myMap.events.add('click', this._onClick, this);
}
var ptp = DeliveryCalculator.prototype;

    ptp._onClick = function (e) {
        var position = e.get('coordPosition');

        if(!this._start) {
            finish = null;

            this._start = new ymaps.Placemark(position,        
            {
            iconContent: "Поставщик",
            hintContent: "Перетащите метку и кликните, чтобы узнать адрес"
            }, {
            draggable: "true",
            preset: "twirl#greenStretchyIcon",
            // Заставляем балун открываться даже если в нем нет содержимого.
            openEmptyBalloon: true
            });
           
            this._start.events.add('dragend', this._onDragEnd, this);
            this._map.geoObjects.add(this._start);
        } else if (!this._finish) {
            this._finish = new ymaps.Placemark(position,
                        {
            iconContent: "Заказчик",
            hintContent: "Перетащите метку и кликните, чтобы узнать адрес"
            }, {
            draggable: "true",
            preset: "twirl#redStretchyIcon",
            // Заставляем балун открываться даже если в нем нет содержимого.
            openEmptyBalloon: true
            });
            this._finish.events.add('dragend', this._onDragEnd, this);
            this._map.geoObjects.add(this._finish);
        } else {
            this._map.geoObjects.remove(this._start);
            this._start = null;
            this._map.geoObjects.remove(this._finish);
            this._finish = null;
            this._map.geoObjects.remove(this._route);
            this._route = null;
            start = null;
            finish = null;
        }
        this.getDirections();
    };
 
    ptp._onDragEnd = function (e) {
        this.getDirections();
    };

ptp.getDirections = function () {
    try
    {
    var self = this;
    start = this._start.geometry.getCoordinates();
    finish = this._finish.geometry.getCoordinates();
    if(this._route) {
        this._map.geoObjects.remove(this._route);
    }   

    ymaps.geocode(start, { results: 1 })
        .then(function (geocode) {
            var address = geocode.geoObjects.get(0) &&
                geocode.geoObjects.get(0).properties.get('balloonContentBody') || '';

            ymaps.route([start, finish])
                .then(function (router) {
                    self._route = router.getPaths();
                    self._route.options.set({ strokeWidth: 5, strokeColor: '0000ffff', opacity: 0.5 });
                    self._map.geoObjects.add(self._route);                  
                    var distance = Math.round(router.getLength() / 1000);
                    document.getElementById("txt4").value = distance;
                    dost_for_map();
                    var message = '<span>Расстояние: ' + distance + 'км.</span><br/>' +
                            '<span style="font-weight: bold; font-style: italic">Стоимость доставки: '+document.getElementById("txt12").value+'р.</span>';
                     self._start.properties.set('balloonContentBody', address + message);
                    self._start.balloon.open();
                    router.editor.start({ addWayPoints: true });
                });
        });
        }
        catch (e)  {}
};

ptp.setStartPoint = function (position) {
    if(this._start) {
        this._start.geometry.setCoordinates(position);
    }
    else {
        this._start = new ymaps.Placemark(position, //{ iconContent: 'Поставщик' }, { draggable: true });
            {
            iconContent: "Поставщик",
            hintContent: "Перетащите метку и кликните, чтобы узнать адрес"
            }, {
            draggable: "true",
            preset: "twirl#greenStretchyIcon",
            // Заставляем балун открываться даже если в нем нет содержимого.
            openEmptyBalloon: true
            });
 
           
        this._start.events.add('dragend', this._onDragEnd, this);
        this._map.geoObjects.add(this._start);
        //start = this._start.geometry.getCoordinates();

       
    }
    this.getDirections();
};

ptp.setFinishPoint = function (position) {
    if(this._finish) {
        this._finish.geometry.setCoordinates(position);
    }
    else {
        this._finish = new ymaps.Placemark(position, //{ iconContent: 'Заказчик' }, { draggable: true });
            {
            iconContent: "Заказчик",
            hintContent: "Перетащите метку и кликните, чтобы узнать адрес"
            }, {
            draggable: "true",
            preset: "twirl#redStretchyIcon",
            // Заставляем балун открываться даже если в нем нет содержимого.
            openEmptyBalloon: true
            });
           

           
           
        //this._finish.events.add('dragend', this._onFinishPointChange, this);
        this._finish.events.add('dragend', this._onDragEnd, this);
        this._map.geoObjects.add(this._finish);
        //finish = this._finish.geometry.getCoordinates();
    }
    this.getDirections();
};


ptp.calculate = function (len) {
    // Константы.
    var DELIVERY_TARIF = 20,
        MINIMUM_COST = 500;

    return Math.max(len * DELIVERY_TARIF, MINIMUM_COST);
};

ymaps.ready(init);

 

28 комментариев
Подписаться на комментарии к посту

Здравствуйте, 

в этом примере использовались недокументрированные поля события dragend. По счастливой случайности раньше код работал. А теперь перестал.

Вот корректная реализация примера

 

function init() {

    var myMap = new ymaps.Map('map', {

            center: [60.906882, 30.067233],

            zoom: 9,

            type: 'yandex#map',

            behaviors: ['scrollZoom', 'drag']

        }),

        search = new ymaps.control.SearchControl({

            useMapBounds: true,

            noCentering: true,

            noPlacemark: true

        }),

        calculator = new DeliveryCalculator(myMap, myMap.getCenter());

 

    myMap.controls.add(search, { right: 5, top: 5 });

 

    search.events.add('resultselect', function (e) {

        var results = search.getResultsArray(),

            selected = e.get('resultIndex'),

            point = results[selected].geometry.getCoordinates();

 

        calculator.setStartPoint(point);

    });

}

 

function DeliveryCalculator(map, finish) {

    this._map = map;

    this._start = null;

    this._finish = new ymaps.Placemark(finish, { iconContent: 'Б' });

    this._route = null;

 

    map.events.add('click', this._onStartPointChange, this);

    map.geoObjects.add(this._finish);

}

 

var ptp = DeliveryCalculator.prototype;

 

ptp._onStartPointChange = function (e) {

    this.setStartPoint(e.get('coordPosition'));

};

 

ptp._onDragEnd = function (e) {

    var target = e.get('target');

    this.setStartPoint(target.geometry.getCoordinates());

}

 

ptp.getDirections = function () {

    var self = this,

        start = this._start.geometry.getCoordinates(),

        finish = this._finish.geometry.getCoordinates();

 

    if(this._route) {

        this._map.geoObjects.remove(this._route);

    }

 

    ymaps.geocode(start, { results: 1 })

        .then(function (geocode) {

            var address = geocode.geoObjects.get(0) &&

                geocode.geoObjects.get(0).properties.get('balloonContentBody') || '';

 

            ymaps.route([start, finish])

                .then(function (router) {

                    var distance = Math.round(router.getLength() / 1000),

                        message = 'Расстояние: ' + distance + 'км.
' +

                            'Стоимость доставки: %sр.';

 

                    self._route = router.getPaths();

                    self._route.options.set({ strokeWidth: 5, strokeColor: '0000ffff', opacity: 0.5 });

                    self._map.geoObjects.add(self._route);

                    self._start.properties.set('balloonContentBody', address + message.replace('%s', self.calculate(distance)));

                    self._start.balloon.open();

                });

        });

};

 

ptp.setStartPoint = function (position) {

    if(this._start) {

        this._start.geometry.setCoordinates(position);

    }

    else {

        this._start = new ymaps.Placemark(position, { iconContent: 'А' }, { draggable: true });

        this._start.events.add('dragend', this._onDragEnd, this);

        this._map.geoObjects.add(this._start);

    }

    this.getDirections();

};

 

ptp.calculate = function (len) {

    // Константы.

    var DELIVERY_TARIF = 20,

        MINIMUM_COST = 500;

 

    return Math.max(len * DELIVERY_TARIF, MINIMUM_COST);

};

 

ymaps.ready(init);

Мы поправим пример в песочнице, чтобы больше никто об это не спотыкался, спасибо за ваше сообщение.

Так перетаскивание маршрута все равно не работает. Даже если в этот код подставить router.editror.start();

 Код, который я прислала, я скорпировала из песочницы, когда получила рабочий вариант. Можете прислать ссылку на ваш вариант исправленного кода?

код:

 

function init() {

    var myMap = new ymaps.Map('map', {

            center: [60.906882, 30.067233],

            zoom: 9,

            type: 'yandex#map',

            behaviors: ['scrollZoom', 'drag']

        }),

        search = new ymaps.control.SearchControl({

            useMapBounds: true,

            noCentering: true,

            noPlacemark: true

        }),

        calculator = new DeliveryCalculator(myMap, myMap.getCenter());

 

    myMap.controls.add(search, { right: 5, top: 5 });

 

    search.events.add('resultselect', function (e) {

        var results = search.getResultsArray(),

            selected = e.get('resultIndex'),

            point = results[selected].geometry.getCoordinates();

 

        calculator.setStartPoint(point);

    });

}

 

function DeliveryCalculator(map, finish) {

    this._map = map;

    this._start = null;

    this._finish = new ymaps.Placemark(finish, { iconContent: 'Б' });

    this._route = null;

 

    map.events.add('click', this._onStartPointChange, this);

    map.geoObjects.add(this._finish);

}

 

var ptp = DeliveryCalculator.prototype;

 

ptp._onStartPointChange = function (e) {

    this.setStartPoint(e.get('coordPosition'));

};

 

ptp._onDragEnd = function (e) {

    var target = e.get('target');

    this.setStartPoint(target.geometry.getCoordinates());

}

 

ptp.getDirections = function () {

    var self = this,

        start = this._start.geometry.getCoordinates(),

        finish = this._finish.geometry.getCoordinates();

 

    if(this._route) {

        this._map.geoObjects.remove(this._route);

    }

 

    ymaps.geocode(start, { results: 1 })

        .then(function (geocode) {

            var address = geocode.geoObjects.get(0) &&

                geocode.geoObjects.get(0).properties.get('balloonContentBody') || '';

 

            ymaps.route([start, finish])

                .then(function (router) {

                    var distance = Math.round(router.getLength() / 1000),

                        message = 'Расстояние: ' + distance + 'км.
' +

                            'Стоимость доставки: %sр.';

 

                    self._route = router.getPaths();

                    self._route.options.set({ strokeWidth: 5, strokeColor: '0000ffff', opacity: 0.5 });

                    self._map.geoObjects.add(self._route);

                    self._start.properties.set('balloonContentBody', address + message.replace('%s', self.calculate(distance)));

                    self._start.balloon.open();

                    router.editor.start();

                });

        });

};

 

ptp.setStartPoint = function (position) {

    if(this._start) {

        this._start.geometry.setCoordinates(position);

    }

    else {

        this._start = new ymaps.Placemark(position, { iconContent: 'А' }, { draggable: true });

        this._start.events.add('dragend', this._onDragEnd, this);

        this._map.geoObjects.add(this._start);

    }

    this.getDirections();

};

 

ptp.calculate = function (len) {

    // Константы.

    var DELIVERY_TARIF = 20,

        MINIMUM_COST = 500;

 

    return Math.max(len * DELIVERY_TARIF, MINIMUM_COST);

};

 

ymaps.ready(init);

 

 

 

 

Я взяла ваш код, скопировала и поместила в песочницу. Все работает как надо. Может быть у нас какое-то недопонимание? Что вы имеете в виду под перетаскиванием маршрута? У меня получается таскать конечную метку.

режим редактирования маршрута, когда наводишь на маршрут мышью, и есть возможность его подвинуть на соседнюю улицу или добавить путевую точку.

 Все, теперь я поняла. В этом примере на карту добавляется не сам маршрут, а вычленяются его составляющие и по отдельности добавляются на карту. 

                    self._route = router.getPaths();

                    self._route.options.set({ strokeWidth: 5, strokeColor: '0000ffff', opacity: 0.5 });

                    self._map.geoObjects.add(self._route);

Сам объект-router на карту не добавлен, поэтому у него и не включается редактирование.

 

А какая у вас задача глобально?

что бы добавление  было подобным образом. первый клик -1я метка, второй клик 2я метка и маршрут между 1ой и 2ой меткой. Далее, что бы его можно было подвинуть, либо добавить контрольные точки.

Я пробовал сделать подобное на примере из песочницы "Редактирование маршрута", но тогда добавляются еще метки начала и окончания маршрута. которые являются лишними.

Может можно просто добавить еще объект router? Но, как это сделать, что бы без лишних меток начала и окончания маршрута?

Вы хотите, чтобы по клику ставились 1я и 2я метки, но при этом вы не хотите, чтобы были метки начала и конца. А первая и вторая метки не являются метками начала и конца?

Это и есть метки начала  и конца маршрута. Просто я пробовал сделать на примере, который есть в песочнице (редактирование маршрута), он мне дополнительно еще 2 метки добавляет, итого их получается 4. А как сделать так, что бы он для текущих 2х меток строил маршрут, который можно двигать (редактировать), и более меток на кару не добавлял?

Может быть стоит удалить с карты свои метки и оставить только те, которые включены в маршрут?

нет, так не проще. потому что в данные метки со временем планируется добавляться информация. можно как то добавить маршрут с возможностью редактирования без меток начала и конца?

Вы можете переопределить стили для конечных точек.

Сделать свой макет, который будет по сути точкой (без дополнительных изображений) и передать его в опции маршрута.

router.getWayPoints().options.set('layout', myLayout);

 

На карте останется 4 точки, но точки маршрута не будут бросаться в глаза.

Т.е. необходимо создать свой слой, далее добавить объект router на карту, после чего путевые точки разместить на созданном слое: router.getWayPoints().options.set('layout', myLayout);

И тогда у меня будут видны мои добавленные кликами мышки по карте точки, будет виден построенный маршрту, с возможностью его редактирования и не будет видно точек  начала и окончания маршрута, т.к. они будут на другом слое. Так?

И как сделать свой макет, который будет по сути точкой (без дополнительных изображений), что бы потом передать его в опции маршрута?

Про слои речи не было.

У метки есть макет. Макет - это html-отображение метки. Вот идея в том, чтобы заменить стандартный макет метки (запятую) на html-макет, который будет выглядеть как точка.

Создать пустой макет можно так:

  var myLayout = ymaps.templateLayoutFactory.createClass('');

И потом передать этот пустой макет через опцию.

 

Все равно они выглядят как запятые:

ptp.getDirections = function () {
    var button = $('#editor'); 
    var startEditing = false;
    var self = this,
        start = this._start.geometry.getCoordinates(),
        finish = this._finish.geometry.getCoordinates();

    if(this._route) {
        this._map.geoObjects.remove(this._route);
    }

    ymaps.geocode(start, { results: 1 })
        .then(function (geocode) {
            var address = geocode.geoObjects.get(0) &&
                geocode.geoObjects.get(0).properties.get('balloonContentBody') || '';

            ymaps.route([start, finish])
                .then(function (router) {
                    var distance = Math.round(router.getLength() / 1000),
                        message = 'Расстояние: ' + distance + 'км.
' +
                            'Стоимость доставки: %sр.';
                     var myLayout = ymaps.templateLayoutFactory.createClass('');                
                    router.getWayPoints().options.set('la    yout', myLayout);
                    self._map.geoObjects.add(router);

        button.click(function () {
            if (startEditing == false) {
                // Включаем редактор.
                router.editor.start({ });
                button.val('Отключить редактор маршрута');
                startEditing = true;
            } else {
                // Выключаем редактор.
                router.editor.stop();
                button.val('Включить редактор маршрута');
                startEditing = false;
                distance = Math.round(router.getLength() / 1000);
            }
        });

                    //self._route = router.getPaths();
                    //self._route.options.set({ strokeWidth: 5, strokeColor: '0000ffff', opacity: 0.5 });
                    //self._map.geoObjects.add(self._route);
                   self._start.properties.set('balloonContentBody', address + message.replace('%s', self.calculate(distance)));;
                    self._start.balloon.open();
                });
        });
};



У вас опция 'la  yout' написана с пробелами. Если так и есть в исходном коде, то оно не  будет работать.

это так из песочницы скопировалось. По факту там пробела не было и не работает.

Я посмотрела в доке - опция для иконки метки не layout, а iconLayout. Вот копия рабочего кода из песочницы.

 

ymaps.ready(init);

 

function init() {

    var myMap = new ymaps.Map("map", {

            center: [57.131311, 34.576128],

            zoom: 5

        }),

        // Признак начала редактирования маршрута.

        startEditing = false,

        button = $('#editor');

 

    // Построение маршрута от станции метро Смоленская до станции Третьяковская.

    // Маршрут должен проходить через метро "Арбатская".

    ymaps.route([

        'Москва, метро Смоленская',

        {

            // Метро Арбатская - транзитная точка (проезжать через эту точку,

            // но не останавливаться в ней).

            type: 'viaPoint',

            point: 'Москва, метро Арбатская'

        },

        // Метро "Третьяковская".

        [55.74062, 37.62561]

    ], {

        // Автоматически позиционировать карту.

        mapStateAutoApply: true

    }).then(function (route) {

        route.getWayPoints().options.set('iconLayout', ymaps.templateLayoutFactory.createClass(''));

        myMap.geoObjects.add(route);

        button.click(function () {

            if (startEditing = !startEditing) {

                // Включаем редактор.

                route.editor.start({ addWayPoints: true });

                button.val('Отключить редактор маршрута');

            } else {

                // Выключаем редактор.

                route.editor.stop();

                button.val('Включить редактор маршрута');

            }

        });

    }, function (error) {

        alert("Возникла ошибка: " + error.message);

    });

}

Спасибо большое, работает. А можно удалять маршрут нажатием на карту, как в примере сделано в функции getDirections?

    if(self._map) {
        self._map.geoObjects.remove(self._map);
    }

map.geoObjects.remove(route);

Это понятно, что так можно, но вот проблема. не удаляет при клике на карту:

 

var r=null;
ptp.getDirections = function () {
    var button = $('#editor');
    var startEditing = false;
    var self = this,
        start = this._start.geometry.getCoordinates(),
        finish = this._finish.geometry.getCoordinates();
    if(r) {
        this._map.geoObjects.remove(r);
    }

    ymaps.geocode(start, { results: 1 })
        .then(function (geocode) {
            var address = geocode.geoObjects.get(0) &&
                geocode.geoObjects.get(0).properties.get('balloonContentBody') || '';

            ymaps.route([start, finish])
                .then(function (router) {
                    var distance = Math.round(router.getLength() / 1000),
                        message = 'Расстояние: ' + distance + 'км.
' +
                            'Стоимость доставки: %sр.';
                     var myLayout = ymaps.templateLayoutFactory.createClass('');               
                    router.getWayPoints().options.set('iconLayout', myLayout);
        r = router.getPaths();
self._map.geoObjects.add(router);
        button.click(function () {
            if (startEditing == false) {
                // Включаем редактор.
                router.editor.start({ });
                button.val('Отключить редактор маршрута');
                startEditing = true;
            } else {
                // Выключаем редактор.
                router.editor.stop();
                button.val('Включить редактор маршрута');
                startEditing = false;
                distance = Math.round(router.getLength() / 1000);        self._map.geoObjects.remove(router);
            }
        });
             self._start.properties.set('balloonContentBody', address + message.replace('%s', self.calculate(distance)));;
                    self._start.balloon.open();
                });
        });
};

получается я в переменную r возвращаю кол-цию путевых точек маршрута. Потом при следующем запуске функции пробую удалить все, но не удаляется ничего.

Я немного не понимаю, зачем вам удалять только часть маршрута, почему бы не удалять его целиком.

Сейчас по идее у вас должны удаляться линии маршрута, а промежуточные точки останутся на карте.

Просто поотлаживайте код, посмотрите, что в переменной r, заходит ли программа вообще в ту ветку кода или нет и тд.

r возвращает [object object], т.е. заходит в эту ветку кода, но ничего не удаляет. Далее рисует новую линию маршрута и все.

Участок маршрута прикреплен к маршруту, а не напрямую к карте. Чтобы его удалить, нужно написать

route.getPaths().setParent(null);

 

У вас удалится часть маршрута, а промежуточные точки останутся на карте.

Отлично, работает, только видимо нужно полностью маршрут удалять, потому что он возвращает потом длину всех маршрутов, которые были. А по клику в пустое место карты, он старый маршрут не дает удалить, потому что не знает, что такое router.

    Спасибо еще раз большое запомощь.  

С удалением разобрался.

Пожалуйста)