Source: src/overpass/overpass.service.js


/**
 * @class
 * Create osmOverpassAPI service instance
 */
class OverpassAPI{
    /**
     * @param {Object} $http angular $http service
     * @param {Object} $q  angular $q service
     * @param {Object} options
     */
    constructor($http, $q, options) {
        this.url = options.url;
        this.$http = $http;
        this.$q = $q;
    }
    /**
     * @param {Object/String} query
     * http://wiki.openstreetmap.org/wiki/FR:Overpass_API
     * @return {Promise} $http.get
    */
    overpass(query) {
        var url = this.url;
        var deferred = this.$q.defer();
        var headers = {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        };
        this.$http.post(
            url,
            'data=' + encodeURIComponent(query),
            {headers: headers}
        ).then(function (data) {
            deferred.resolve(data.data);
        }, function (data) {
            deferred.reject(data);
        });
        return deferred.promise;
    }
    /**
     * http://wiki.openstreetmap.org/wiki/FR:Overpass_API/Overpass_QL#By_area_.28area.29
        By convention the area id can be calculated from an existing OSM way by adding 2400000000 to its OSM id, or in case of a relation by adding 3600000000 respectively. Note that area creation is subject to some extraction rules, i.e. not all ways/relations have an area counterpart (notably those that are tagged with area=no, and most multipolygons and that don't have a defined name=* will not be part of areas).
     * @param {String} type 'r'/'relation' or 'w'/'way'
     * @param {String/Number} osmId the id of the element
     * @return {Number} the area id
    */
    getAreaId(type, osmId) {
        var id;
        if (typeof osmId === 'string') {
            id = parseInt(osmId, 10);
        } else {
            id = osmId;
        }
        if (type === 'r' || type === 'relation') {
            return 3600000000 + id;
        } else if (type === 'w' || type === 'way') {
            return 2400000000 + id;
        }
    }
    overpassToGeoJSON(query, filter) {
        var deferred = this.$q.defer();
        var features = [];
        var relations = [];
        var result = {
            type: 'FeatureCollection',
            features: features,
            relations: relations
        };
        if (filter === undefined) {
            filter = function () {};
        }
        this.overpass(query).then(function (data) {
            //TODO check if data is XML or JSON, here it's JSON
            var node, feature, coordinates;
            var cache = {loaded:false};
            function getNodeById (id) {
                if (!cache.loaded) {
                    var tmp;
                    for (var i = 0; i < data.elements.length; i++) {
                        tmp = data.elements[i];
                        cache[tmp.id] = tmp;
                    }
                }
                return cache[id];
            }
            for (var i = 0; i < data.elements.length; i++) {
                node = data.elements[i];
                if (node.type === 'node') {
                    feature = {
                        type: 'Feature',
                        properties:node.tags,
                        id: node.id,
                        geometry: {
                            type:'Point',
                            coordinates: [node.lon, node.lat]
                        }
                    };
                    if (!filter(feature)) {
                        features.push(feature);
                    }
                } else if (node.type === 'way') {
                    coordinates = [];
                    feature = {
                        type: 'Feature',
                        properties:node.tags,
                        id: node.id,
                        geometry: {
                            type:'LineString',
                            coordinates: coordinates
                        }
                    };
                    for (var j = 0; j < node.nodes.length; j++) {
                        coordinates.push([
                            getNodeById(node.nodes[j]).lon,
                            getNodeById(node.nodes[j]).lat
                        ]);
                    }
                    if (!filter(feature)) {
                        features.push(feature);
                    }
                } else if (node.type === 'relation') {
                    result.relations.push({
                        ref: node.id,
                        tags: node.tags,
                        type: 'relation',
                        members: node.members
                    });
                }
            }
            deferred.resolve(result);
        }, function (error) {
            deferred.reject(error);
        });
        return deferred.promise;
    }
}

export default OverpassAPI;