Google Maps API 折线动画速度与线段长度适配问题
Ah, I get it—using a fixed offset increment makes longer lines animate faster because each percentage jump covers more actual distance. The key is to adjust the offset change based on each line's total length so that all lines move at the same real-world speed (like meters per second). Here's how to do it:
Step 1: Calculate Each Polyline's Total Length
First, you need to know how long each polyline is. Use Google Maps' geometry library to compute the length in meters for every line. Make sure you include the geometry library in your Maps script URL (add &libraries=geometry to the end).
Step 2: Track Per-Polyline Data
Store each line's total length and its current animation offset so you can update them individually. A Map works great for this.
Step 3: Animate Based on Time and Speed
Instead of using a fixed offset increment per frame, calculate how much distance each line should cover in the time since the last frame. Convert that distance to a percentage of the line's total length to get the offset change.
Full Code Example
// Initialize your map first (omitted for brevity) // Create your polylines with animation symbols const polylines = [ new google.maps.Polyline({ path: [{ lat: 37.7749, lng: -122.4194 }, { lat: 37.789, lng: -122.407 }], map: map, strokeColor: '#FF0000', icons: [{ icon: { path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW }, offset: '0%' }] }), new google.maps.Polyline({ path: [{ lat: 37.7749, lng: -122.4194 }, { lat: 37.765, lng: -122.432 }], map: map, strokeColor: '#00FF00', icons: [{ icon: { path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW }, offset: '0%' }] }) ]; // Store length and current offset for each polyline const polylineAnimationData = new Map(); polylines.forEach(polyline => { const totalLength = google.maps.geometry.spherical.computeLength(polyline.getPath()); polylineAnimationData.set(polyline, { totalLength: totalLength, currentOffset: 0 }); }); // Set your desired speed in meters per second const animationSpeed = 50; // 50 meters per second let lastAnimationTimestamp = 0; function animatePolylines(timestamp) { // Initialize last timestamp on first run if (!lastAnimationTimestamp) lastAnimationTimestamp = timestamp; // Calculate time passed since last frame (in seconds) const deltaTime = (timestamp - lastAnimationTimestamp) / 1000; // Update each polyline's animation polylineAnimationData.forEach((data, polyline) => { // How far should this line move in this frame? const distanceToMove = animationSpeed * deltaTime; // Convert distance to percentage of the line's total length const offsetIncrement = (distanceToMove / data.totalLength) * 100; // Update current offset data.currentOffset += offsetIncrement; // Reset if we've reached the end of the line if (data.currentOffset > 100) { data.currentOffset = 0; // Loop back to start, or set to 100 to stop } // Apply the new offset to the polyline's symbol const icons = polyline.get('icons'); icons[0].offset = `${data.currentOffset}%`; polyline.set('icons', icons); }); // Update last timestamp for next frame lastAnimationTimestamp = timestamp; // Keep the animation going requestAnimationFrame(animatePolylines); } // Start the animation loop requestAnimationFrame(animatePolylines);
Key Notes:
- Consistent Speed: By calculating offset based on distance per time unit, every line moves the same number of meters per second, regardless of length.
- Geometry Library: Don't forget to include
&libraries=geometryin your Google Maps API script URL—otherwisecomputeLengthwon't work. - Loop Control: If you don't want the animation to loop, replace the reset to 0 with setting
data.currentOffset = 100and stop the animation by canceling therequestAnimationFrame(store the ID and callcancelAnimationFramewhen needed).
This approach ensures that all your polylines animate at the same real-world speed, fixing the "longer lines move faster" issue you're seeing.
内容的提问来源于stack exchange,提问作者MarvinVK

