From b1d988ab0efd7935e06a481e7ffb7ef2dc209379 Mon Sep 17 00:00:00 2001 From: suyubin <84109842+websybin@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:48:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20sam-control=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A2=84=E8=A7=88=E5=8A=9F=E8=83=BD=20(#25)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix/sam-control组件新增预览功能 * fix/sam-control组件防抖时间调整,删除报错 * fix: click 修改为 onClick * fix: 延迟时间改为2S --------- Co-authored-by: syb01094648 --- .../map-control-group/sam-control/index.tsx | 141 ++++++++++++------ 1 file changed, 95 insertions(+), 46 deletions(-) diff --git a/src/components/map-control-group/sam-control/index.tsx b/src/components/map-control-group/sam-control/index.tsx index 110d054..a13361c 100644 --- a/src/components/map-control-group/sam-control/index.tsx +++ b/src/components/map-control-group/sam-control/index.tsx @@ -1,9 +1,21 @@ -import type { LineLayerProps } from '@antv/larkmap'; -import { CustomControl, LineLayer, Marker, useLayerList } from '@antv/larkmap'; +import type { LineLayerProps, PolygonLayerProps } from '@antv/larkmap'; +import { + CustomControl, + LineLayer, + Marker, + PolygonLayer, + useLayerList, +} from '@antv/larkmap'; import type { Layer } from '@antv/larkmap/es/types'; import { MODEL_URL, SAMGeo } from '@antv/sam'; import type { Feature, MultiPolygon, Polygon } from '@turf/turf'; -import { booleanPointInPolygon, point, polygon } from '@turf/turf'; +import { + booleanPointInPolygon, + featureCollection, + point, + polygon, +} from '@turf/turf'; +import { useDebounceFn } from 'ahooks'; import { Spin, Tooltip, message } from 'antd'; import { isEmpty } from 'lodash-es'; import React, { useCallback, useEffect, useState } from 'react'; @@ -34,6 +46,24 @@ const options: Omit = { }, }; +const layerOptions: Omit = { + shape: 'fill', + color: '#ff0000', + id: 'hoverLayer', + state: { + active: false, + }, + style: { + opacity: 0.5, + }, + zIndex: 100, +}; + +const defaultPolygonSource = { + data: { type: 'FeatureCollection', features: [] }, + parser: { type: 'geojson' }, +}; + export const SamControl = () => { const styles = useStyle(); const style = useStyles(); @@ -54,51 +84,18 @@ export const SamControl = () => { const [source, setSource] = useState({ data: { type: 'FeatureCollection', features: [] }, }); + const [polygonSource, setPolygonSource] = useState(defaultPolygonSource); const { t } = useTranslation(); const onMapClick = useCallback( (event: any) => { - const coords = [event.lngLat.lng, event.lngLat.lat] as [number, number]; - if (bound) { - if (booleanPointInPolygon(point(coords), bound)) { - if (samModel) { - const px = samModel.lngLat2ImagePixel(coords)!; - const newPoint = [ - { - x: px[0], - y: px[1], - clickType: 1, - }, - ]; - const threshold = 1; - - samModel.predict(newPoint).then(async (res) => { - const fc = await samModel.exportGeoPolygon(res, threshold); - const image = samModel.exportImageClip(res)!; - const newData = { - feature: fc.features as any, - imageUrl: image.src, - }; - if ( - booleanPointInPolygon(point(coords), newData?.feature[0]) && - newData?.feature[0].geometry.coordinates[0].length > 4 - ) { - const newFeature = revertCoord(newData.feature); - resetFeatures([...features, ...newFeature] as IFeatures); - } else { - message.warning(t('map_control_group.sam.tuXingJieXiCuoWu')); - } - }); - } - } else { - message.error(t('map_control_group.sam.qingZaiQuYuNei')); - } - } + const newFeature = revertCoord([event.feature]); + resetFeatures([...features, ...newFeature] as IFeatures); + setPolygonSource(defaultPolygonSource); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [bound, samModel, features, t], + [features], ); - // 生成 embedding 并初始化载入模型 const generateEmbedding = async () => { setLoading(true); @@ -175,7 +172,6 @@ export const SamControl = () => { } } catch (error) { message.error(t('map_control_group.sam.jiSuanShiBai')); - scene?.off('click', onMapClick); } finally { setLoading(false); } @@ -203,21 +199,69 @@ export const SamControl = () => { } }, [allLayerList]); + const { run: onMapHover } = useDebounceFn( + (e) => { + const coords = [e.lngLat.lng, e.lngLat.lat] as [number, number]; + if (bound) { + if (booleanPointInPolygon(point(coords), bound)) { + if (samModel) { + const px = samModel.lngLat2ImagePixel(coords)!; + const newPoint = [ + { + x: px[0], + y: px[1], + clickType: 1, + }, + ]; + const threshold = 1; + + samModel.predict(newPoint).then(async (res) => { + const fc = await samModel.exportGeoPolygon(res, threshold); + const image = samModel.exportImageClip(res)!; + const newData = { + feature: fc.features as any, + imageUrl: image.src, + }; + if ( + booleanPointInPolygon(point(coords), newData?.feature[0]) && + newData?.feature[0].geometry.coordinates[0].length > 4 + ) { + const newFeatures = revertCoord(newData.feature); + setPolygonSource((prevState: any) => ({ + ...prevState, + data: featureCollection(newFeatures), + })); + // resetFeatures([...features, ...newFeature] as IFeatures); + } + }); + } + } else { + setPolygonSource(defaultPolygonSource); + } + } + }, + { + wait: 2000, + maxWait: 2000, + }, + ); + useEffect(() => { if (polygonLayer) { if (samOpen) { - polygonLayer.on('unclick', onMapClick); + polygonLayer.on('unmousemove', onMapHover); } else { setSource({ data: { type: 'FeatureCollection', features: [] } }); setMarker(undefined); - polygonLayer.off('unclick', onMapClick); + setPolygonSource(defaultPolygonSource); + polygonLayer.off('unmousemove', onMapHover); } } return () => { - polygonLayer?.off('unclick', onMapClick); + polygonLayer?.off('unmousemove', onMapHover); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [samOpen, scene, onMapClick]); + }, [samOpen, scene, onMapHover, onMapClick]); useEffect(() => { if (samOpen && samModel) { @@ -268,6 +312,11 @@ export const SamControl = () => { )} + ); };