tool_centroid.js

// Imports
import { geoArea, geoCentroid, geoIdentity, geoPath } from "d3-geo";
const d3 = Object.assign({}, { geoArea, geoCentroid, geoIdentity, geoPath });

/**
 * @function tool/centroid
 * @description The `tool.centroid` function calculate the centroid of all the geometries given in a GeoJSON FeatureCollection. It returns a GeoJSON FeatureCollection (points)
 * @see {@link https://observablehq.com/@neocartocnrs/handle-geometries}
 * @property {object} data - a GeoJSON FeatureCollection
 * @property {boolean} [options.largest = true] - place the centroid in the largest polygon.
 * @property {boolean} [options.latlong = true] - use `true` if input coordinates are in latitude ans longitude. Use `false` if the coordinates are already defined in the page plan
 * @example
 * let dots = geoviz.tool.centroid(world, { largest: true })
 */
export function centroid(data, { largest = true, latlong = true } = {}) {
  let path = d3.geoPath(d3.geoIdentity());

  let geojson = JSON.parse(JSON.stringify(data));
  const largestPolygon = function (d) {
    var best = {};
    var bestArea = 0;
    d.geometry.coordinates.forEach(function (coords) {
      var poly = { type: "Polygon", coordinates: coords };
      var area = latlong ? d3.geoArea(poly) : path.area(poly);
      if (area > bestArea) {
        bestArea = area;
        best = poly;
      }
    });
    return best;
  };

  let centers = geojson.features
    .filter((d) => d.geometry != null)
    .map((d) => {
      if (latlong) {
        d.geometry.coordinates = d3.geoCentroid(
          largest == true
            ? d.geometry.type == "Polygon"
              ? d
              : largestPolygon(d)
            : d
        );
      } else {
        d.geometry.coordinates = path.centroid(
          largest == true
            ? d.geometry.type == "Polygon"
              ? d
              : largestPolygon(d)
            : d
        );
      }

      d.geometry.type = "Point";
      return d;
    });

  geojson.features = centers;

  return geojson;
}