处理世界副本中的Mapbox GeoJson行?

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

我有一个mapbox地图,我正在渲染点并在点之间绘制线来创建路线。设置工作正常,动画按预期工作。

然而,当我有一条线穿过一个新的世界副本时,曲线被绘制,但另一条线也被绘制在整个地图上。

map

有没有人知道处理线条绘制的方法,以便它们不会交叉到新的世界渲染?或者对于处理线条绘制的最佳方法有什么想法?

作为参考,我使用的是这里的mapbox示例:

https://docs.mapbox.com/mapbox-gl-js/example/animate-point-along-route/

showRoute = route => {
		const steps = 500;

		const getRouteChunks = (array, size) => {
			const chunkedArr = [];

			array.forEach((arr, i) => {
				chunkedArr.push(array.slice(i, i + size));
			});

			return chunkedArr;
		};

		const routeChunks = getRouteChunks(route.destinations, 2);

		this.setState(prevState => {
			// Let's remove any existing route lines
			const mapLayers = prevState.map.style._layers;

			const midLayersOnlyToRemove = this.getMapboxLayersToRemove(mapLayers, '-midpoint');
			midLayersOnlyToRemove.forEach(activeLayer => {
				prevState.map.removeLayer(activeLayer.id);
			});

			const layersAndSourcesToRemove = this.getMapboxLayersToRemove(mapLayers, 'Route');
			layersAndSourcesToRemove.forEach(activeLayer => {
				prevState.map.removeLayer(activeLayer.id);
				prevState.map.removeSource(activeLayer.id);
			});

			const layersOnlyToRemove = this.getMapboxLayersToRemove(mapLayers, 'symbolPoint');
			layersOnlyToRemove.forEach(activeLayer => {
				prevState.map.removeLayer(activeLayer.id);
			});

			// Get a copy of all the geojson in state and then find the destinations we will need
			const { allGeoJson } = prevState;
			const destinationIds = route.destinations.map(dest => dest.id);
			const activeRouteDestinationsGeoJson = allGeoJson.features.filter(feature =>
				destinationIds.some(dId => dId === feature.properties.id)
			);

			// Setup the updated geojson object with the relvant destinations
			const activeRouteGeoJson = {
				features: activeRouteDestinationsGeoJson,
				type: 'FeatureCollection',
			};

			// Get the current markers that have been rendered in ReactDOM and remove them if they aren't needed
			const currentDomMarkers = document.querySelectorAll(`.current-mapoint-marker`);
			currentDomMarkers.forEach(marker => {
				const routeIds = marker.getAttribute('route-ids').split(',');
				const compareCatArrays = routeIds.some(c => c === route.id);
				if (!compareCatArrays) {
					marker.remove();
				}
			});

			// If the user clicks on a route that is already active, unset it and show all points again
			if (prevState.activeRouteId === route.id) {
				this.renderMarkers(allGeoJson);
				getMapboxJs().then(({ default: mapboxgl }) => {
					const bounds = new mapboxgl.LngLatBounds();
					allGeoJson.features.forEach(feature => {
						bounds.extend(feature.geometry.coordinates);
					});
					prevState.map.fitBounds(bounds, {
						padding: { top: 200, bottom: 200, left: 200, right: 200 },
						easing(t) {
							return t * (2 - t);
						},
					});
				});

				return { geojson: allGeoJson, activeRouteId: null, activeRoute: null };
			}

			routeChunks.forEach((chunk, i) => {
				let counter = 0;
				const icon = route.routeSteps[i];
				const getIcon = icon => {
					switch (icon) {
						case 'Flight': {
							return 'airport-15';
						}
						case 'Train': {
							return 'rail-15';
						}
						default:
							return 'airport-15';
					}
				};

				const pointExists = prevState.map.getSource(`symbolPoint-${chunk[0].id}`);
				const lineExists = prevState.map.getSource(`Route-line-${i}`);

				const chunkPoint = {
					type: 'FeatureCollection',
					features: [
						{
							type: 'Feature',
							properties: {},
							geometry: {
								type: 'Point',
								coordinates: chunk[0].coordinates,
							},
						},
					],
				};

				if (!pointExists) {
					prevState.map.addSource(`symbolPoint-${chunk[0].id}`, {
						type: 'geojson',
						data: chunkPoint,
					});
				}
				const chunkLength = chunk.length;
				if (chunkLength === 2) {
					const chunkRoute = {
						type: 'FeatureCollection',
						features: [
							{
								type: 'Feature',
								geometry: {
									type: 'LineString',
									coordinates: [chunk[0].coordinates, chunk[1].coordinates],
								},
							},
						],
					};

					const chunkLine = lineString([...chunkRoute.features[0].geometry.coordinates]);
					const chunkLineDistance = length(chunkLine, { units: 'miles' });

					const chunkArc = [];
					// Draw an arc between the `origin` & `destination` of the two points
					for (let j = 0; j < chunkLineDistance; j += chunkLineDistance / steps) {
						const segment = along(chunkRoute.features[0], j, { units: 'miles' });
						chunkArc.push(segment.geometry.coordinates);
					}

					chunkRoute.features[0].geometry.coordinates = chunkArc;

					if (!lineExists) {
						prevState.map.addSource(`Route-line-${i}`, {
							type: 'geojson',
							data: chunkRoute,
						});
					}

					prevState.map.addLayer({
						id: `Route-line-${i}`,
						source: `Route-line-${i}`,
						type: 'line',
						paint: {
							'line-width': 2,
							'line-color': '#007cbf',
						},
					});

					prevState.map.addLayer({
						id: `symbolPoint-${chunk[0].id}`,
						source: `symbolPoint-${chunk[0].id}`,
						type: 'symbol',
						layout: {
							'icon-image': getIcon(icon),
							'icon-rotate': ['get', 'bearing'],
							'icon-rotation-alignment': 'map',
							'icon-allow-overlap': true,
							'icon-ignore-placement': true,
						},
					});

					const animate = () => {
						// Update point geometry to a new position based on counter denoting
						// the index to access the arc.
						const nextPoint = chunkRoute.features[0].geometry.coordinates[counter + 1];
						if (chunkRoute.features[0].geometry.coordinates[counter] !== undefined) {
							chunkPoint.features[0].geometry.coordinates = chunkRoute.features[0].geometry.coordinates[counter];

							// Calculate the bearing to ensure the icon is rotated to match the route arc
							// The bearing is calculate between the current point and the next point, except
							// at the end of the arc use the previous point and the current point
							if (nextPoint) {
								chunkPoint.features[0].properties.bearing = bearing(
									point(chunkRoute.features[0].geometry.coordinates[counter >= steps ? counter - 1 : counter]),
									point(chunkRoute.features[0].geometry.coordinates[counter >= steps ? counter : counter + 1])
								);
							}

							// Update the source with this new data.
							prevState.map.getSource(`symbolPoint-${chunk[0].id}`).setData(chunkPoint);

							// Request the next frame of animation so long the end has not been reached.
							if (counter < steps) {
								requestAnimationFrame(animate);
							}
							counter += 1;
						}
					};

					animate(counter);
				}
			});

			getMapboxJs().then(({ default: mapboxgl }) => {
				const bounds = new mapboxgl.LngLatBounds();

				route.destinations.forEach(destination => {
					bounds.extend(destination.coordinates);
				});

				prevState.map.fitBounds(bounds, {
					padding: { top: 200, bottom: 200, left: 200, right: 200 },
					easing(t) {
						return t * (2 - t);
					},
				});
			});

			// Re-render the markers and then update state
			this.renderMarkers(activeRouteGeoJson);
			return { geojson: activeRouteGeoJson, activeRouteId: route.id, activeRoute: route };
		});
	};
javascript reactjs mapbox-gl-js
1个回答
0
投票

我设法通过使用Turf.js并使用它拥有的大圆包来找到解决方案。您所要做的就是获取您正在绘制的线的起点和终点的坐标,并将它们传递给greatCircle方法,然后使用它返回的lineString来绘制Mapbox的线。

const start = point(chunk[0].coordinates);
const end = point(chunk[1].coordinates);
const circle = greatCircle(start, end);

prevState.map.addSource(`Route-line-${i}`, {
    type: 'geojson',
    data: circle,
});
© www.soinside.com 2019 - 2024. All rights reserved.