diff --git a/README.md b/README.md index 637ea9d..bf12baf 100644 --- a/README.md +++ b/README.md @@ -266,11 +266,13 @@ const featureCollections = calculateRoutesResponseToFeatureCollections(response) ### calculateIsolinesResponseToFeatureCollection -This converts a CalculateIsolineResponse from the standalone Routes SDK to a GeoJSON FeatureCollection which contains one Feature for each isoline -in the response. Isolines can contain both polygons for isoline regions and lines for connectors between regions -(such as ferry travel), so each Feature is a GeometryCollection that can contain a mix of Polygons and LineStrings. -The `flattenProperties` option will flatten the nested response data into a flat properties list. -This option is enabled by default, as it makes the data easier to use from within MapLibre expressions. +This converts a CalculateIsolineResponse from the standalone Routes SDK to a GeoJSON +FeatureCollection which contains one Feature for each isoline in the response. Isolines can contain +both polygons for isoline regions and lines for connectors between regions (such as ferry travel), +so each Feature contains either a GeometryCollection with a mix of Polygons and LineStrings or a +single Polygon. The `flattenProperties` option will flatten the nested response data into a flat +properties list. This option is enabled by default, as it makes the data easier to use from within +MapLibre expressions. Any feature that is missing its geometry in the response or has invalid geometry will throw an Error(). diff --git a/src/to-geojson/georoutes-converter.ts b/src/to-geojson/georoutes-converter.ts index 11e3b30..039e2e3 100644 --- a/src/to-geojson/georoutes-converter.ts +++ b/src/to-geojson/georoutes-converter.ts @@ -343,7 +343,8 @@ const defaultCalculateIsolinesResponseOptions = defaultBaseGeoRoutesOptions; /** * This converts a CalculateIsolineResponse to a GeoJSON FeatureCollection which contains one Feature for each isoline * in the response. Isolines can contain both polygons for isoline regions and lines for connectors between regions - * (such as ferry travel), so each Feature is a GeometryCollection that can contain a mix of Polygons and LineStrings. + * (such as ferry travel), so each Feature contains either a GeometryCollection with a mix of Polygons and LineStrings + * or a single Polygon. * * Any feature that is missing its geometry in the response or has invalid geometry will throw an Error. * @@ -405,11 +406,11 @@ const defaultCalculateIsolinesResponseOptions = defaultBaseGeoRoutesOptions; export function calculateIsolinesResponseToFeatureCollection( isolinesResponse: CalculateIsolinesResponse, options?: CalculateIsolinesResponseOptions, -): FeatureCollection { +): FeatureCollection | Polygon> { // Set any options that weren't passed in to the default values. options = { ...defaultCalculateIsolinesResponseOptions, ...options }; - const isolines: FeatureCollection = { + const isolines: FeatureCollection | Polygon> = { type: "FeatureCollection", features: [], }; @@ -420,7 +421,7 @@ export function calculateIsolinesResponseToFeatureCollection( // eslint-disable-next-line @typescript-eslint/no-unused-vars const { Geometries, Connections, ...properties } = isoline; - const feature: Feature = { + const feature: Feature> = { type: "Feature", id: isolines.features.length, properties: options.flattenProperties ? flattenProperties(properties, "") : properties, @@ -448,7 +449,20 @@ export function calculateIsolinesResponseToFeatureCollection( // As long as this feature has at least one polygon or line, add it to the result set. if (feature.geometry.geometries.length > 0) { - isolines.features.push(feature); + if (feature.geometry.geometries.length === 1 && feature.geometry.geometries[0].type === "Polygon") { + // GeometryCollections containing single geometries trigger GeoJSONLint warnings: + // GeometryCollection with a single geometry should be avoided in favor of single part + // or a single object of multi-part type + // in practice, the geometry type for single-geometry isolines is Polygon; LineStrings are + // supplemental and appear when multiple polygons are present, representing the connection + // between those areas + isolines.features.push({ + ...feature, + geometry: feature.geometry.geometries[0], + }); + } else { + isolines.features.push(feature); + } } }