如何使用 pidgeon-maps 在 Reactjs 中对地图上的点之间的线进行动画处理?

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

在我的 Reactjs 应用程序中,我使用一个名为 pidegon-maps 的轻量级地图库来显示船只位置。在不尝试使用更大的库(传单、谷歌地图反应)的情况下,我尝试为船只所走的路线制作动画。

从这个问题中汲取灵感,我尝试创建一个类似的实现。

useEffect(() => {

let start = [0.108266, 52.202758];
let end = [0.11556, 52.201733];

const speedFactor = 500;

let diffX = parseFloat(end[0]) - parseFloat(start[0]);
let diffY = parseFloat(end[1]) - parseFloat(start[1]);
let sfX = diffX / speedFactor;
let sfY = diffY / speedFactor;

let i = 0;
let j = 0;

let lineCoordinates = [];

while (i < diffX || Math.abs(j) < Math.abs(diffY)) {
  lineCoordinates.push([start[0] + i, start[0] + j]);

  if (i < diffX) {
    i += sfX;
  }

  if (Math.abs(j) < Math.abs(diffY)) {
    j += sfY;
  }
}

console.log(lineCoordinates);
let animationCounter = 0;

const animateLine = () => {
  if (animationCounter < lineCoordinates.length) {
    geojson.features[0].geometry.coordinates.push(lineCoordinates[animationCounter]);
    requestAnimationFrame(animateLine);
    animationCounter++;
    
  }

}

animateLine();

}, []);

由于某种原因,它在动画中运行得非常快,然后消失。它还仅将线显示为直线(南北,根本没有角度),因此它实际上并没有连接。距离是正确的,但角度不正确。我尝试将其移动到状态,因为放大和缩小时,它会导致地图重新渲染。这工作得很好,但它只在放大和缩小时才会有动画效果。所以我可以将其速度减慢至 1000 并放大和缩小并观看它的动画,但它本身不会这样做。

目前,它处于 useEffect 中,但我也将其删除并尝试不使用它。

reactjs requestanimationframe maptiler
1个回答
0
投票

有两种方法可以实现此目的,一种是为每个步骤添加许多点到

lineString
,就像您正在尝试实现的那样。

另一种方法是使用 css 让 svg 自行绘制,这种方法更简单,推荐使用。关键的 CSS 属性

stroke-dashoffset
现已得到广泛支持。

方法一:CSS

#VesslePath1{
    stroke-dasharray: 1;
    stroke-dashoffset: 0;
    /*Remove infinite if you don't want it to repeat*/
    animation: dash 3s linear forward infinite;
}

@keyframes dash {
    from{
        stroke-dashoffset: 1;
    }
    to {
        stroke-dashoffset: 0;
    }
}
import { GeoJson, GeoJsonFeature, Map, Marker } from "pigeon-maps";

const start = [0.108266, 52.202758];
const end = [0.11556, 52.201733];

export function MyMap() {

    const feature = {
        "type": "Feature",
        "properties": {
        },
        "geometry": {
            "type": "LineString",
            "coordinates": [start, end]
        }
    }

    return (
        <div>
            <Map height={600} width={1000} defaultCenter={[52.202245, 0.111913]} defaultZoom={15}>
            <Marker width={50} anchor={[52.202758, 0.108266]} />
            <Marker width={50} anchor={[52.201733, 0.11556]} />

                <GeoJson
                    svgAttributes={{
                        fill: "#d4e6ec99",
                        strokeWidth: "4",
                        stroke: "black",
                        r: "20",
                        id: "VesslePath1",
                        pathLength:"1"
                    }}
                >
                    <GeoJsonFeature feature={feature} />
                </GeoJson>
            </Map>
        </div>
    );
}

沙盒演示

方法2:您原来的方法,在

LineString
中有多个点 我不确定你原来的问题是什么,因为你只显示了 useEffect 方法,但可能的问题很少:

  1. geoJson坐标(
    [lng,lat]
    )与鸽子地图坐标(
    [lat,lng]
    )相反
  2. 不确定您的
    requestAnimationFrame
    框架在这里如何使用以及是否正确使用。因此,我已经切换到
    setIntervals
import { GeoJson, GeoJsonFeature, Map, Marker } from "pigeon-maps";
import { useEffect, useState } from "react";

const speedFactor = 600;
const start = [0.108266, 52.202758];
const end = [0.11556, 52.201733];
const diffX = parseFloat(end[0]) - parseFloat(start[0]);
const diffY = parseFloat(end[1]) - parseFloat(start[1]);
const sfX = diffX / speedFactor;
const sfY = diffY / speedFactor;

export function MyMap() {

    const [coordinates, setCoordinates] = useState([start, [start[0] + sfX, start[1] + sfY]]);

    useEffect(() => {
        let currentDiff = [sfX, sfY]
        const interval = setInterval(() => {
            
            currentDiff[0] += sfX;
            currentDiff[1] += sfY;

            if (Math.abs(currentDiff[0]) > Math.abs(diffX)  || Math.abs(currentDiff[1]) > Math.abs(diffY)) {
                setCoordinates((prevCoordinates) => [
                    ...prevCoordinates,
                    end,
                ]);
                clearInterval(interval);
                return;
            }
            
            setCoordinates((prevCoordinates) => [
                ...prevCoordinates,
                [start[0] + currentDiff[0], start[1] + currentDiff[1]],
            ]);
        }, 10);

        return () => clearInterval(interval);
    }, []);

    const feature = {
        "type": "Feature",
        "properties": {
        },
        "geometry": {
            "type": "LineString",
            "coordinates": coordinates
        }
    }

    return (
        <div>
            <Map height={600} width={1000} defaultCenter={[52.202245, 0.111913]} defaultZoom={15}>
            <Marker width={50} anchor={[52.202758, 0.108266]} />
            <Marker width={50} anchor={[52.201733, 0.11556]} />

                <GeoJson
                    svgAttributes={{
                        fill: "#d4e6ec99",
                        strokeWidth: "4",
                        stroke: "black",
                        r: "20",
                    }}
                >
                    <GeoJsonFeature feature={feature} />
                </GeoJson>
            </Map>
        </div>
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.