百度地图开发入门(5):飞线动画示例

2,181 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

讲解另一种常见应用-飞线动画,主要用于展示数据流向

lbsyun.baidu.com/solutions/m…

1. 绘制单条飞线

这里曲线的绘制可以借助百度的曲线生成器:lbsyun.baidu.com/solutions/m…

<body>

    <div id="map_container"></div>

    <script>

        const map = initBMap();

        const data = initData();

        setData(data, map);



        // 初始化百度地图

        function initBMap() {

            // 引入的common库所作的处理

            // mapv提供了api,根据名称获取坐标

            const cityCenter = mapv.utilCityCenter.getCenterByCityName('上海');

            const map = initMap({

                center: [cityCenter.lng, cityCenter.lat],

                zoom: 6,

                style: purpleStyle,

                tilt: 30

            })

            return map;



        }





        // 准备数据源

        function initData() {

            let data = [];

            // 生成贝塞尔曲线坐标集 - 关键要素

            // 1. 实例化贝塞尔曲线对象

            const curve = new mapvgl.BezierCurve();

            // 2. 设置起始和终点坐标

            const start = mapv.utilCityCenter.getCenterByCityName('上海');

            const end = mapv.utilCityCenter.getCenterByCityName('北京');

            curve.setOptions({

                start:[start.lng, start.lat],

                end:[end.lng, end.lat]

            });

            // 3. 生成贝塞尔曲线坐标集

            const curveData = curve.getPoints();

            data.push({

                geometry:{

                    type: 'LineString',

                    coordinates: curveData

                }

            })

            return data;

        }





        // 绘制数据源 

        function setData(data, map) {

           const view = new mapvgl.View({map});

           // 初始化飞线对象并添加到图层中

            const flyLine = new mapvgl.FlyLineLayer({

                // 更多配置项可以看文档

                color: 'red',

                textureColor: 'blue',

                textureWidth: 20,

                textureLength: 80,

                style: 'chaos',

                step: 0.5

            });

            view.addLayer(flyLine);

            flyLine.setData(data);



        }

    </script>

</body>

// 绘制数据源 

        function setData(data, map) {

           const view = new mapvgl.View({map});

           // 初始化飞线对象并添加到图层中

            const flyLine = new mapvgl.FlyLineLayer({

                // 更多配置项可以看文档

                color: 'rgba(33,242,214,0.3)',

                textureColor: '#ff0000',

                textureWidth: 20,

                textureLength: 10,

                style: 'chaos',

                step: 0.3

            });

            view.addLayer(flyLine);

            flyLine.setData(data);



        }

2. 增加更多的线

// 准备数据源

        function initData() {

            let data = [];

            const cities = [

                '北京', '天津', '上海', '重庆', '石家庄', '太原', '呼和浩特', '哈尔滨',

                '长春', '沈阳', '济南', '南京', '合肥', '杭州', '南昌', '福州', '郑州',

                '武汉', '长沙', '广州', '南宁', '西安', '银川', '兰州', '西宁', '乌鲁木齐',

                '成都', '贵阳', '昆明', '拉萨', '海口'

            ];

            let randomCount = 100;

            // 生成贝塞尔曲线坐标集 - 关键要素

            // 1. 实例化贝塞尔曲线对象

            const curve = new mapvgl.BezierCurve();

            while (randomCount--) {

                // 2. 设置起始和终点坐标

                const start = mapv.utilCityCenter.getCenterByCityName(cities[parseInt(Math.random() * cities.length)]);

                const end = mapv.utilCityCenter.getCenterByCityName(cities[parseInt(Math.random() * cities.length)]);

                curve.setOptions({

                    start: [start.lng, start.lat],

                    end: [end.lng, end.lat]

                });

                // 3. 生成贝塞尔曲线坐标集

                const curveData = curve.getPoints();

                data.push({

                    geometry: {

                        type: 'LineString',

                        coordinates: curveData

                    }

                })

            }



            return data;

        }

3. mapv示例移植mapvgl - 点汇聚线图

这里其实mapv(mapvgl的前身)有很多很好的飞线图案例可以参考,不过官方已经不维护了,但是我们还是可以去学习一下,例如这里:mapv.baidu.com/examples/#b…

点击源码后可以看到他的实现源码,不过需要注意script路径需要改成绝对路径,默认示例里面是相对路径:

image.png

上面案例是老的mapv版本,其实不建议学习,不会详细讲解代码。

mapv是基于canvas渲染的,移动视角时会卡顿,mapvgl基于webgl实现,不会有上述问题

但是我们可以整体移植到mapvgl里面去,这个图其实内容还是比较多,他其实是由移动的点加上静态的线构成的

实现静态线layer

这其中主要涉及到一个汇聚算法的移植,我们先实现一个多点汇聚北京的线,接着看一下有没有实现静态线的layer,这里可以基于LineLayer来实现:lbsyun.baidu.com/solutions/m…

<body>

    <div id="map_container"></div>

    <script>

        const map = initBMap();

        const data = initData();

        setData(data, map);



        // 初始化百度地图

        function initBMap() {

            // 引入的common库所作的处理

            // mapv提供了api,根据名称获取坐标

            const cityCenter = mapv.utilCityCenter.getCenterByCityName('北京');

            const map = initMap({

                center: [cityCenter.lng, cityCenter.lat],

                zoom: 5,

                style: purpleStyle,

                tilt: 0

            })

            return map;



        }





        // 准备数据源

        function initData() {

            let data = [];

            const cities = [

                '北京', '天津', '上海'

            ];

            let randomCount = 100;

            const targetCity = mapv.utilCityCenter.getCenterByCityName('北京');

            const curve = new mapvgl.BezierCurve();

            for (let i = 1; i < cities.length; i++) {

                const startCity = mapv.utilCityCenter.getCenterByCityName(cities[i]);

                curve.setOptions({

                    start: [startCity.lng, startCity.lat],

                    end: [targetCity.lng, targetCity.lat]

                })

                const curveData = curve.getPoints();

                data.push({

                    geometry: {

                        type: 'LineString',

                        coordinates: curveData

                    }

                });



            }





            return data;

        }





        // 绘制数据源 

        function setData(data, map) {

            const view = new mapvgl.View({ map });

            // 初始化linelayer实现静态线

            const lineLayer = new mapvgl.LineLayer({

                color: 'rgba(55,50,250,0.3)'

            });

            view.addLayer(lineLayer);

            lineLayer.setData(data);



        }







    </script>

</body>

实现移动点layer

这里需要注意移动点layer的轨迹其实是和静态线一致的,就是说背后的data是一样的,这里官网上没有找到layer,但是在示例demo里面我们找到一个轨迹图,里面由很多移动点:mapv.baidu.com/gl/examples…

他的背后其实是基于LinePointLayer实现的,但是官方文档没有这个Layer的信息,我们只能参考demo的做法来实现:

// 绘制数据源 

        function setData(data, map) {

            const view = new mapvgl.View({ map });

            // 初始化linelayer实现静态线

            const lineLayer = new mapvgl.LineLayer({

                color: 'rgba(55,50,250,0.3)'

            });

            const linePointLayer = new mapvgl.LinePointLayer({

                size: 8, // 点大小

                speed: 12, // 点运动速度

                color: 'rgba(255, 255, 0, 0.6)',

                animationType: mapvgl.LinePointLayer.ANIMATION_TYPE_SMOOTH, // 点动画类型

                shapeType: mapvgl.LinePointLayer.SHAPE_TYPE_CIRCLE, //点形状

                blend: 'lighter' // 交会时处理

            });

            view.addLayer(lineLayer);

            view.addLayer(linePointLayer)

            lineLayer.setData(data);

            linePointLayer.setData(data);



        }

实现更多的点

这里仍然基于随机数来生生成一些随机点汇聚目标:

// 准备数据源

        function initData() {

            let data = [];

            const cities = [

                '北京', '天津', '上海', '重庆', '石家庄', '太原', '呼和浩特', '哈尔滨',

                '长春', '沈阳', '济南', '南京', '合肥', '杭州', '南昌', '福州', '郑州',

                '武汉', '长沙', '广州', '南宁', '西安', '银川', '兰州', '西宁', '乌鲁木齐',

                '成都', '贵阳', '昆明', '拉萨', '海口'

            ];

            let randomCount = 500;

            const targetCity = mapv.utilCityCenter.getCenterByCityName('北京');

            const curve = new mapvgl.BezierCurve();

            for (let i = 0; i < randomCount; i++) {

                const startCity = mapv.utilCityCenter.getCenterByCityName(cities[parseInt(Math.random() * cities.length)]);

                curve.setOptions({

                    start: [startCity.lng - 5 + 10 * Math.random(), startCity.lat - 5 + 10 * Math.random()],

                    end: [targetCity.lng, targetCity.lat]

                })

                const curveData = curve.getPoints();

                data.push({

                    geometry: {

                        type: 'LineString',

                        coordinates: curveData

                    }

                });



            }





            return data;

        }

边绑定算法实现

这个算法可以帮助降低图的混乱程度,作一个边的汇聚功能,例如某个位置线特别临近,它可以帮助你汇聚在一起到达目的blog.csdn.net/gdp12315_gu…

我们目前并没有实现边绑定,效果没有上面的示例比较好,下面我们来看看mapv的工具方法来作边绑定

        // 准备数据源

        function initData() {

            let data = [];

            const cities = [

                '北京', '天津', '上海', '重庆', '石家庄', '太原', '呼和浩特', '哈尔滨',

                '长春', '沈阳', '济南', '南京', '合肥', '杭州', '南昌', '福州', '郑州',

                '武汉', '长沙', '广州', '南宁', '西安', '银川', '兰州', '西宁', '乌鲁木齐',

                '成都', '贵阳', '昆明', '拉萨', '海口'

            ];

            const targetCity = mapv.utilCityCenter.getCenterByCityName('北京');

            let nodeData = [{

                x: targetCity.lng,

                y: targetCity.lat

            }]; // 点

            let edgeData = [{

                source: 0, // 0表示的是nodeData的第0号元素

                target: 0 // 0 - 0号元素的线

            }]; // 边,表示点点关系

            // 我们需要生成一系列node和edge数据





            let randomCount = 500;

            const curve = new mapvgl.BezierCurve();

            for (let i = 0; i < randomCount; i++) {

                const startCity = mapv.utilCityCenter.getCenterByCityName(cities[parseInt(Math.random() * cities.length)]);

                nodeData.push({

                    x: startCity.lng + 5 - Math.random() * 10,

                    y: startCity.lat + 5 - Math.random() * 10

                });

                edgeData.push({

                    source: i + 1, // source为上面新push的node

                    target: 0

                })

            }

            // 基于百度边绑定API获取需要的数据

            const bundling = mapv.utilForceEdgeBundling().nodes(nodeData).edges(edgeData);

            const results = bundling(); // 获取所有线沿途的点数据 - 一个二维数组

            for (let i = 0; i < results.length; i++) {

                const line = results[i];

                const coordinates = [];

                for (let j = 0; j < line.length; j++) {

                    coordinates.push([line[j].x, line[j].y])



                }

                data.push({

                    geometry: {

                        type: 'LineString',

                        coordinates

                    }

                });



            }

            return data;

        }





        // 绘制数据源 

        function setData(data, map) {

            const view = new mapvgl.View({ map });

            // 初始化linelayer实现静态线

            const lineLayer = new mapvgl.LineLayer({

                color: 'rgba(55,50,250,0.5)'

            });

            const linePointLayer = new mapvgl.LinePointLayer({

                size: 5, // 点大小

                speed: 12, // 点运动速度

                color: 'rgba(255, 255, 0, 0.6)',

                animationType: mapvgl.LinePointLayer.ANIMATION_TYPE_SMOOTH, // 点动画类型

                shapeType: mapvgl.LinePointLayer.SHAPE_TYPE_CIRCLE, //点形状

                blend: 'lighter' // 交会时处理

            });

            view.addLayer(lineLayer);

            view.addLayer(linePointLayer)

            lineLayer.setData(data);

            linePointLayer.setData(data);



        }

再加上汇聚效果

// 初始化linelayer实现静态线

            const lineLayer = new mapvgl.LineLayer({

                color: 'rgba(55,50,250,0.5)',

                blend: 'lighter' 

            });

边绑定算法实际应用还是经常使用到的