diff --git a/src/components/AMapGeoJSON/stories/AMapGeoJSON.stories.tsx b/src/components/AMapGeoJSON/stories/AMapGeoJSON.stories.tsx index dcdc84f..30f1709 100644 --- a/src/components/AMapGeoJSON/stories/AMapGeoJSON.stories.tsx +++ b/src/components/AMapGeoJSON/stories/AMapGeoJSON.stories.tsx @@ -1,13 +1,82 @@ import type { FC } from 'react'; import React, { useEffect, useState } from 'react'; import { Meta, Story } from '@storybook/react'; -// import { actions } from '@storybook/addon-actions'; -import { AMapGeoJSON, AMapGeoJSONGetOverlayCallback, AMapGeoJSONProps } from 'index'; +import type { AMapGeoJSONGetOverlayCallback, AMapGeoJSONProps } from 'index'; +import { AMapGeoJSON, coordsOfGeoJSON2AMapPolygonPath } from 'index'; import { withAMapContainer } from '../../AMapMap/stories/AMapMap.stories'; import useAMap from '../../../hooks/useAMap'; +const point: GeoJSON.Point = { + type: 'Point', + coordinates: [116.39, 39.9], +}; + +const line: GeoJSON.LineString = { + type: 'LineString', + coordinates: [ + [116.388904, 39.903423], + [116.392122, 39.901176], + ], +}; + +const commonPolygon: GeoJSON.Polygon = { + type: 'Polygon', + coordinates: [ + [ + [116.386069, 39.898857], + [116.386023, 39.897477], + [116.387719, 39.897539], + [116.386069, 39.898857], + ], + ], +}; +const polygonWithHole: GeoJSON.Polygon = { + type: 'Polygon', + coordinates: [ + [ + [116.384595, 39.901321], + [116.383526, 39.899865], + [116.386284, 39.900917], + [116.384595, 39.901321], + ], + [ + [116.384594, 39.901], + [116.384, 39.9003], + [116.3861, 39.900917], + [116.384594, 39.901], + ], + ], +}; +const multiPolygon: GeoJSON.MultiPolygon = { + type: 'MultiPolygon', + coordinates: [ + [ + [ + [116.388624, 39.900055], + [116.390452, 39.898583], + [116.391294, 39.900003], + [116.388624, 39.900055], + ], + [ + [116.389113, 39.899924], + [116.390251, 39.898962], + [116.391055, 39.899899], + [116.389113, 39.899924], + ], + ], + [ + [ + [116.387884, 39.899645], + [116.38796, 39.898347], + [116.390175, 39.898394], + [116.387884, 39.899645], + ], + ], + ], +}; + const mockData: GeoJSON.FeatureCollection = { type: 'FeatureCollection', features: [ @@ -17,32 +86,11 @@ const mockData: GeoJSON.FeatureCollection = { geometry: { type: 'GeometryCollection', geometries: [ - { - type: 'Point', - coordinates: [116.39, 39.9], - }, - { - type: 'Polygon', - coordinates: [ - [ - [116.384595, 39.901321], - [116.383526, 39.899865], - [116.386284, 39.900917], - ], - [ - [116.384594, 39.901], - [116.384, 39.9003], - [116.3861, 39.900917], - ], - ], - }, - { - type: 'LineString', - coordinates: [ - [116.388904, 39.903423], - [116.392122, 39.901176], - ], - }, + point, + line, + commonPolygon, + polygonWithHole, + multiPolygon, ], }, }, @@ -167,7 +215,8 @@ const getPolyline: AMapGeoJSONGetOverlayCallback = (_, lnglat, map, AMap) => { const getPolygon: AMapGeoJSONGetOverlayCallback = (_, lnglat, map, AMap) => { const polygon = new AMap!.Polygon(); - polygon.setPath(lnglat as AMap.PolygonOptions['path']); + const path = coordsOfGeoJSON2AMapPolygonPath(lnglat!); + polygon.setPath(path as AMap.PolygonOptions['path']); polygon.setOptions({ strokeColor: 'yellow', }); diff --git a/src/helpers/amapPolygonPath2GeoJSONCoords.ts b/src/helpers/amapPolygonPath2GeoJSONCoords.ts new file mode 100644 index 0000000..efc069c --- /dev/null +++ b/src/helpers/amapPolygonPath2GeoJSONCoords.ts @@ -0,0 +1,21 @@ +const isLatLng = (p: any): p is AMap.LngLat => !!('lat' in p && 'lng' in p); +const isLatLngArr = (p: any): p is AMap.LngLat[] => p.every(isLatLng); + +/** + * 补充最后一个 Position。 + * 支持转换至 GeoJSON.Polygon 和 GeoJSON.MultiplePolygon 的 coords + */ +const amapPolygonPath2GeoJSONCoords = ( + path: ReturnType, +): typeof path => { + if (isLatLngArr(path)) { + const coords = path.map((item) => item.toArray()); + coords.push(coords[0].slice(0) as [number, number]); + return coords; + } + + // trick way + return (path as AMap.LngLat[][][])!.map(amapPolygonPath2GeoJSONCoords); +}; + +export default amapPolygonPath2GeoJSONCoords; diff --git a/src/helpers/coordsOfGeoJSON2AMapPolygonPath.ts b/src/helpers/coordsOfGeoJSON2AMapPolygonPath.ts new file mode 100644 index 0000000..29340e3 --- /dev/null +++ b/src/helpers/coordsOfGeoJSON2AMapPolygonPath.ts @@ -0,0 +1,23 @@ +import { isLineCoords } from './geoJSONHelper'; + +const coordsOfGeoJSONRingLine2AMapPolygonPath = (coords: GeoJSON.Position[]): typeof coords => { + const len = coords.length; + return coords.slice(0, len - 1); +}; + +/** + * 去掉最后一个 Position 点。 + * 支持 GeoJSON.Polygon 和 GeoJSON.MultiplePolygon 转换 + */ +const coordsOfGeoJSON2AMapPolygonPath = ( + coords: GeoJSON.Position[] | GeoJSON.Polygon['coordinates'] | GeoJSON.MultiPolygon['coordinates'], +): typeof coords => { + if (isLineCoords(coords)) { + return coordsOfGeoJSONRingLine2AMapPolygonPath(coords); + } + + // trick way + return (coords as GeoJSON.MultiPolygon['coordinates']).map(coordsOfGeoJSON2AMapPolygonPath) as typeof coords; +}; + +export default coordsOfGeoJSON2AMapPolygonPath; diff --git a/src/helpers/geoJSONHelper.ts b/src/helpers/geoJSONHelper.ts new file mode 100644 index 0000000..3ba54be --- /dev/null +++ b/src/helpers/geoJSONHelper.ts @@ -0,0 +1,10 @@ +export const isPosition = (pos: any): pos is GeoJSON.Position => ( + Array.isArray(pos) + && pos.length === 2 + && typeof pos[0] === 'number' + && typeof pos[1] === 'number' +); + +export const isLineCoords = ( + line: any, +): line is GeoJSON.Position[] => Array.isArray(line) && line.every(isPosition); diff --git a/src/index.ts b/src/index.ts index c0c0d49..23d81d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,3 +19,7 @@ export { } from './components/AMapGeoJSON'; export { default as AMapMouseTool, AMapMouseToolProps } from './components/AMapMouseTool'; + +// helpers +export { default as coordsOfGeoJSON2AMapPolygonPath } from './helpers/coordsOfGeoJSON2AMapPolygonPath'; +export { default as amapPolygonPath2GeoJSONCoords } from './helpers/amapPolygonPath2GeoJSONCoords';