У меня есть карта mapbox, на которой я рисую точки и рисую линии между точками для создания маршрутов.Настройка работает нормально, а анимация работает так, как задумано.
Однако, когда у меня есть линия, которая пересекает новую копию мира, изогнутая линия рисуется, но другая линия также рисуется по всей карте.
Кто-нибудь знает способ обработки рисования линий, чтобы они не переходили в новый мир?Или есть идеи о том, как лучше всего рисовать линии?
В качестве ссылки я использую пример 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 };
});
};