Клуб API Карт

Найдено на тему «коллекция»:
Циклическое создание полигонов по координатам из файла или вручную при их отсутствии
lolwut-lol
31 мая 2017, 01:51

Заранее прошу извинения за ОЧЕНЬ длинный пост, но считаю, что развёрнутое и подробное объяснение гораздо полезнее двух-трёх строк и страницы кода. Готов показать любые логи консоли и дать весь код целиком.

Есть некоторый JSON файл, в котором есть массив из N объектов. Каждый из объектов, помимо некоторых данных (обрабатываются в непосредственной связи с полигонами, поэтому сам код для обработки даже не начинал писать), может хранить в себе координаты в трёхмерном массиве (начальное значение ключа везде " "). В самом скрипте координаты из строк переводятся в числа и по ним вполне себе строится полигон. 

Карта области изначально строится в схематическом виде, с помощью фотошопа и небольших костылей на неё накладываются те же дома/здания из вида со спутника. Полигон служит для обводки каждого дома, цвет зависит от "типа здания" (жилой дом, школа, магазин и т. д.). Использование схематической карты и готовых зданий гарантированно лишь сейчас, потому что потом, возможно, придётся рисовать планы ещё не застроенных участков, для которых нельзя средствами API просто определить координаты зданий, но можно вручную построить полигоны по уже наложенному на карту "плановому" изображению и сохранить их координаты.

Требуется после получения JSON-данных пройтись по массиву, и если координаты уже есть, то построить полигон (или добавить в коллекцию для дальнейшего построения). Если же координат нет, то запустить редактор, в котором один из пунктов меню позволяет завершить рисование и AJAX-запросом отправить координаты нового полигона для соответствующего объекта в JSON-файл.

Потом и кровью заставил координаты отправляться и даже сохранил полигон для первого объекта (изначально for отсутствовал и везде стоял индекс 0), затем начал расширять масштабы деятельности и наткнулся сразу на несколько проблем, описанных после кода.

Последняя версия выглядит вот так. В ней решены все проблемы с jQuery, с самим редактором и окраской, остались лишь специфичные для API Яндекс.Карт вопросы, которые не задашь просто так на каком-нибудь StackOverflow (в гугле и блоге тоже не нашёл). Убрал не имеющие отношения к вопросу части кода и добавил несколько объяснений.

ymaps.ready(init);

function init() {

//Тут создаётся карта

//Тут немного кода для наложения картинки

//Коллекция с объектами, для которых уже заданы координаты в JSON
 var buildingsOverlay = new ymaps.GeoObjectCollection({},{});
 $.getJSON("data/strogi.json",function(objdata){
  console.log(".getJSON success");
 })
 .done(function(objdata){
//Создаю и задаю "шаблонный" полигон тут
//Пытался решить проблему с несовпадением 
//индексов рисуемого и отправляемого объекта
//Подозревал задание пункта меню в for 
//даже при единоразовом создании меню проблема остаётся
   var tempPol = new ymaps.Polygon([],{},{
    fillColor: "#BBBBBB",
    opacity: 0.3,
    strokeColor: "#BBBBBB",
    strokeOpacity: 0.5,
    strokeWidth: 1
   });
   tempPol.editor.options.set({
    drawingCursor: "crosshair",
    maxPoints: 50,
    menuManager: function(menuItems, model){
     menuItems.push({
      id:"StopAndSend",
      title: "Завершить редактирование и отправить координаты",					
//count-1 стоит, так как при тесте двух объектов
//(индексы 0 и 1) 
//данные записывались в третий (индекс 2)
//и индекс менялся именно при нажатии на кнопку
      onClick: function(){
       console.log(count-1);
       tempPol.editor.stopDrawing();					
       var tempArr = tempPol.geometry.getCoordinates();
							
//Тут перевод координат в строки для валидности JSON
//Почти такой же код есть ниже
//с переводом строк в числа
							
       objdata.buildings[count-1].coords = tempArr;
							
//Проверял вид JSON, всегда координаты приписывались не туда
       console.log(JSON.stringify(objdata));
							
//Чтобы не отправить пустоту
       if (objdata.buildings[count-1].coords != " "){
        $.ajax({
         type: "POST",
         data: {json: JSON.stringify(objdata)},
         url: "writecoords.php",
         success: function(data){
          console.log("AJAX success");
         },
         error: function(){
          console.log("failed to send POST");
          alert("error");
         }
        });	
       }
      }
     });
     return menuItems;
    }
   });
//До трёх, потому что объектов много
//а тестировать все сразу очень долго
//Также при большем числе
//с имеющимся количеством возможных тестов
//новых вариантов появиться не должно
   for(count = 0; count < 3; count++){
    console.log(count);
    console.log(objdata.buildings[count]);
//"Шаблонный" полигон добавляется
//Дальше используется для редактирования 
//при пустых координаты у текущего объекта)
    strogino.geoObjects.add(tempPol);
    if(objdata.buildings[count].coords == " ") {
     console.log(count);
//Опустошение координат стоит, так как в предыдущих попытках
//Тот же "шаблонный" полигон использовался с готовыми координатами
//После чего добавлялся в коллекцию
     tempPol.geometry.setCoordinates([]);
     tempPol.editor.startDrawing();
    }
//Если координаты уже заданы
    else {
//Перевод координат JSON-объекта из строк в числа
     var coordArr = objdata.buildings[count].coords;
     for (var j = 0; j < coordArr[0].length; j++) {
      console.log(coordArr[0][j]);
      for (var k = 0; k < coordArr[0][j].length; k++) {
       var mn = parseFloat(coordArr[0][j][k]);
       coordArr[0][j][k] = mn;	
      }
     }
			
//Создание объекта по готовым координатам
     var newObj1 = new ymaps.Polygon([coordArr[0]],{},{
      fillColor: "#999999",
      strokeColor: "#999999",
      opacity: "0.4",
      strokeOpacity: "0.6",
      strokeWidth: "2"
     });
			
//Немного кода для установки цвета 
//по данным из JSON через 
//newObj1.options.set("fillColor", "#БлаБла"); и 
//newObj1.options.set("strokeColor", "#БлаБла"); 
//через if и switch, расположенный в else
			
     strogino.geoObjects.add(newObj1);
    }
   }			
 })
//Коллбеки .fail() и .always(), роли не играют
}

Как я понял после кучи мелких правок, экспериментов и выкидывания в консоль всего возможного, даже несмотря на цикл for, тупо упирающийся в развилку, из 3 объектов редактирование всегда вызывается для последнего: в консоли появляется первый объект, затем второй (с пустыми координатами), затем третий (также с пустыми координатами) и только после этого начинается редактирование.

После завершения рисования и отправки координат вместо нового курсора-прицела, который означает начало рисования, появляется обычная "рука" и карта становится завершённой.

Сохраняется всё, естественно, для последнего объекта, а второй (первый из пустых) так и остаётся пустым. Без count-1 в менюшке даже при цикле из ДВУХ возможных объектов objdata.buildings[0] и odjdata.buildings[1] пункт меню сохранял всё в objdata.buildings[2], что я проверял и несколькими вызовами всего объекта objdata, и вызовом objdata.buildings[1].coords в пункте меню, и выводами индексов на всех стадиях кода, и чтением JSON из файла после записи. Даже непосредственно JSON-файл смотрел.

Думал об использовании коллекции для сохранения готовых объектов, которые будут рисоваться в конце (а tempPol использовать только для постоянного рисования), но и тут ничего не помогло, пробовал сразу несколько способов. Заканчивалось несколькими разными ошибками:

  1. Объект tempPol создавался в цикле for и только потом следовала развилка. В else использовалось buildingsOverlay.add(tempPol); После добавления готового объекта (сначала выводились длины до и после добавления) в консоли появлялась ошибка (указанная строка с ошибкой показывала на следующее создание tempPol) о невозможности выполнения getParent на undefined.
  2. Использовать buildingsOverlay.set(count, tempPol);. Это я пробовал и при работе с одним объектом (0 вместо count), не работало вообще.
  3. Создавать в else{} объект newObj1, приписывать ему все свойства и координаты, затем добавлять в коллекцию. Успешно увеличивалась длина, вне else{} (в конце коллбека .done() и после окончания всей функции .getJSON()) длина становилась равной нулю.
  4. После задания нужных опций и координат у tempPol, использовать что-то вроде var newObj1 = tempPol; и записывать newObj1 в коллекцию, но эффект был совсем не тот -- newObj1 не становился геообъектом (в прицнипе, ожидаемо).

Смутно подозреваю, что я не очень правильно понял принцип работы геоколлекций, и добавленный в неё геообъект никуда не пропадает, поэтому его нельзя задавать заново.

За сегодня пришло в голову несколько новых идей:

  • Два раза делать .getJSON, в первый раз ТОЛЬКО рисовать, если есть объекты без координат, во второй раз нарисовать все объекты, т. к. наличие координат гарантированно;

Критичной проблемой является невозможность рисовать несколько полигонов подряд. Даже если else убрать и оставить только рисование при пустых координатах, в консоли сначала появляются два пустых объекта (при том, что в том же if, где стоит вывод в консоль, есть tempPol.editor.startDrawing(), т. е. вывод два раза, а рисуется один)

  • Добавлять объекты в коллекцию без присвоения объектов, сразу через buildingsOverlay.add(new ymaps.Polygon([coords[count]], {}, {});

Так можно избежать отсутствия возможности создать новый шаблонный полигон. Однако я уже не уверен в том, что можно дальше менять опции через buildingsOverlay.get(count).options.set();, как это делается для отдельных объектов, да и внезапное обнуление коллекции после else{} в коде не просто же так происходит.

  • В самом-самом начале хотел использовать ещё и коллекцию со временными объектами (в которой не было необходимости при работе с одним-двумя объектами) и дальнейшем переносе из временной коллекции в готовую, но эта идея упирается сразу в обе проблемы.

Можно, конечно, вернуться к редактированию по одному объекту, однако их число УЖЕ перевалило за пару десятков, и несмотря на возможную простоту обводки одного дома, столько раз менять везде индексы и обновлять карту довольно утомительно. Да и после отправки карты в пользование при добавлении новых объектов заказчик, очевидно, предпочтёт сразу добавить объект на карту, а не копаться в коде скрипта.

Конечные вопросы, с учётом всех нюансов:

  1. Возможно ли использование редактора в цикле при каждом его выполнении?
  2. Как правильно использовать коллекции для хранения изменяющегося числа объектов с возможностью дальнейшего изменения опций?

Также принимаю абсолютно любые советы по улучшению благовидности кода. Особенно интересует создание отдельных функций для редактирования полигона, отправки данных (если есть способ отправлять обратно не весь JSON объект, а только координаты, которые обработаются в php и будут записаны в JSON-файл, буду крайне рад услышать), изменения типа данных сохранённых координат. Последняя попытка создать обработку для всего трёхмерного массива сразу с использованием рекурсивного захода и Array.isArray() закончилась превышением максимального размера call stack, а моё желание сделать универсально и долгосрочно и без попыток всё это создать и отладить уже надолго растянуло создание скрипта.

    1 комментарий
    полигоны,коллекция,циклы
    Возможно ли получить .getBounds() у коллекции геообъектов, не добавляя их на карту?
    Удалённый пользователь
    14 августа 2016, 11:34

    Добавляю на карту несколько меток. В документации конструктора карты говорится, что вместо center и zoom можно передать bounds. Именно это я и хочу сделать, но .getBounds() у коллекции возвращает null. Видимо потому, что коллекция еще не добавлена на карту. Получается, что мне нужно сначала создать карту все же передав center и zoom в конструктор, потом добавить на карту коллекцию и только потом сделать setBounds карты. Но тогда заметен неприятный скачок: сначала центр в одном месте, потом происходит прыжок в другое и изменение зума.

    Есть ли способ решить данный вопрос ?

    2 комментария
    bounds,коллекция
    Не все регионы показываются
    pavelbrov
    29 мая 2016, 06:31

    Пытался через each вывести определенные регионы и заметил, что в цикл попадают только часть из них.

    Что я делаю не так?

    Для наглядности fiddle: https://jsfiddle.net/cja184df/3/

    Код скрипта :

    ymaps.ready(init);
    function init() {

      
        var myMap = new ymaps.Map('map',{
              center: [57.01, 41.00],
              zoom: 3,
              controls:['zoomControl']
            });


        ymaps.regions.load('RU', {
                lang: 'ru',
                quality: 1
            }).then(function (result) {
                var regions = result.geoObjects; 
                regions.each(function (reg) {
                  myMap.geoObjects.add(reg);
                });
          
            }, function () {
                //alert('No response');
            });
    }

    И еще заметил, что при добавлении в коллекцию полигонов, границы коллекции (getBounds) не определяются. Если добавить Placemark-и и полигоны, границы будут составляться на основе Placemark-ов, а полигоны не учитываются. Так и должно быть?

    4 комментария
    регионы,коллекция,полигон
    Зависание браузера на большом кол-ве объектов
    Удалённый пользователь
    1 июня 2015, 17:20

    Строго говоря, объектов не так уж и много, 3500. Но при попытке добавить их в геоколлекцию и вывести эту коллекцию на карту браузер просто умирает.

     

    Незначительно помогает, если объекты не добавлять в коллекцию, а сразу выводить на карту.  В этом случае браузер изрядно тормозит, но вскоре вытягивает отображение объектов. Однако, потом при взаимодействии с пользователем приходится заново отображать/скрывать эти объекты и все начинает  снова тупить.

     

    Объекты приходят из отдельного файла в виде JSON:

     

    Points.stores =  [{"id":"1", "name":"ТУТ ИМЯ", "lat":"55.751656", "lng":"37.71718", "descript":"ОПИСАНИЕ", "type":"ТИП", "sell":"1", "refill":"1" ,"refund":"0"},.....]

     

    После создания карты, обычным образом создаю метки:

     

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

                center: [55.754015, 37.618827],

                zoom: 15

            });

    collection = new ymaps.GeoObjectCollection();

    for (var i = 0; i < Points.stores.length; i++) {

                marker = new ymaps.Placemark([Points.stores[i].lat, Points.stores[i].lng], {

                        iconContent: i,

                        balloonContent: Points.stores[i].descript,

                        content: Points.stores[i].descript

                    },{

                        preset: 'islands#blueStretchyIcon'

                    });

                  collection.add(marker); //вот тут все умирает

    }

    map.geoObjects.add(collection);

     

    Пробовал создавать коллекции по запросу,  а не при инициализаии карты; вносить метки в атрибуты самих объектов Points, но работает хоть как-то только если уйти от коллекций. Где-то что-то я не замечаю. Прошу помощи.

    2 комментария
    коллекция,метка,API 2.1,коллекции
    список объектов на карте и ссылки на них
    ya.aligan
    18 мая 2015, 18:05

    Необходимо отобразить список квартир на карте и рядом html-блок со списком ссылок на эти объекты.
    При клике на ссылку карта зумируется и показывается данный объект на карте.
    Как это выглядит вот здесь - http://gyazo.com/6fe77b66b82fddd38a31b5a61e1a3773
    Собственно буду рад любой информации или примером где можно посмотреть реализацию, так как пока изучаю api карт.

    1 комментарий
    меню,метка,API 2.1,коллекция
    Открытие нескольких баллунов
    palatka-msk
    5 февраля 2015, 20:03

    Добрый день!

     

    Имеется небольшой и простой код в результате на карте появляются две метки.

    Как сделать так что бы сразу два балуна были открыты.

      
            myMap = new ymaps.Map("contact", { center: [55.90399648, 49.05702693], zoom: 5, controls: ["default"] });

            var myPlacemarkProvodnik = new ymaps.Placemark([55.90203528, 37.44876792], {
                hintContent: 'ООО ПРОВОДНИК',
                balloonContent: '<strong>ООО ПРОВОДНИК</strong>'
            });

            var myPlacemarkTehnoproekt = new ymaps.Placemark([55.18920373, 61.44156684], {
                hintContent: 'ООО ТехноПроект',
                balloonContent: '<strong>ООО ТехноПроект</strong>'
            });

            myCollection = new ymaps.GeoObjectCollection();
           
            myCollection
                .add(myPlacemarkProvodnik)
                .add(myPlacemarkTehnoproekt);
           
            myMap.geoObjects.add(myCollection);
       

    1 комментарий
    коллекция,API 2.1,балун
    Поиск по своим объектам загруженным из xml файла при помощи control.SearchControl
    Александр
    5 января 2015, 01:40

    Данная тема уже поднималась, но для себя ответа так и не смог найти. Пытаюсь сделать аналогично с примером ( Пример от Яндекса - поиск по своим объектам ), но проблема в том что объекты загружаются из xml-файла (xml файл). Не могу определиться даже с алгоритмом решения, толи мне из моих данных такой же массив сформировать и использовать функцию как в примере, толи есть какой то еще способ более правильный. Пожалуйста помогите!

    4 комментария
    API 2.1,поиск,контролы,YMapsML,коллекция,элементы управления
    Идентификатор для геобъекта
    tzhe
    26 сентября 2014, 13:39
    Создаю геобъекты и добавляю их в геоколлекцию.
    Вопрос: есть ли у геобъектов какой-то уникальный идентификатор, который можно задать, а затем по этому идентификатору искать соответствующий объект в коллекции?
    3 комментария
    коллекция,поиск объекта
    Как задать балун для геоколлекции
    tzhe
    26 сентября 2014, 08:17
    Привет, есть коллекция геобъектов: globalCollection, хочу задать для коллекции балун, чтобы при клике на любом объекте коллекции открывался одинаковый балун.
    Попробовал сделать так:
    globalCollection.properties['balloonContentBody'] = "Содержимое балуна";
    Но балун при клике не появляется.
    Подскажите как сделать.
    1 комментарий
    коллекция,балун
    (API 2.0) можно ли добавить несколько редактируемых полигонов в одну коллекцию?
    AntiMandron
    18 июня 2014, 13:04

    // инициализирую карту и добавляю на карту коллекцию

    ...

    myMapSearchAreaCollection = new ymaps.GeoObjectCollection();

     

    // добавить многоугольную область поиска
    function SearchAreaAddPolygon()
    {
    var myPolygonArea = new ymaps.GeoObject({geometry: {type: "Polygon", coordinates: []}});
    // myMap.geoObjects.add(myPolygonArea);
    myMapSearchAreaCollection.add(myPolygonArea);
    myPolygonArea.editor.startDrawing();
    myMapSearchAreaCollection.add(myPolygonArea);
    }

    можно ли так делать? это надо, чтобы потом одним кликом удалить все редактируемые многоугольники... что-то вроде

    myMapSearchAreaCollection.removeAll();

     

    или подскажите куда копать, чтобы можно было кнопкой добавить несколько редактируемых полигонов, а другой удалить их все

    5 комментариев
    коллекция,редактор геометрии,API 2.0,полигон
    События колекции полигонов
    Boarddog
    22 мая 2014, 15:26

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

     

     collectionGEO.events.add('geometrychange', function (event) { ....}   не подходит так как при окончании перетаскивания вершины полигона  имеем старые координаты вершины.

    Помогите пожалуйста.

    10 комментариев
    коллекция,API 2.1,события,полигон