欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Openlayers4中实现动态线效果

发布时间:2025/7/14 编程问答 47 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Openlayers4中实现动态线效果 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

2019独角兽企业重金招聘Python工程师标准>>>

概述:

本文讲述如何结合canvas在Openlayers4中实现动态线的效果。

 

效果:

 

代码:

1、move-line扩展

 

[javascript] view plain copy

  • (function (global, factory) {  
  •     typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :  
  •         typeof define === 'function' && define.amd ? define(factory) :  
  •             (global.MoveLine = factory());  
  • }(this, (function () { 'use strict';  
  •   
  •     /** 
  •      * @author https://github.com/chengquan223 
  •      * @Date 2017-02-27 
  •      * */  
  •     function CanvasLayer(options) {  
  •         this.options = options || {};  
  •         this.paneName = this.options.paneName || 'labelPane';  
  •         this.zIndex = this.options.zIndex || 0;  
  •         this._map = options.map;  
  •         this._lastDrawTime = null;  
  •         this.show();  
  •     }  
  •   
  •     CanvasLayer.prototype.initialize = function () {  
  •         var canvas = this.canvas = document.createElement('canvas');  
  •         var ctx = this.ctx = this.canvas.getContext('2d');  
  •         canvas.style.cssText = 'position:absolute;' + 'left:0;' + 'top:0;' + 'z-index:' + this.zIndex + ';';  
  •         this.adjustSize();  
  •         this.adjustRatio(ctx);  
  •         map.getViewport().appendChild(canvas);  
  •         var that = this;  
  •         map.getView().on('propertychange',function(){  
  •             $(canvas).hide();  
  •         });  
  •         map.on("moveend",function(){  
  •             $(canvas).show();  
  •             that.adjustSize();  
  •             that._draw();  
  •         });  
  •         return this.canvas;  
  •     };  
  •   
  •     CanvasLayer.prototype.adjustSize = function () {  
  •         var size = this._map.getSize();  
  •         var canvas = this.canvas;  
  •         canvas.width = size[0];  
  •         canvas.height = size[1];  
  •         canvas.style.width = canvas.width + 'px';  
  •         canvas.style.height = canvas.height + 'px';  
  •     };  
  •   
  •     CanvasLayer.prototype.adjustRatio = function (ctx) {  
  •         var backingStore = ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;  
  •         var pixelRatio = (window.devicePixelRatio || 1) / backingStore;  
  •         var canvasWidth = ctx.canvas.width;  
  •         var canvasHeight = ctx.canvas.height;  
  •         ctx.canvas.width = canvasWidth * pixelRatio;  
  •         ctx.canvas.height = canvasHeight * pixelRatio;  
  •         ctx.canvas.style.width = canvasWidth + 'px';  
  •         ctx.canvas.style.height = canvasHeight + 'px';  
  •         ctx.scale(pixelRatio, pixelRatio);  
  •     };  
  •   
  •     CanvasLayer.prototype.draw = function () {  
  •         var self = this;  
  •         var args = arguments;  
  •         clearTimeout(self.timeoutID);  
  •         self.timeoutID = setTimeout(function () {  
  •             self._draw();  
  •         }, 15);  
  •     };  
  •   
  •     CanvasLayer.prototype._draw = function () {  
  •         var map = this._map;  
  •         var size = map.getSize();  
  •         var center = map.getView().getCenter();  
  •         if (center) {  
  •             var pixel = map.getPixelFromCoordinate(center);  
  •             this.canvas.style.left = pixel[0] - size[0] / 2 + 'px';  
  •             this.canvas.style.top = pixel[1] - size[1] / 2 + 'px';  
  •             this.options.update && this.options.update.call(this);  
  •         }  
  •     };  
  •   
  •     CanvasLayer.prototype.getContainer = function () {  
  •         return this.canvas;  
  •     };  
  •   
  •     CanvasLayer.prototype.show = function () {  
  •         this.initialize();  
  •         this.canvas.style.display = 'block';  
  •     };  
  •   
  •     CanvasLayer.prototype.hide = function () {  
  •         this.canvas.style.display = 'none';  
  •     };  
  •   
  •     CanvasLayer.prototype.setZIndex = function (zIndex) {  
  •         this.canvas.style.zIndex = zIndex;  
  •     };  
  •   
  •     CanvasLayer.prototype.getZIndex = function () {  
  •         return this.zIndex;  
  •     };  
  •   
  •     var global = typeof window === 'undefined' ? {} : window;  
  •   
  •     var requestAnimationFrame = global.requestAnimationFrame || global.mozRequestAnimationFrame || global.webkitRequestAnimationFrame || global.msRequestAnimationFrame || function (callback) {  
  •             return global.setTimeout(callback, 1000 / 60);  
  •         };  
  •   
  •     var MoveLine = function MoveLine(map, userOptions) {  
  •         var self = this;  
  •   
  •         //默认参数  
  •         var options = {  
  •             //marker点半径  
  •             markerRadius: 3,  
  •             //marker点颜色,为空或null则默认取线条颜色  
  •             markerColor: '#fff',  
  •             //线条类型 solid、dashed、dotted  
  •             lineType: 'solid',  
  •             //线条宽度  
  •             lineWidth: 1,  
  •             //线条颜色  
  •             colors: ['#F9815C', '#F8AB60', '#EDCC72', '#E2F194', '#94E08A', '#4ECDA5'],  
  •             //移动点半径  
  •             moveRadius: 2,  
  •             //移动点颜色  
  •             fillColor: '#fff',  
  •             //移动点阴影颜色  
  •             shadowColor: '#fff',  
  •             //移动点阴影大小  
  •             shadowBlur: 5  
  •         };  
  •   
  •         //全局变量  
  •         var baseLayer = null,  
  •             animationLayer = null,  
  •             width = map.getSize()[0],  
  •             height = map.getSize()[1],  
  •             animationFlag = true,  
  •             markLines = [];  
  •   
  •         //参数合并  
  •         var merge = function merge(userOptions, options) {  
  •             Object.keys(userOptions).forEach(function (key) {  
  •                 options[key] = userOptions[key];  
  •             });  
  •         };  
  •   
  •         function Marker(opts) {  
  •             this.city = opts.city;  
  •             this.location = opts.location;  
  •             this.color = opts.color;  
  •         }  
  •   
  •         Marker.prototype.draw = function (context) {  
  •             var pixel = this.pixel = map.getPixelFromCoordinate(this.location);  
  •   
  •             context.save();  
  •             context.beginPath();  
  •             context.fillStyle = options.markerColor || this.color;  
  •             context.arc(pixel[0], pixel[1], options.markerRadius, 0, Math.PI * 2, true);  
  •             context.closePath();  
  •             context.fill();  
  •   
  •             context.textAlign = 'center';  
  •             context.textBaseline = 'middle';  
  •             context.font = '12px Microsoft YaHei';  
  •             context.fillStyle = this.color;  
  •             context.fillText(this.city, pixel[0], pixel[1] - 10);  
  •             context.restore();  
  •         };  
  •   
  •         function MarkLine(opts) {  
  •             this.from = opts.from;  
  •             this.to = opts.to;  
  •             this.id = opts.id;  
  •             this.step = 0;  
  •         }  
  •   
  •         MarkLine.prototype.getPointList = function (from, to) {  
  •             var points = [[from[0], from[1]], [to[0], to[1]]];  
  •             var ex = points[1][0];  
  •             var ey = points[1][1];  
  •             points[3] = [ex, ey];  
  •             points[1] = this.getOffsetPoint(points[0], points[3]);  
  •             points[2] = this.getOffsetPoint(points[3], points[0]);  
  •             points = this.smoothSpline(points, false);  
  •             //修正最后一点在插值产生的偏移  
  •             points[points.length - 1] = [ex, ey];  
  •             return points;  
  •         };  
  •   
  •         MarkLine.prototype.getOffsetPoint = function (start, end) {  
  •             var distance = this.getDistance(start, end) / 3; //除以3?  
  •             var angle, dX, dY;  
  •             var mp = [start[0], start[1]];  
  •             var deltaAngle = -0.2; //偏移0.2弧度  
  •             if (start[0] != end[0] && start[1] != end[1]) {  
  •                 //斜率存在  
  •                 var k = (end[1] - start[1]) / (end[0] - start[0]);  
  •                 angle = Math.atan(k);  
  •             } else if (start[0] == end[0]) {  
  •                 //垂直线  
  •                 angle = (start[1] <= end[1] ? 1 : -1) * Math.PI / 2;  
  •             } else {  
  •                 //水平线  
  •                 angle = 0;  
  •             }  
  •             if (start[0] <= end[0]) {  
  •                 angle -= deltaAngle;  
  •                 dX = Math.round(Math.cos(angle) * distance);  
  •                 dY = Math.round(Math.sin(angle) * distance);  
  •                 mp[0] += dX;  
  •                 mp[1] += dY;  
  •             } else {  
  •                 angle += deltaAngle;  
  •                 dX = Math.round(Math.cos(angle) * distance);  
  •                 dY = Math.round(Math.sin(angle) * distance);  
  •                 mp[0] -= dX;  
  •                 mp[1] -= dY;  
  •             }  
  •             return mp;  
  •         };  
  •   
  •         MarkLine.prototype.smoothSpline = function (points, isLoop) {  
  •             var len = points.length;  
  •             var ret = [];  
  •             var distance = 0;  
  •             for (var i = 1; i < len; i++) {  
  •                 distance += this.getDistance(points[i - 1], points[i]);  
  •             }  
  •             var segs = distance / 2;  
  •             segs = segs < len ? len : segs;  
  •             for (var i = 0; i < segs; i++) {  
  •                 var pos = i / (segs - 1) * (isLoop ? len : len - 1);  
  •                 var idx = Math.floor(pos);  
  •                 var w = pos - idx;  
  •                 var p0;  
  •                 var p1 = points[idx % len];  
  •                 var p2;  
  •                 var p3;  
  •                 if (!isLoop) {  
  •                     p0 = points[idx === 0 ? idx : idx - 1];  
  •                     p2 = points[idx > len - 2 ? len - 1 : idx + 1];  
  •                     p3 = points[idx > len - 3 ? len - 1 : idx + 2];  
  •                 } else {  
  •                     p0 = points[(idx - 1 + len) % len];  
  •                     p2 = points[(idx + 1) % len];  
  •                     p3 = points[(idx + 2) % len];  
  •                 }  
  •                 var w2 = w * w;  
  •                 var w3 = w * w2;  
  •   
  •                 ret.push([this.interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3), this.interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)]);  
  •             }  
  •             return ret;  
  •         };  
  •   
  •         MarkLine.prototype.interpolate = function (p0, p1, p2, p3, t, t2, t3) {  
  •             var v0 = (p2 - p0) * 0.5;  
  •             var v1 = (p3 - p1) * 0.5;  
  •             return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;  
  •         };  
  •   
  •         MarkLine.prototype.getDistance = function (p1, p2) {  
  •             return Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));  
  •         };  
  •   
  •         MarkLine.prototype.drawMarker = function (context) {  
  •             this.from.draw(context);  
  •             this.to.draw(context);  
  •         };  
  •   
  •         MarkLine.prototype.drawLinePath = function (context) {  
  •             var pointList = this.path = this.getPointList(map.getPixelFromCoordinate(this.from.location), map.getPixelFromCoordinate(this.to.location));  
  •             var len = pointList.length;  
  •             context.save();  
  •             context.beginPath();  
  •             context.lineWidth = options.lineWidth;  
  •             context.strokeStyle = options.colors[this.id];  
  •   
  •             if (!options.lineType || options.lineType == 'solid') {  
  •                 context.moveTo(pointList[0][0], pointList[0][1]);  
  •                 for (var i = 0; i < len; i++) {  
  •                     context.lineTo(pointList[i][0], pointList[i][1]);  
  •                 }  
  •             } else if (options.lineType == 'dashed' || options.lineType == 'dotted') {  
  •                 for (var i = 1; i < len; i += 2) {  
  •                     context.moveTo(pointList[i - 1][0], pointList[i - 1][1]);  
  •                     context.lineTo(pointList[i][0], pointList[i][1]);  
  •                 }  
  •             }  
  •             context.stroke();  
  •             context.restore();  
  •             this.step = 0; //缩放地图时重新绘制动画  
  •         };  
  •   
  •         MarkLine.prototype.drawMoveCircle = function (context) {  
  •             var pointList = this.path || this.getPointList(map.getPixelFromCoordinate(this.from.location), map.getPixelFromCoordinate(this.to.location));  
  •   
  •             context.save();  
  •             context.fillStyle = options.fillColor;  
  •             context.shadowColor = options.shadowColor;  
  •             context.shadowBlur = options.shadowBlur;  
  •             context.beginPath();  
  •             context.arc(pointList[this.step][0], pointList[this.step][1], options.moveRadius, 0, Math.PI * 2, true);  
  •             context.fill();  
  •             context.closePath();  
  •             context.restore();  
  •             this.step += 1;  
  •             if (this.step >= pointList.length) {  
  •                 this.step = 0;  
  •             }  
  •         };  
  •   
  •         //底层canvas渲染,标注,线条  
  •         var brush = function brush() {  
  •             var baseCtx = baseLayer.canvas.getContext('2d');  
  •             if (!baseCtx) {  
  •                 return;  
  •             }  
  •   
  •             addMarkLine();  
  •   
  •             baseCtx.clearRect(0, 0, width, height);  
  •   
  •             markLines.forEach(function (line) {  
  •                 line.drawMarker(baseCtx);  
  •                 line.drawLinePath(baseCtx);  
  •             });  
  •         };  
  •   
  •         //上层canvas渲染,动画效果  
  •         var render = function render() {  
  •             var animationCtx = animationLayer.canvas.getContext('2d');  
  •             if (!animationCtx) {  
  •                 return;  
  •             }  
  •   
  •             if (!animationFlag) {  
  •                 animationCtx.clearRect(0, 0, width, height);  
  •                 return;  
  •             }  
  •   
  •             animationCtx.fillStyle = 'rgba(0,0,0,.93)';  
  •             var prev = animationCtx.globalCompositeOperation;  
  •             animationCtx.globalCompositeOperation = 'destination-in';  
  •             animationCtx.fillRect(0, 0, width, height);  
  •             animationCtx.globalCompositeOperation = prev;  
  •   
  •             for (var i = 0; i < markLines.length; i++) {  
  •                 var markLine = markLines[i];  
  •                 markLine.drawMoveCircle(animationCtx); //移动圆点  
  •             }  
  •         };  
  •         var addMarkLine = function addMarkLine() {  
  •             markLines = [];  
  •             var dataset = options.data;  
  •             dataset.forEach(function (line, i) {  
  •                 markLines.push(new MarkLine({  
  •                     id: i,  
  •                     from: new Marker({  
  •                         city: line.from.city,  
  •                         location: [line.from.lnglat[0], line.from.lnglat[1]],  
  •                         color: options.colors[i]  
  •                     }),  
  •                     to: new Marker({  
  •                         city: line.to.city,  
  •                         location: [line.to.lnglat[0], line.to.lnglat[1]],  
  •                         color: options.colors[i]  
  •                     })  
  •                 }));  
  •             });  
  •         };  
  •   
  •         //初始化  
  •         var init = function init(map, options) {  
  •             merge(userOptions, options);  
  •   
  •             baseLayer = new CanvasLayer({  
  •                 map: map,  
  •                 update: brush  
  •             });  
  •   
  •             animationLayer = new CanvasLayer({  
  •                 map: map,  
  •                 update: render  
  •             });  
  •   
  •             (function drawFrame() {  
  •                 requestAnimationFrame(drawFrame);  
  •                 render();  
  •             })();  
  •         };  
  •   
  •         init(map, options);  
  •   
  •         self.options = options;  
  •     };  
  •   
  •     MoveLine.prototype.update = function (resetOpts) {  
  •         for (var key in resetOpts) {  
  •             this.options[key] = resetOpts[key];  
  •         }  
  •     };  
  •   
  •     return MoveLine;  
  •   
  • })));  
  •  

    2、前段调用

    a、数据格式

     

    [javascript] view plain copy

  • {  
  •                     from: {  
  •                         city: '广州',  
  •                         lnglat: [113.270793, 23.135308]  
  •                     },  
  •                     to: {  
  •                         city: '衡山',  
  •                         lnglat: [112.612787, 27.317599]  
  •                     }  
  •                 }  

  • b、前段调用

     

    [javascript] view plain copy

  • new MoveLine(map, {  
  •                     //marker点半径  
  •                     markerRadius: 2,  
  •                     //marker点颜色,为空或null则默认取线条颜色  
  •                     markerColor: null,  
  •                     //线条类型 solid、dashed、dotted  
  •                     lineType: 'solid',  
  •                     //线条宽度  
  •                     lineWidth: 2,  
  •                     //线条颜色  
  •                     colors: ['#F9815C', '#F8AB60', '#EDCC72', '#E2F194', '#94E08A', '#4ECDA5'],  
  •                     //移动点半径  
  •                     moveRadius: 3,  
  •                     //移动点颜色  
  •                     fillColor: '#fff',  
  •                     //移动点阴影颜色  
  •                     shadowColor: '#fff',  
  •                     //移动点阴影大小  
  •                     shadowBlur: 6,  
  •                     data: data  
  •                 });  
  •  

    ------------------------------------------------------------------------------https://blog.csdn.net/GISShiXiSheng/article/details/78148576?locationNum=11&fps=1

    转载于:https://my.oschina.net/u/1464512/blog/1801155

    总结

    以上是生活随笔为你收集整理的Openlayers4中实现动态线效果的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。