原创不易~看完若对你有所帮助,记得点一个赞哈,这就是对我最大的支持了!
讲解另一种常见应用-飞线动画,主要用于展示数据流向
/solutions/mapvdata
1. 绘制单条飞线
这里曲线的绘制可以借助百度的曲线生成器:/solutions/mapvdata
<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的前身)有很多很好的飞线图案例可以参考,不过官方已经不维护了,但是我们还是可以去学习一下,例如这里:/examples/#baidu-map-forceEdgeBundling.html
点击源码后可以看到他的实现源码,不过需要注意script路径需要改成绝对路径,默认示例里面是相对路径:
上面案例是老的mapv版本,其实不建议学习,不会详细讲解代码。
mapv是基于canvas渲染的,移动视角时会卡顿,mapvgl基于webgl实现,不会有上述问题
但是我们可以整体移植到mapvgl里面去,这个图其实内容还是比较多,他其实是由移动的点加上静态的线构成的
实现静态线layer
这其中主要涉及到一个汇聚算法的移植,我们先实现一个多点汇聚北京的线,接着看一下有没有实现静态线的layer,这里可以基于LineLayer来实现:/solutions/mapvdata
<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里面我们找到一个轨迹图,里面由很多移动点:/gl/examples/editor.html#line-point.html
他的背后其实是基于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;}
边绑定算法实现
这个算法可以帮助降低图的混乱程度,作一个边的汇聚功能,例如某个位置线特别临近,它可以帮助你汇聚在一起到达目的/gdp12315_gu/article/details/70139135:
我们目前并没有实现边绑定,效果没有上面的示例比较好,下面我们来看看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的nodetarget: 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' });
边绑定算法实际应用还是经常使用到的