我有一个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 };
});
};
答案 0 :(得分: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,
});