| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | import { featureEach } from "@turf/meta";import { featureCollection } from "@turf/helpers";/** * Get Cluster * * @name getCluster * @param {FeatureCollection} geojson GeoJSON Features * @param {*} filter Filter used on GeoJSON properties to get Cluster * @returns {FeatureCollection} Single Cluster filtered by GeoJSON Properties * @example * var geojson = turf.featureCollection([ *     turf.point([0, 0], {'marker-symbol': 'circle'}), *     turf.point([2, 4], {'marker-symbol': 'star'}), *     turf.point([3, 6], {'marker-symbol': 'star'}), *     turf.point([5, 1], {'marker-symbol': 'square'}), *     turf.point([4, 2], {'marker-symbol': 'circle'}) * ]); * * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties) * var clustered = turf.clustersKmeans(geojson); * * // Retrieve first cluster (0) * var cluster = turf.getCluster(clustered, {cluster: 0}); * //= cluster * * // Retrieve cluster based on custom properties * turf.getCluster(clustered, {'marker-symbol': 'circle'}).length; * //= 2 * turf.getCluster(clustered, {'marker-symbol': 'square'}).length; * //= 1 */export function getCluster(geojson, filter) {    // Validation    if (!geojson)        throw new Error("geojson is required");    if (geojson.type !== "FeatureCollection")        throw new Error("geojson must be a FeatureCollection");    if (filter === undefined || filter === null)        throw new Error("filter is required");    // Filter Features    var features = [];    featureEach(geojson, function (feature) {        if (applyFilter(feature.properties, filter))            features.push(feature);    });    return featureCollection(features);}/** * Callback for clusterEach * * @callback clusterEachCallback * @param {FeatureCollection} [cluster] The current cluster being processed. * @param {*} [clusterValue] Value used to create cluster being processed. * @param {number} [currentIndex] The index of the current element being processed in the array.Starts at index 0 * @returns {void} *//** * clusterEach * * @name clusterEach * @param {FeatureCollection} geojson GeoJSON Features * @param {string|number} property GeoJSON property key/value used to create clusters * @param {Function} callback a method that takes (cluster, clusterValue, currentIndex) * @returns {void} * @example * var geojson = turf.featureCollection([ *     turf.point([0, 0]), *     turf.point([2, 4]), *     turf.point([3, 6]), *     turf.point([5, 1]), *     turf.point([4, 2]) * ]); * * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties) * var clustered = turf.clustersKmeans(geojson); * * // Iterate over each cluster * turf.clusterEach(clustered, 'cluster', function (cluster, clusterValue, currentIndex) { *     //= cluster *     //= clusterValue *     //= currentIndex * }) * * // Calculate the total number of clusters * var total = 0 * turf.clusterEach(clustered, 'cluster', function () { *     total++; * }); * * // Create an Array of all the values retrieved from the 'cluster' property * var values = [] * turf.clusterEach(clustered, 'cluster', function (cluster, clusterValue) { *     values.push(clusterValue); * }); */export function clusterEach(geojson, property, callback) {    // Validation    if (!geojson)        throw new Error("geojson is required");    if (geojson.type !== "FeatureCollection")        throw new Error("geojson must be a FeatureCollection");    if (property === undefined || property === null)        throw new Error("property is required");    // Create clusters based on property values    var bins = createBins(geojson, property);    var values = Object.keys(bins);    for (var index = 0; index < values.length; index++) {        var value = values[index];        var bin = bins[value];        var features = [];        for (var i = 0; i < bin.length; i++) {            features.push(geojson.features[bin[i]]);        }        callback(featureCollection(features), value, index);    }}/** * Callback for clusterReduce * * The first time the callback function is called, the values provided as arguments depend * on whether the reduce method has an initialValue argument. * * If an initialValue is provided to the reduce method: *  - The previousValue argument is initialValue. *  - The currentValue argument is the value of the first element present in the array. * * If an initialValue is not provided: *  - The previousValue argument is the value of the first element present in the array. *  - The currentValue argument is the value of the second element present in the array. * * @callback clusterReduceCallback * @param {*} [previousValue] The accumulated value previously returned in the last invocation * of the callback, or initialValue, if supplied. * @param {FeatureCollection} [cluster] The current cluster being processed. * @param {*} [clusterValue] Value used to create cluster being processed. * @param {number} [currentIndex] The index of the current element being processed in the * array. Starts at index 0, if an initialValue is provided, and at index 1 otherwise. *//** * Reduce clusters in GeoJSON Features, similar to Array.reduce() * * @name clusterReduce * @param {FeatureCollection} geojson GeoJSON Features * @param {string|number} property GeoJSON property key/value used to create clusters * @param {Function} callback a method that takes (previousValue, cluster, clusterValue, currentIndex) * @param {*} [initialValue] Value to use as the first argument to the first call of the callback. * @returns {*} The value that results from the reduction. * @example * var geojson = turf.featureCollection([ *     turf.point([0, 0]), *     turf.point([2, 4]), *     turf.point([3, 6]), *     turf.point([5, 1]), *     turf.point([4, 2]) * ]); * * // Create a cluster using K-Means (adds `cluster` to GeoJSON properties) * var clustered = turf.clustersKmeans(geojson); * * // Iterate over each cluster and perform a calculation * var initialValue = 0 * turf.clusterReduce(clustered, 'cluster', function (previousValue, cluster, clusterValue, currentIndex) { *     //=previousValue *     //=cluster *     //=clusterValue *     //=currentIndex *     return previousValue++; * }, initialValue); * * // Calculate the total number of clusters * var total = turf.clusterReduce(clustered, 'cluster', function (previousValue) { *     return previousValue++; * }, 0); * * // Create an Array of all the values retrieved from the 'cluster' property * var values = turf.clusterReduce(clustered, 'cluster', function (previousValue, cluster, clusterValue) { *     return previousValue.concat(clusterValue); * }, []); */export function clusterReduce(geojson, property, callback, initialValue) {    var previousValue = initialValue;    clusterEach(geojson, property, function (cluster, clusterValue, currentIndex) {        if (currentIndex === 0 && initialValue === undefined)            previousValue = cluster;        else            previousValue = callback(previousValue, cluster, clusterValue, currentIndex);    });    return previousValue;}/** * Create Bins * * @private * @param {FeatureCollection} geojson GeoJSON Features * @param {string|number} property Property values are used to create bins * @returns {Object} bins with Feature IDs * @example * var geojson = turf.featureCollection([ *     turf.point([0, 0], {cluster: 0, foo: 'null'}), *     turf.point([2, 4], {cluster: 1, foo: 'bar'}), *     turf.point([5, 1], {0: 'foo'}), *     turf.point([3, 6], {cluster: 1}), * ]); * createBins(geojson, 'cluster'); * //= { '0': [ 0 ], '1': [ 1, 3 ] } */export function createBins(geojson, property) {    var bins = {};    featureEach(geojson, function (feature, i) {        var properties = feature.properties || {};        if (Object.prototype.hasOwnProperty.call(properties, String(property))) {            var value = properties[property];            if (Object.prototype.hasOwnProperty.call(bins, value))                bins[value].push(i);            else                bins[value] = [i];        }    });    return bins;}/** * Apply Filter * * @private * @param {*} properties Properties * @param {*} filter Filter * @returns {boolean} applied Filter to properties */export function applyFilter(properties, filter) {    if (properties === undefined)        return false;    var filterType = typeof filter;    // String & Number    if (filterType === "number" || filterType === "string")        return Object.prototype.hasOwnProperty.call(properties, filter);    // Array    else if (Array.isArray(filter)) {        for (var i = 0; i < filter.length; i++) {            if (!applyFilter(properties, filter[i]))                return false;        }        return true;        // Object    }    else {        return propertiesContainsFilter(properties, filter);    }}/** * Properties contains filter (does not apply deepEqual operations) * * @private * @param {*} properties Properties * @param {Object} filter Filter * @returns {boolean} does filter equal Properties * @example * propertiesContainsFilter({foo: 'bar', cluster: 0}, {cluster: 0}) * //= true * propertiesContainsFilter({foo: 'bar', cluster: 0}, {cluster: 1}) * //= false */export function propertiesContainsFilter(properties, filter) {    var keys = Object.keys(filter);    for (var i = 0; i < keys.length; i++) {        var key = keys[i];        if (properties[key] !== filter[key])            return false;    }    return true;}/** * Filter Properties * * @private * @param {*} properties Properties * @param {Array<string>} keys Used to filter Properties * @returns {*} filtered Properties * @example * filterProperties({foo: 'bar', cluster: 0}, ['cluster']) * //= {cluster: 0} */export function filterProperties(properties, keys) {    if (!keys)        return {};    if (!keys.length)        return {};    var newProperties = {};    for (var i = 0; i < keys.length; i++) {        var key = keys[i];        if (Object.prototype.hasOwnProperty.call(properties, key))            newProperties[key] = properties[key];    }    return newProperties;}
 |