У меня проблема, я создал карту со своими слоями и маркерами. Я сделал перетаскиваемые маркеры.
Я использую response-map-gl и машинописный текст.
Моя проблема в том, что когда я меняю маркер с одной точки на другую, когда я прокручиваю мышь или увеличиваю масштаб, маркер «перемещается».
Я бы хотел, чтобы при изменении масштабирования продолжалось по слою и не выходило из слоя при увеличении масштабирования.
Я читал о привязке, но не знаю, как это сделать.
Но невозможно исправить это с помощью карты реакции 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);