【问题标题】:Markers "change" position on zoom标记在缩放时“改变”位置
【发布时间】:2020-06-11 07:20:02
【问题描述】:

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

我正在使用 react-map-gl 和 typescript。

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

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

我读过关于捕捉的文章,但我不知道怎么做。

但是,不能用 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】:

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

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

    希望你喜欢或为你服务:D

    我已经添加了这个方法,并使用了 turf 库来解决它。

    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();
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-09
      • 2014-10-16
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多