标记在缩放时“改变”位置

问题描述 投票:2回答:1

我有问题,我用他的图层和标记创建了一个地图。我已经完成了可拖动标记。

我正在使用react-map-gl和打字稿。

我的问题是,当我将标记从一个点更改为另一点时,用鼠标滚轮或放大标记“移动”。

我希望在更改缩放时继续在图层上移动,而在增加缩放时不退出图层。

我已经读过有关捕捉的信息,但我不知道该怎么做。

但是,不能用react map gl修复它吗?

这是我的代码:

export class SettingsMap extends React.PureComponent<
    Readonly<
        ISettingsMapProps &
            InteractiveMapProps &
            WrappedComponentProps & { children?: ReactNode }
    >,
    ISettingsMapState
> {
    mapRef: React.RefObject<InteractiveMap> = React.createRef<InteractiveMap>();
    timeout: ReturnType<typeof setTimeout> = setTimeout(() => "", 1000);

    constructor(
        props: Readonly<
            ISettingsMapProps &
                InteractiveMapProps &
                WrappedComponentProps & { children?: ReactNode }
        >
    ) {
        super(props);
        this.state = {
            viewport: {
                width: 100,
                height: 100,
                latitude: 39.46096,
                longitude: -0.40212,
                zoom: 12,
                pitch: 0,
            },
            mapGL: undefined,
            interactiveLayers: [TITLE_PIPE_LAYER, TITLE_POINT_LAYER],
            dragging: false,
            selectedFlowmeter: undefined,
        };
    }

    componentDidUpdate(prevProps: ISettingsMapProps) {
        if (prevProps.showModal !== this.props.showModal) {
            const { mapGL } = this.state;
            mapGL?.getMap().on("moveend", () => {
                this.updateViewportOnFinishFly(mapGL);
            });
        }
    }

    componentWillUnmount(): void {
        clearTimeout(this.timeout);
        const { mapGL } = this.state;
        if (mapGL) {
            mapGL?.getMap().off("moveend");
        }
    }

    updateViewportOnFinishFly = (mapGL: any) => {
        const { viewport } = this.state;
        mapGL.getMap().off("moveend");
        const center: Center = mapGL
            ?.getMap()
            .getCenter()
            .wrap();
        const zoom: number = mapGL?.getMap().getZoom();
        const updatedViewport = Object.assign({}, viewport, {
            latitude: center.lat,
            longitude: center.lng,
            zoom: zoom,
        });
        this.setState({ viewport: updatedViewport });
    };

    onClickedMap = (): void => {
        const { flowmeters, setFlowMeters } = this.props;
        const newArray: Array<IFlowMeter> = disableMenuAllFlowMeters(
            flowmeters
        );
        setFlowMeters(newArray);
    };

    handleLoad = (event: MapLoadEvent): void => {
        const loaded: boolean = event.target.loaded();
        const mapGL = this.mapRef.current;
        if (this.props.onSetLoaded) {
            this.props.onSetLoaded(loaded, mapGL);
        }
        if (mapGL !== null) {
            this.setState({ mapGL: mapGL });
        }
    };

    onClickedFlowmeter = (flowmeter: IFlowMeter): void => {
        const { flowmeters, setFlowMeters } = this.props;
        const newArray: Array<IFlowMeter> = updateFlowMeterMenu(
            flowmeter,
            flowmeters,
            true
        );
        setFlowMeters(newArray);
    };

    onDragStart = (flowmeter: IFlowMeter) => {
        this.setState({ dragging: true, selectedFlowmeter: flowmeter });
    };

    onDragEnd = (): void => {
        this.setState({ dragging: false });
    };

    handleMouseMove = (event: any) => {
        const { dragging, selectedFlowmeter, mapGL } = this.state;
        const { flowmeters, setFlowMeters } = this.props;
        if (!dragging && selectedFlowmeter) {
            const features = mapGL.getMap().queryRenderedFeatures(event.point);
            let existFeature = false;

            features.forEach((feature: any) => {
                if (
                    feature.layer.id.startsWith(TITLE_PIPE_LAYER) ||
                    feature.layer.id.startsWith(TITLE_POINT_LAYER)
                ) {
                    existFeature = true;
                }
            });

            if (existFeature) {
                const lngLat: number[] = event.lngLat;
                const newArray: Array<IFlowMeter> = flowMeterUpdatePosition(
                    lngLat,
                    selectedFlowmeter,
                    flowmeters
                );
                setFlowMeters(newArray);
            }
            this.setState({ selectedFlowmeter: undefined });
        } else if (!dragging && !selectedFlowmeter) {
            return;
        }
    };

    renderMarker = (flowmeter: IFlowMeter, index: number) => {
        const { flowmeters, setFlowMeters } = this.props;
        const { showUpdateModal } = this.props;

        return (
            <div
                className="flowmeter-marker-compose"
                key={index}
                onMouseUp={() => {
                    if (showUpdateModal) return;
                    this.onClickedFlowmeter(flowmeter);
                }}
            >
                <Marker
                    className={`flowmeter-marker ${
                        showUpdateModal ? "--disabled" : "--enabled"
                    }`}
                    offsetLeft={-30}
                    offsetTop={-30}
                    draggable={flowmeter.draggable}
                    latitude={flowmeter.latitude}
                    longitude={flowmeter.longitude}
                    onDragStart={() => {
                        if (showUpdateModal) return;
                        this.onDragStart(flowmeter);
                    }}
                    onDragEnd={() => {
                        if (showUpdateModal) return;
                        this.onDragEnd();
                    }}
                >
                    {flowmeter && flowmeter.menu && (
                        <FlowMeterMenu
                            flowmeter={flowmeter}
                            flowmeters={flowmeters}
                            updateFlowMeters={setFlowMeters}
                        />
                    )}
                    {!flowmeter.locked ? <FlowMiter /> : <FlowMiterLocked />}
                </Marker>
            </div>
        );
    };

    onWheel = (event: any) => {
        // SNAPPING
        // console.log("event: ", event);
        // update marker to line
        // npm install @turf/nearest-point-on-line
        const { flowmeters, geojson } = this.props;
        flowmeters.forEach( (flowmeter: IFlowMeter) => {
            const targetPoint = point([flowmeter.longitude, flowmeter.latitude]);
            const nearest = nearestPoint(targetPoint, geojson);
            console.log("nearest point: ", nearest);
        })
    };

    renderPipeLayer = (
        features:
            | string
            | GeoJSON.Feature<GeoJSON.Geometry, GeoJSON.GeoJsonProperties>
            | GeoJSON.FeatureCollection<
                  GeoJSON.Geometry,
                  GeoJSON.GeoJsonProperties
              >
            | undefined
    ) => {
        return <GeojsonPipieLayer data={features} />;
    };

    renderPointsLayer = (
        features:
            | string
            | GeoJSON.Feature<GeoJSON.Geometry, GeoJSON.GeoJsonProperties>
            | GeoJSON.FeatureCollection<
                  GeoJSON.Geometry,
                  GeoJSON.GeoJsonProperties
              >
            | undefined
    ) => {
        return <GeojsonPointLayer data={features} />;
    };

    render() {
        const { theme, children, showModal, flowmeters } = this.props;
        const { width, height, geojson } = this.props;
        const { viewport, interactiveLayers } = this.state;
        const mapStyle: string =
            theme === mapThemes.DARK ? darkTheme : lightTheme;
        return (
            <div className="dma-map__wrapper">
                <InteractiveMap
                    {...viewport}
                    ref={this.mapRef}
                    className="mapbox"
                    width={width}
                    height={height}
                    mapStyle={mapStyle}
                    attributionControl={false}
                    onLoad={this.handleLoad}
                    onClick={this.onClickedMap}
                    onWheel={this.onWheel}
                    onMouseMove={this.handleMouseMove}
                    onViewportChange={(viewport: ViewportProps) => {
                        viewport.width = 100;
                        viewport.height = 100;
                        this.setState({ viewport });
                    }}
                    interactiveLayerIds={geojson ? interactiveLayers : []}
                >
                    {!showModal && children}
                    {!showModal && geojson && this.renderPipeLayer(geojson)}
                    {!showModal && geojson && this.renderPointsLayer(geojson)}

                    {!showModal &&
                        flowmeters &&
                        flowmeters.length > 0 &&
                        flowmeters.map(this.renderMarker)}
                </InteractiveMap>
            </div>
        );
    }
}

export default injectIntl(SettingsMap);
mapbox mapbox-gl-js mapbox-marker
1个回答
0
投票

我有一种解决方案,可以在更改缩放比例时正确显示标记:D

我正在使用一种称为捕捉的技术,或者我不知道我是否正在使用该技术。

希望您喜欢它或为您服务:D

我已经添加了这种方法,并且已经使用草皮库来解决它。

onWheel = () => {
    this.snapping();
};

snapping = () => {
    this.isSnapping = true;
    const { flowmeters, setFlowMeters } = this.props;
    flowmeters.forEach((flowmeter: IFlowMeter, index: number) => {
        if (!flowmeter) return;
        if (flowmeter && !flowmeter.feature) return;
        const coordinates = flowmeter.feature.geometry.coordinates;
        const line = lineString(coordinates);
        const pt = point([flowmeter.longitude, flowmeter.latitude]);
        const nearest = nearestPointOnLine(line, pt);
        const lngLat: Array<number> = [
            nearest.geometry.coordinates[0],
            nearest.geometry.coordinates[1],
        ];
        setFlowMeters(
            flowMeterUpdatePosition(lngLat, flowmeter, flowmeters)
        );
    });
    this.isSnapping = false;
};

并且在componentDidUpdate中,我已经添加了这个:

 const { viewport } = this.state;
    if ( prevState.viewport.zoom !== viewport.zoom && prevState.viewport.zoom < viewport.zoom && !this.isSnapping ) {
        this.snapping();
 }
© www.soinside.com 2019 - 2024. All rights reserved.