Selections of geo objects

There are various actions you can perform when working with an interactive map with geo objects. For example, add to the map, change properties or options, assign an event handler, and so on. These are basic operations, and a corresponding function is defined for each of them in the API.

However, a developer often faces more difficult tasks. For example, you need to find geo objects that are located north of some geographical region (house, street, etc.). Or you need to find out whether a geo object falls into the geographical region of another object. The implementation of such tasks using standard API functions can lead to a significant expansion of the program code.

To simplify such tasks, the API has a built-in set of helper methods. These methods are wrappers for standard API functions. When using helper methods, you do not need to implement operations such as searching geo objects, detecting their position relative to each other, and many other operations.

As an example, the table below shows two ways of completing the same task.

Task: Make geo objects red if they fall within a draggable circle. But make all other geo objects blue (see the example in the sandbox).

Standard implementation

Implementation using helper methods

// All types of geo objects are included in the example: placemarks, lines, polygons, and others.
myCircle.events.add('drag', function () {
  for (var i = 0, l = myObjects.length; i < l; i++) {
    var contains = false;
    // For each type of geo object, a separate check is implemented for whether it falls within the circle..
    switch (myObjects[i].geometry.getType()) {
      case "Point":
        contains = myCircle.contains(myObjects[i].geometry.getCoordinates());
        break;
      case "Polygon":
        contains = true;
        var coordinates = myObjects[i].geometry.getCoordinates();
        for (var i = 0, l = coordinates.length; i < l && contains; i++) {
          for (var j = 0, k = coordinates[i].length; j < k && contains; j++) {
            if (!myCircle.contains(coordinates[i][j])) {
              contains = false;
            }
          }
        }
        break;
      case "Polyline":
      case "Rectangle":
        contains = true;
        var coordinates = myObjects[i].geometry.getCoordinates();
        for (var i = 0, l = coordinates.length; i < l && contains; i++) {
          if (!myCircle.contains(coordinates[i])) {
            contains = false;
          }
        }
        break;
        case "Circle":
          if (!myCircle.contains(myObjects[i].geometry.getCoordinates())) {
            contains = false;
            break;
          }
          var distance = myMap.options.get('projection').getCoordSystem().getDistance(
             myObjects[i].geometry.getCoordinates(),
                               myCircle.geometry.getCoordinates()
          );
          contains = distance + myObjects[i].geometry.getRadius() <= myCircle.geometry.getRadius();
        break;
    }
    if (contains) {
      myObjects[i].options.set({
        preset: 'islands#redIcon',
        fillColor: '#ff001a',
        strokeColor: '#ff001a'
      });
    } else {
      myObjects[i].options.set({
        preset: 'islands#blueIcon',
        fillColor: '#0081ff',
        strokeColor: '#0081ff'
      });
    }
  }
});
myCircle.events.add('drag', function () {
    // Geo objects that fall within the circle will be red.
    var objectsInsideCircle = objects.searchInside(myCircle);
    objectsInsideCircle.setOptions({
        preset: 'islands#redIcon',
        fillColor: '#ff001a',
        strokeColor: '#ff001a'
    });

    // The remaining objects will be blue.
    objects.remove(objectsInsideCircle).setOptions({
        preset: 'islands#blueIcon',
        fillColor: '#0081ff',
        strokeColor: '#0081ff'
    });
});
 

As seen in the example, helper methods can significantly simplify the programming code.

Helper methods are defined in the GeoQueryResult class. The GeoQueryResult object is called a geo object selection and consists of data storage with a special structure. The geo objects that actions will be performed on must first be added to this object. This can be any type of geo objects: placemarks, circles, rectangles, collections of them, and so on. However, they do not have to be placed on the map.

To create a GeoQueryResult selection, use the geoQuery function. It is passed the data source — geo objects that the selection will be based on.

var circle = new ymaps.Circle([[30, 42 ], 5000]);
//Adding a circle to the map
myMap.geoObjects.add(circle);
// Making the data source.
var objects = [
        new ymaps.Placemark([34, 56]),
        new ymaps.Rectangle([[34, 56], [36, 57]]),
        circle
    ],
    // Making the selection.
    storage = ymaps.geoQuery(objects);
// All the map's geo objects are passed to the selection as the data source
var storage = ymaps.geoQuery(myMap.geoObjects);

The geoQuery function can also form a selection of geo objects based on an asynchronous data source. For example, the data source may be the resulting data that will be received from the server. Since processing the request and response takes some time, geoQuery will wait for the source to be ready before making the selection:

// When the server returns the result, geoQuery will process data and construct the selection based on it.
ymaps.geoQuery(ymaps.geocode('Saint Petersburg'));

The geoQuery function returns the GeoQueryResult selection that was formed. Now various actions can be performed with its objects, using helper methods: add to the map, set properties or options, and so on. Various filters can also be applied to this selection to make new selections based on it.

The set of available methods for performing various operations with a selection and its geo objects is shown below:

1. Methods that perform operations on the selection

The selection is an ordered array of geo objects that have been selected by some criteria. As with normal arrays, various actions can be performed with the selection, such as adding or removing objects, sorting, putting its items in reverse order, and so on. The following methods are intended for use with an array of selected objects:

add

Adds new objects to the selection. It does not change the original GeoQueryResult selection, but creates a new one that contains the resulting set of geo objects.

var placemark = new ymaps.Placemark([34, 56]);
myGeoQueryResult.add(placemark);

For more information about the method, see the Reference guide.

getLength

Returns the number of items in the selection.

var result = ymaps.geoQuery(myMap.geoObject).searchIntersect(myPolygon);
alert('The number of geo objects that intersect with the polygon: ' + result.getLength());

For more information about the method, see the Reference guide.

remove

Removes objects from the selection. It does not change the original selection, but creates a new one that contains the resulting set of geo objects.

var objects = [
        new ymaps.Placemark([34, 56]),
        new ymaps.Rectangle([[34, 56], [36, 57]])
    ],
    result = ymaps.geoQuery(objects);
// Note that a different GeoQueryResult object will be obtained in the result, while the old one remains unchanged.
var newResult = result.remove(objects[1]);

For more information about the method, see the Reference guide.

reverse

Reverses the order of the items in the selection. Returns a new selection.

var result = ymaps.geoQuery(myMap.geoObjects).sort('x'),
    reversedResult = result.reverse();

For more information about the method, see the Reference guide.

slice

Returns a slice of the selection.

var result = ymaps.geoQuery(map.geoObjects).slice(0, 10);
alert('Number of items in the new selection:' + result.getLength());

For more information about the method, see the Reference guide.

sort

Sorts the selection by the given parameter.

var result = ymaps.geoQuery(myMap.geoObjects);
result.sort('lat').sort('x');

For more information about the method, see the Reference guide.

sortByDistance

Creates a new selection of items that are sorted by their distance from the specified object.

var result = ymaps.geoQuery(objects).addToMap(myMap),
    polyline = new ymaps.Polyline([[35, 65], [35, 66], [34, 62], [34, 63]]);
myMap.geoObjects.add(polyline);
var sortedByPolyline = result.sortByDistance(polyline);

For more information about the method, see the Reference guide.

2. Methods for accessing a selection item

The following methods are used for accessing a selection item:

each

Passes through the selection items.

ymaps.geoQuery(placemarks).searchIntersect(myMap).each(function(pm) {
    if (pm.options.get('preset') == 'islands#redIcon') {
        myMap.geoObjects.remove(pm);
    }
});

For more information about the method, see the Reference guide.

get

Returns a selection item by index.

var result = ymaps.geoQuery(placemarks).sort('lat'),
    // Southernmost object.
    southObject = result.get(0),
    // Northernmost object.
    northObject = result.get(result.getLength() - 1);

For more information about the method, see the Reference guide.

getIterator

Returns an iterator for selection items.

// Searching for elements that match the click coordinates.
myMap.events.add('click', function (event) {
    var iterator = ymaps.geoQuery(myMap.geoObjects)
            .searchContaining(event.getCoordinates())
            .getIterator(),
        obj;
    while ((obj = iterator.getNext()) != iterator.STOP_ITERATION) {
        // Performing the necessary actions on a geo object.
    }
});

For more information about the method, see the Reference guide.

indexOf

Returns the index of an item in the selection. If the item was not found, it returns -1.

// Sorting the selection by the "name" field.
var result = ymaps.geoQuery(polygons).sort('properties.name');
alert('New position of the first item: ' + result.indexOf(polygons[0]));

For more information about the method, see the Reference guide.

map

Calls the callback method for all the selection items and forms a new selection based on the results received.

// Adding only circle objects to the map.
var circlesResult = ymaps.geoQuery(objects).search('geometry.type="Circle"').addToMap(myMap),
// We'll also add placemarks that mark the circle centers.
    centers = circlesResult.map(function (object) {
        return new ymaps.Placemark(object.geometry.getCenter());
    }).addToMap(myMap);

For more information about the method, see the Reference guide.

3. Methods for processing asynchronous operations

Operations with selections can be performed asynchronously. Asynchronous mode usually occurs when data is exchanged with the server in one of the functions. Since getting the data takes some time, all the subsequent functions that are interacting with the selection must wait for the results to be ready.

Asynchronous interaction is implemented using promise objects. The following diagram shows how this type of interaction works.

All the functions in the chain are called synchronously. This means that the interpreter calls them sequentially, in a single thread. The process of filling the selection is asynchronous. If the data for forming the selection are not ready when a function is called, this function creates an empty GeoQueryResult object. The promise object that was passed by the previously called function is now passed to the empty object's constructor. Execution of the promise object means that the data is ready and the selection can be formed.

On the picture, the geocode function, which is waiting for a response from the server, creates the promise object, which is fulfilled when the server returns the data. The next geoQuery function subscribes to promise1 and starts filling the selection only when this promise object is fulfilled. Similarly, a new promise3 object is created, and the next add function will subscribe to it.

Alert

Functions that do not return the GeoQueryResult object (such as getLength()) are executed synchronously, meaning they do not wait for data to be ready before starting:

var result = ymaps.geoQuery(ymaps.geocode('Lena river')).getLength();
alert(result); // result = 0

In order for these functions to be executed asynchronously, their call of the then function must be passed as a callback:

var result = ymaps.geoQuery(ymaps.geocode('Lena river'));
result.then(function () {
     alert('Number of objects found: ' + result.getLength());
}, function () {
     alert('Error occurred.');
});

For more information about the method, see the Reference guide.

To debug an asynchronous operation, use the isReady() method, which returns a flag for the result readiness:

var result = ymaps.geoQuery(ymaps.geocode('Ivanovo'));
if (!result.isReady()) {
    result.then(function () {
        // Processing data.
    });
} else {
    // Processing data.
}

For more information about the method, see the Reference guide.

4. Methods for group processing of selection items

Various actions can be performed with the geo objects in a selection: add to the map, change properties and options, and so on. A list of methods for working with a group of geo objects is provided below:

addEvents

Assigns event handlers to all the items in the selection.

ymaps.geoQuery(map.geoObjects).search('geometry.type="Circle"').addEvents('click', function () {
    alert('You clicked a circle!');
});

For more information about the method, see the Reference guide.

addTo

Adds selection items to the specified collection of geo objects.

// Showing objects in the northern hemisphere on the map.
var result1 = ymaps.geoQuery(placemarks).search('lat > 0').addTo(myMap.geoObjects);

For more information about the method, see the Reference guide.

addToMap

Adds objects in the selection to the map.

// Showing objects in the northern hemisphere on the map.
var result1 = ymaps.geoQuery(placemarks).search('lat > 0').addToMap(myMap);

For more information about the method, see the Reference guide.

clusterize

Creates a clusterer and adds objects from the selection to it. If the selection data is not ready yet, it will be added to the clusterer immediately after processing, but the returned clusterer will be empty at first.

// Selecting only point objects and adding them to the clusterer.
var clusterer = ymaps.geoQuery(objects).search('geometry.type="Point"').clusterize();
myMap.geoObjects.add(clusterer);

For more information about the method, see the Reference guide.

removeEvents

Deletes the subscription to events from objects.

Alert

In order to unsubscribe correctly, the arguments passed must be exactly the same as the ones for subscribing via the addEvents method.

var callback = function () {
        alert('You clicked a circle!);
    };
ymaps.geoQuery(map.geoObjects).search('geometry.type="Circle"').addEvents('click', callback);
// ...
ymaps.geoQuery(map.geoObjects).search('geometry.type="Circle"').removeEvents('click', callback);

For more information about the method, see the Reference guide.

removeFrom

Removes selection objects from the specified collection of geo objects.

// Showing all objects on the map.
var result1 = ymaps.geoQuery(placemarks).addTo(myMap.geoObjects),
    // Then hiding objects in the northern hemisphere.
    result2 = result1.search('lat > 0').removeFrom(myMap.geoObjects);

For more information about the method, see the Reference guide.

removeFromMap

Removes selection objects from the map.

// Showing all objects on the map.
var result1 = ymaps.geoQuery(placemarks).addToMap(myMap),
// Then hiding objects in the northern hemisphere.
    result2 = result1.search('lat > 0').removeFromMap(myMap);

For more information about the method, see the Reference guide.

setOptions

Sets the value of options for all the objects in the selection.

var result = ymaps.geoQuery(placemarks);
// Making items visible that fall within a rectangular region.
result.searchIntersect(myBounds).setOptions('visible', true);.

For more information about the method, see the Reference guide.

setProperties

Sets the value of the properties field for all the objects in the selection.

var result = ymaps.geoQuery(objects);
// Marking elements that fall inside the area.
result.searchIntersect(myBounds1).setProperties('intersectBounds', true);
result.searchIntersect(myBounds2).setProperties('intersectBounds', true);
// ...
result.search('properties.intersectBounds = true').addToMap(myMap);

For more information about the method, see the Reference guide.

unsetOptions

Resets the value of options for all the objects in the selection.

result.unsetOptions('visible');

For more information about the method, see the Reference guide.

unsetProperties

Resets the value of the properties field for all the items in the selection.

var result = ymaps.geoQuery(objects);
// Marking items that fall inside the first area, but do not fall inside the second one.
result.searchIntersect(myBounds1).setProperties('intersectBounds', true);
result.searchIntersect(myBounds2).unsetProperties('intersectBounds', true);
// ...
result.search('properties.intersectBounds = true').addToMap(myMap);

For more information about the method, see the Reference guide.

5. Methods that perform search on a selection

intersect

Creates a new selection containing common items for two different selections.

var result = ymaps.geoQuery(placemarks),
    greenObjects = result.search('properties.color=green'),
    roundObjects = result.search('properties.shape=round'),
    greenRoundObjects = greenObjects.intersect(roundObjects);
alert('Number of round green objects:  ' + greenRoundObjects.getLength());

For more information about the method, see the Reference guide.

search

Searches for selection objects that meet the specified conditions.

var result = ymaps.geoQuery(myMap.geoObjects);

// Searching for objects with a specific type of geometry. The value is set in quotation marks, since it is a string.
result.search('geometry.type = "Point"')
     // Searching by coordinates.
    .search('geometry.coordinates.0 > 100')

For more information about the method, see the Reference guide.

searchContaining

Creates a new selection from objects containing the specified geo object.

Alert

For correct calculations, all geo objects must be added to the map. If geo objects do not need to be displayed, set their "visible" option to visible: false.

var result = ymaps.geoQuery(objects).addToMap(myMap),
    polygon = new ymaps.Polygon([[[35, 65], [35, 66], [34, 62], [34, 63], [35, 65]]]);
myMap.geoObjects.add(polygon);
var objectsContainingPolygon = result.searchContaining(polygon);

For more information about the method, see the Reference guide.

searchInside

Creates a new selection from objects that are completely inside the specified object.

Alert

For correct calculations, the geo objects must be added to the map. If geo objects do not need to be displayed, set their "visible" option to visible: false.

var result = ymaps.geoQuery(objects).addToMap(myMap),
    polygon = new ymaps.Polygon([[[35, 65], [35, 66], [34, 62], [34, 63], [35, 65]]]);
myMap.geoObjects.add(polygon);
var objectsInsidePolygon = result.searchInside(polygon);

For more information about the method, see the Reference guide.

searchIntersect

Creates a new selection from the selection objects that intersect the specified object.

Alert

For correct calculations, the geo objects must be added to the map. If geo objects do not need to be displayed, set their "visible" option to visible: false.

var result = ymaps.geoQuery(objects).addToMap(myMap),
    polygon = new ymaps.Polygon([[[35, 65], [35, 66], [34, 62], [34, 63], [35, 65]]]);
myMap.geoObjects.add(polygon);
var objectsIntersectPolygon = result.searchIntersect(polygon);

For more information about the method, see the Reference guide.

6. Methods for getting geometric parameters of a selection

applyBoundsToMap

Allows setting the map viewport so that all the objects in the selection are visible.

var result = ymaps.geoQuery(objects).applyBoundsToMap(myMap);
alert('Map viewport changed.');

For more information about the method, see the Reference guide.

getBounds

Returns the geographical coordinates of the area that includes all the result objects.

// Setting the map center and zoom so that the entire result is displayed.
myMap.setBounds(myResult.getBounds());
getCenter
// Moving the map center to the center of the area that covers the objects.
myMap.setCenter(ymaps.geoQuery(objects).getCenter());
getCentralObject

Returns the geo object that is closes to the center of the map viewport.

// Opening a balloon for the geo object that is closest to the center of the map viewport.
ymaps.geoQuery(objects).getCentralObject(myMap).balloon.open();
getClosestTo

Returns the selection object that is closest to the one specified. If an object that is already in the selection is given as input, it returns a different object from the selection that is closest to the one specified.

Alert

For correct calculations, the geo objects must be added to the map. If geo objects do not need to be displayed, set their "visible" option to visible: false.

var result = ymaps.geoQuery(objects).addToMap(myMap),
    polyline = new ymaps.Polyline([[35, 65], [35, 66], [34, 62], [34, 63]]);
myMap.geoObjects.add(polyline);
var closestObject = result.getClosestTo(polyline);

For more information about the method, see the Reference guide.

getExtreme

Returns the maximum and minimum coordinate values among the coordinates of objects in the selection.

alert('Northernmost coordinate: ', ymaps.geoQuery(myMap.geoObjects).getExtreme('top'));

For more information about the method, see the Reference guide.

getExtremeObject

Returns the object with the minimum or maximum coordinates among the coordinates of objects in the selection.

// Opening a balloon on the northernmost object.
var topObject = ymaps.geoQuery(myMap.geoObjects).getExtremeObject('top');
topObject.balloon.open();

For more information about the method, see the Reference guide.

getGlobalPixelBounds

Returns global pixel coordinates for the area that spans the selection objects (for the current map zoom value).

var result = ymaps.geoQuery(placemarks).search('properties.type="shop"').getGlobalPixelBounds(myMap);
if (Math.abs(result[0][0] - result[1][0]) > myMap.container.getSize()[0]) {
   alert('Objects are too wide to fit on the map!');
}

For more information about the method, see the Reference guide.

getGlobalPixelCenter

For the current zoom level, returns the global pixel coordinates of the center of the area that spans the selection objects.

// Calculating the tile number that contains the center of the area that spans the result.
var globalPixelCenter = ymaps.geoQuery(objects).getGlobalPixelCenter(myMap),
    tileNumber = [
        Math.floor(globalPixelCenter[0] / 256),
        Math.floor(globalPixelCenter[1] / 256)
    ];
alert('Number of the center tile: ' + tileNumber[0] + ' ' + tileNumber[1]);

For more information about the method, see the Reference guide.

Note

In the Sandbox, you can explore examples of working with a selection of geo objects.