gif:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js地图-leaflet</title>
<link href="https://cdn.bootcss.com/leaflet/1.3.1/leaflet.css" rel="stylesheet">
<style type="text/css">
.m-map {width: 486px;height: 302px;}
.leaflet-control{display: none;}
.leaflet-right{direction: none;}
</style>
</head>
<body>
<div id="map" class="m-map"></div>
<script src="https://cdn.bootcss.com/leaflet/1.3.1/leaflet.js"></script>
<script src="src.js"></script>
<script type="text/javascript">var map = L.map('map').setView([51.505, -0.09], 1);;var positron = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {}).addTo(map);L.marker([51.5, -0.09]).addTo(map).bindPopup('这里是伦敦').openPopup();var data = [{"from":[-0.09,51.505],"to":[116.3,39.9],"labels":["伦敦","北京"],"color":"#ff3a31"}];var migrationLayer = new L.migrationLayer({map: map,data: data,pulseRadius:30,pulseBorderWidth:3,arcWidth:1,arcLabel:true,arcLabelFont:'10px sans-serif',});migrationLayer.addTo(map);
</script>
</body>
</html>

src.js:

(function (window) {var utils = {// color:rgb或rgba格式// opacity: 透明度calculateColor: function (color, opacity) {if (color.indexOf('#') === 0) {var color16 = color.slice(1);var r = parseInt(color16.slice(0, 2), 16);var g = parseInt(color16.slice(2, 4), 16);var b = parseInt(color16.slice(4), 16);return 'rgba(' + r + ',' + g + ',' + b + ',' + opacity + ')';} else if (/^rgb\(/.test(color)) {return color.replace(/rgb/, 'rgba').replace(')', ",") +opacity + ')';} else {return color.split(',').splice(0, 3).join(',') +opacity + ')';}}};var arrayUtils = {forEach: function (arr, cb, scope) {if (typeof Array.prototype.forEach === 'function') {arr.forEach(cb, scope);} else {for (var i = 0, len = arr.length; i < len; i++) {cb.apply(scope, [arr[i], i, arr]);}}},map: function (arr, cb, scope) {if (typeof Array.prototype.map === 'function') {return arr.map(cb, scope);} else {var mapped = [];for (var i = 0, len = arr.length; i < len; i++) {mapped[i] = cb.apply(scope, [arr[i], i, arr]);}return mapped;}}};var Marker = (function () {var M = function (options) {this.x = options.x;this.y = options.y;this.rotation = options.rotation;this.style = options.style;this.color = options.color;this.size = options.size;this.borderWidth = options.borderWidth;this.borderColor = options.borderColor;};M.prototype.draw = function (context) {context.save();context.translate(this.x, this.y);context.rotate(this.rotation);context.lineWidth = this.borderWidth || 0;context.strokeStyle = this.borderColor || '#000';context.fillStyle = this.color || '#000';// 目前先只支持圆context.beginPath();if (this.style === 'circle') {context.arc(0, 0, this.size, 0, Math.PI * 2, false);} else if (this.style === 'arrow') {context.moveTo(-this.size, -this.size);context.lineTo(this.size, 0);context.lineTo(-this.size, this.size);context.lineTo(-this.size / 4, 0);context.lineTo(-this.size, -this.size);}context.closePath();context.stroke();context.fill();context.restore();};return M;})();var Arc = (function () {var A = function (options) {var startX = options.startX,startY = options.startY,endX = options.endX,endY = options.endY;//两点之间的圆有多个,通过两点及半径便可以定出两个圆,根据需要选取其中一个圆var L = Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));var m = (startX + endX) / 2; // 横轴中点var n = (startY + endY) / 2; // 纵轴中点var factor = 1.5;var centerX = (startY - endY) * factor + m;var centerY = (endX - startX) * factor + n;var radius = Math.sqrt(Math.pow(L / 2, 2) + Math.pow(L * factor, 2));var startAngle = Math.atan2(startY - centerY, startX - centerX);var endAngle = Math.atan2(endY - centerY, endX - centerX);// this.L = L;this.startX = startX;this.startY = startY;this.endX = endX;this.endY = endY;this.centerX = centerX;this.centerY = centerY;this.startAngle = startAngle;this.endAngle = endAngle;this.startLabel = options && options.labels && options.labels[0],this.endLabel = options && options.labels && options.labels[1],this.radius = radius;this.lineWidth = options.width || 1;this.strokeStyle = options.color || '#000';this.label = options.label;this.font = options.font;this.shadowBlur = options.shadowBlur;};A.prototype.draw = function (context) {context.save();context.lineWidth = this.lineWidth;context.strokeStyle = this.strokeStyle;context.shadowColor = this.strokeStyle;context.shadowBlur = this.shadowBlur || 2;context.beginPath();context.arc(this.centerX, this.centerY, this.radius, this.startAngle, this.endAngle, false);context.stroke();context.restore();context.save();context.fillStyle = this.strokeStyle;if (this.label) {context.font = this.font;if (this.startLabel) {var x = this.startX - 15var y = this.startY + 5context.fillText(this.startLabel, x, y);}if (this.endLabel) {var x = this.endX - 15;var y = this.endY - 5;context.fillText(this.endLabel, x, y);}}context.restore();};return A;})();var Pulse = (function () {function P(options) {this.x = options.x;this.y = options.y;this.maxRadius = options.radius;this.color = options.color;this.shadowBlur = 5;this.lineWidth = options.borderWidth;this.r = 0;this.factor = 2 / options.radius;};P.prototype.draw = function (context) {// var vr = (this.maxRadius - this.r) * this.factor;var vr = 0.5;this.r += vr;// this.shadowBlur = Math.floor(this.r);context.save();context.translate(this.x, this.y);var strokeColor = this.color;strokeColor = utils.calculateColor(strokeColor, 1 - this.r / this.maxRadius);context.strokeStyle = strokeColor;context.shadowBlur = this.shadowBlur;context.shadowColor = strokeColor;context.lineWidth = this.lineWidth;context.beginPath();context.arc(0, 0, this.r, 0, Math.PI * 2, false);context.stroke();context.restore();if (Math.abs(this.maxRadius - this.r) < 0.8) {this.r = 0;}}return P;})();var Spark = (function () {var S = function (options) {var startX = options.startX,startY = options.startY,endX = options.endX,endY = options.endY;//两点之间的圆有多个,通过两点及半径便可以定出两个圆,根据需要选取其中一个圆var L = Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));var m = (startX + endX) / 2; // 横轴中点var n = (startY + endY) / 2; // 纵轴中点var factor = 1.5;var centerX = (startY - endY) * factor + m;var centerY = (endX - startX) * factor + n;var radius = Math.sqrt(Math.pow(L / 2, 2) + Math.pow(L * factor, 2));var startAngle = Math.atan2(startY - centerY, startX - centerX);var endAngle = Math.atan2(endY - centerY, endX - centerX);// 保证Spark的弧度不超过Math.PIif (startAngle * endAngle < 0) {if (startAngle < 0) {startAngle += Math.PI * 2;endAngle += Math.PI * 2;} else {endAngle += Math.PI * 2;}}this.tailPointsCount = 50; // 拖尾点数this.centerX = centerX;this.centerY = centerY;this.startAngle = startAngle;this.endAngle = endAngle;this.radius = radius;this.lineWidth = options.width || 1;this.strokeStyle = options.color || '#fff';this.factor = 2 / this.radius;this.deltaAngle = (80 / Math.min(this.radius, 400)) / this.tailPointsCount;this.trailAngle = this.startAngle;this.arcAngle = this.startAngle;this.animateBlur = true;this.marker = new Marker({x: 50,y: 80,rotation: 50 * Math.PI / 180,style: 'arrow',color: 'rgb(255, 255, 255)',size: 3,borderWidth: 0,borderColor: this.strokeStyle});};S.prototype.drawArc = function (context, strokeColor, lineWidth, startAngle, endAngle) {context.save();context.lineWidth = lineWidth;// context.lineWidth = 5;context.strokeStyle = strokeColor;context.shadowColor = this.strokeStyle;// context.shadowBlur = 5;context.lineCap = "round";context.beginPath();context.arc(this.centerX, this.centerY, this.radius, startAngle, endAngle, false);context.stroke();context.restore();};S.prototype.draw = function (context) {var endAngle = this.endAngle;// 匀速var angle = this.trailAngle + this.factor;var strokeColor = this.strokeStyle;if (this.animateBlur) {this.arcAngle = angle;}this.trailAngle = angle;strokeColor = utils.calculateColor(strokeColor, 0.1);this.drawArc(context, strokeColor, this.lineWidth, this.startAngle, this.arcAngle);// 拖尾效果var count = this.tailPointsCount;for (var i = 0; i < count; i++) {var arcColor = utils.calculateColor(this.strokeStyle, 0.3 - 0.3 / count * i);var tailLineWidth = 5;if (this.trailAngle - this.deltaAngle * i > this.startAngle) {this.drawArc(context, arcColor,tailLineWidth - tailLineWidth / count * i,this.trailAngle - this.deltaAngle * i,this.trailAngle);}}context.save();context.translate(this.centerX, this.centerY);this.marker.x = Math.cos(this.trailAngle) * this.radius;this.marker.y = Math.sin(this.trailAngle) * this.radius;this.marker.rotation = this.trailAngle + Math.PI / 2;this.marker.draw(context);context.restore();if ((endAngle - this.trailAngle) * 180 / Math.PI < 0.5) {this.trailAngle = this.startAngle;this.animateBlur = false;}};return S;})();var Migration = (function () {var M = function (options) {this.data = options.data;this.store = {arcs: [],markers: [],pulses: [],sparks: []};this.playAnimation = true;this.started = false;this.context = options.context;this.style = options.style;this.init();};M.prototype.init = function () {this.updateData(this.data);};/** Shape 必须拥有draw方法*/M.prototype.add = function (Shape) {};M.prototype.remove = function () {};M.prototype.clear = function () {this.store = {arcs: [],markers: [],pulses: [],sparks: []};// 更新状态this.playAnimation = true;this.started = false;// 清除绘画实例,如果没有这个方法,多次调用start,相当于存在多个动画队列同时进行window.cancelAnimationFrame(this.requestAnimationId);};/** 更新数据*/M.prototype.updateData = function (data) {if (!data || data.length === 0) {return;}this.clear();this.data = data;if (this.data && this.data.length > 0) {arrayUtils.forEach(this.data, function (element) {var arc = new Arc({startX: element.from[0],startY: element.from[1],endX: element.to[0],endY: element.to[1],labels: element.labels,label: this.style.arc.label,font: this.style.arc.font,width: this.style.arc.width,color: element.color});var marker = new Marker({x: element.to[0],y: element.to[1],rotation: arc.endAngle + Math.PI / 2,style: 'arrow',color: element.color,size: 4,borderWidth: 0,borderColor: element.color});var pulse = new Pulse({x: element.to[0],y: element.to[1],radius: this.style.pulse.radius,color: element.color,borderWidth: this.style.pulse.borderWidth});var spark = new Spark({startX: element.from[0],startY: element.from[1],endX: element.to[0],endY: element.to[1],width: 15,color: element.color});this.store.arcs.push(arc);this.store.markers.push(marker);this.store.pulses.push(pulse);this.store.sparks.push(spark);}, this);}};/**/M.prototype.start = function (canvas) {var that = this;if (!this.started) {(function drawFrame() {that.requestAnimationId = window.requestAnimationFrame(drawFrame, canvas);if (that.playAnimation) {canvas.width += 1;canvas.width -= 1;for (var p in that.store) {var shapes = that.store[p];for (var i = 0, len = shapes.length; i < len; i++) {shapes[i].draw(that.context);}}}})();this.started = true;}};M.prototype.play = function () {this.playAnimation = true;};M.prototype.pause = function () {this.playAnimation = false;};return M;})();L.MigrationLayer = L.Class.extend({options: {map: {},data: {},pulseRadius: 25,pulseBorderWidth: 3,arcWidth: 1,arcLabel: true,arcLabelFont: '15px sans-serif',Marker: {},Spark: {}},_setOptions: function (obj, options) {if (!obj.hasOwnProperty('options')) {obj.options = obj.options ? L.Util.create(obj.options) : {};}for (var i in options) {obj.options[i] = options[i];}return obj.options;},initialize: function (options) {this._setOptions(this, options);this._map = this.options.map || {};this._data = this.options.data || {};this._style = {pulse: {radius: this.options.pulseRadius,borderWidth: this.options.pulseBorderWidth},arc: {width: this.options.arcWidth,label: this.options.arcLabel,font: this.options.arcLabelFont}} || {};this._show = true;this._init();},_init: function () {var container = L.DomUtil.create('div', 'leaflet-ODLayer-container');container.style.position = 'absolute';container.style.width = this._map.getSize().x + "px";container.style.height = this._map.getSize().y + "px";this.container = container;this.canvas = document.createElement('canvas');this.context = this.canvas.getContext('2d');container.appendChild(this.canvas);this._map.getPanes().overlayPane.appendChild(container);//this._resize();if (!this.migration) {var data = this._convertData();this.migration = new Migration({data: data,context: this.context,style: this._style});//this._draw();//this._bindMapEvents();}},_resize: function () {var bounds = this._map.getBounds();var topleft = bounds.getNorthWest();var topLeftscreen = this._map.latLngToContainerPoint(topleft);//当地图缩放或者平移到整个地图的范围小于外层容器的范围的时候,要对this.container进行上下平移操作,反之则回归原位if (topLeftscreen.y > 0) {this.container.style.top = -topLeftscreen.y + 'px';} else {this.container.style.top = '0px';}var containerStyle = window.getComputedStyle(this._map.getContainer());this.canvas.setAttribute('width', parseInt(containerStyle.width, 10));this.canvas.setAttribute('height', parseInt(containerStyle.height, 10));},_convertData: function () {var bounds = this._map.getBounds();if (this._data && bounds) {var data = arrayUtils.map(this._data, function (d) {var fromPixel = this._map.latLngToContainerPoint(new L.LatLng(d.from[1], d.from[0]));var toPixel = this._map.latLngToContainerPoint(new L.LatLng(d.to[1], d.to[0]));return {from: [fromPixel.x, fromPixel.y],to: [toPixel.x, toPixel.y],labels: d.labels,value: d.value,color: d.color}}, this);return data;}},_bindMapEvents: function () {var that = this;// window.onresize = function () {//     that._resize();// };// this._map.on('movestart ', function () {//     that.migration.pause();// });this._map.on('moveend', function () {that.migration.play();that._draw();});this._map.on('zoomstart ', function () { that.container.style.display = 'none' });this._map.on('zoomend', function () {if (that._show) {that.container.style.display = ''that._draw();}});},_draw: function () {var bounds = this._map.getBounds();if (bounds && this.migration.playAnimation) {this._resize();this._transform();var data = this._convertData();this.migration.updateData(data);this.migration.start(this.canvas);}},_transform: function () {var bounds = this._map.getBounds();var topLeft = this._map.latLngToLayerPoint(bounds.getNorthWest());L.DomUtil.setPosition(this.container, topLeft);},addTo: function () {this._bindMapEvents();var bounds = this._map.getBounds();if (bounds && this.migration.playAnimation) {this._resize();this._transform();var data = this._convertData();this.migration.updateData(data);this.migration.start(this.canvas);}},setData: function (data) {this._data = data;this._draw();},hide: function () {this.container.style.display = 'none';this._show = false;},show: function () {this.container.style.display = '';this._show = true;},play: function () {this.migration.play();},pause: function () {this.migration.pause();},destroy: function () {this.migration.clear();//移除domthis.container.parentNode.removeChild(this.container);//移除事件监听this._map.clearAllEventListeners();this.mapHandles = [];}});L.migrationLayer = function (options) {return new L.MigrationLayer(options)}
})(window)

leaflet地图和飞线相关推荐

  1. Echarts实现3d 地图实现飞线效果

    Echarts实现3d 地图实现飞线效果 注意:重点关注data中的数据格式 在lines3D中symbol不能设置指定样式,echarts官网也没有这个参数,所以对于lines3D飞线如何实现飞机航 ...

  2. echart实现3d地图_3D飞线效果——让线“飞”起来的秘密

    在城市规划.统计.交通等行业,地图可视化已成为最直接也最吸引眼球的一种表达方式.例如人群迁徙.人口流动.OD出行.职住分析.客流来源等众多场景都需要用到飞线效果呈现. 2D飞线效果图 随着可视化技术的 ...

  3. vue+echarts平面地图和飞线

    记得引入文件 import * as echarts from 'echarts'; import '@/common/3Dworld.js'; 3Dworld.js链接 链接: 3Dworld.js ...

  4. 高德地图:弧度飞线图层详解

    实现弧度飞线图层需要 地图JS API 和 LOCA数据可视化API 组合实现. 概述-地图 JS API v2.0 | 高德地图API (amap.com) 概述-LOCA 数据可视化 API 2. ...

  5. echarts地图导航飞线与层级穿透

    echarts展示地图时,需要导航飞线链接起始国家与目的国家,点击国家展示对应国家放大地图.如图 echarts版本 "echarts": "^5.3.0",& ...

  6. 百度地图结合echarts实现飞线

    百度地图结合echarts实现飞线 目前很流行的地图轨迹飞线图,咱也来实现一个,使用百度地图和echarts图表实现,示例如下,(其实百度地图api有一个位置数据可视化MapV GL也可实现,需要的小 ...

  7. d3.js-V3制作简单的飞线图

    d3.js制作简单的飞线图 简介 期末的一个小作业,放上来分享一下.若有不懂的地方欢迎在评论区提问~ 最终效果图: 使用工具 d3.js (V3版本) 步骤简介 准备好数据. 绘制一个中国地图. 绘制 ...

  8. 数据可视轻松制作多点飞线图

    今天为大家讲解一下,在数据可视化软件平台中,地图-多点飞线图的使用. 数据可视化,一个可以帮助您展示数据,统计数据,分析数据,通过可视化界面,多种统计图并行的方式,完成数据交互展示. 首先,我们创建一 ...

  9. 一根飞线的故事-SVG篇

    (给IT平头哥联盟加星标,提升前端技能) 前言 作者:胖子. @胖子,目前就职于杭州数澜科技有限公司,数据可视化爱好者,对D3和其他数据可视化图表组件有一定研究.常年混迹于GitHub,热爱阅读开源代 ...

最新文章

  1. golang:mime.Decode、mime.DecodeHeader
  2. 成功解决_catboost.CatBoostError: Invalid cat_features[4] = 8 value: index must be < 8.
  3. python学习-知识点进阶使用(end、while else、range、iter、list的多种遍历方式)
  4. Windows下安装BeautifulSoup
  5. android 仿qq it蓝豹,《IT蓝豹》listview实现各种版面设计功能
  6. (Matlab问题解决)运行matlab程序后,工作区不能显示变量
  7. 一辈子的礼物56ay长沙论坛
  8. linux下u盘病毒msdos,浅谈U盘病毒——MS-DOS.com 以及做最便民的杀毒软件
  9. Module LUT6 is not defined
  10. Turbo码编码举例计算
  11. 必须收藏的文档:IronPython脚本在TIBCO Spotfire中的使用
  12. KETTLE将txt文本文件加载入库
  13. webcron 定时任务管理系统
  14. 看雪CTF.TSRC 2018 团队赛-第六题 追凶者也--拼图游戏
  15. MT6589下载工具,MT6589刷机工具
  16. Proteus的安装和介绍及51单片机电路仿真
  17. Gopher China 2019 讲师专访-腾讯/TARS开源团队核心成员陈明杰
  18. Streptavidin-MAL,Maleimide 马来酰亚胺修饰/标记/偶联链霉亲和素
  19. 如何从生活中领悟设计模式
  20. pow函数 真假硬币

热门文章

  1. 用showdown给HTML网页插入markdown笔记
  2. 计算机休眠模式是关机吗,电脑中的待机、休眠、睡眠和关机状态的区别。
  3. VS2015中更改项目名称
  4. MySQL优化之执行计划
  5. -atime、-ctime、mtime、-newer
  6. ABOV单片机KEIL C51编译器程序仿真器OCD-II操作步骤详解
  7. mysql报错error2002_mysql中异常出错ERROR:2002的处理办法分享
  8. 回归:最小二乘法求解回归模型代码
  9. Android中播放音乐的几种方式
  10. html怎么设置点击播放音乐,html5点击播放音乐试听按钮动画特效