您的位置 首页 > 腾讯云社区

mapboxGL中雷电动画展示---lzugis

概述

在网站ventusky中,点开降雨量图层,你会发现在降雨上面会有一些闪烁的点(小级别)或者闪烁的线(大级别),这些点或者线按照我的分析应该是根据降水相态(取雷阵雨)或者闪电数据叠加而成的,算是一个比较不错的亮点,本文参考此效果,结合github上的代码,在mapbox GL中进行了业务封装实现类似的效果。

效果

说明: 因为数据是随机造的,所以效果上不如实际数据那么好;

实现1、雷电数据

一般的雷电数据都是散点数据,会包含:经纬度、强度等信息,本文在做测试数据的时候只用了经纬度,数据格式如下:

var data = [ [112.08111460679623, 20.81427375298513], [112.71805970936151, 20.09658100108571], [113.9003630369973, 19.673781290716917], [114.10018895152848, 21.004828899791406], [115.36575307688554, 21.605996657108136], [116.46479560680149, 22.01182925045798], [116.34406745010693, 19.75608056730792] ];2、工具封装class Lightning { constructor(c) { this.config = c; } Cast(context, from, to, map) { if (!from || !to) { return; } //Main vector var v = new Vector(from.X1, from.Y1, to.X1, to.Y1); //skip cas if not close enough if (this.config.Threshold && v.Length() > context.canvas.width * this.config.Threshold) { return; } var vLen = v.Length(); var refv = from; var lR = (vLen / context.canvas.width) //count of segemnets var segments = Math.floor(this.config.Segments * lR); //lenth of each var l = vLen / segments; var zoom = map.getZoom(); if(zoom > 6) { for (let i = 1; i <= segments; i++) { //position in the main vector var dv = v.Multiply((1 / segments) * i); //add position noise if (i != segments) { dv.Y1 += l * Math.random(); dv.X1 += l * Math.random(); } //new vector for segment var r = new Vector(refv.X1, refv.Y1, dv.X1, dv.Y1); //background blur this.Line(context, r, { Color: this.config.GlowColor, With: this.config.GlowWidth * lR, Blur: this.config.GlowBlur * lR, BlurColor: this.config.GlowColor, Alpha: this.Random(this.config.GlowAlpha, this.config.GlowAlpha * 2) / 100 }); //main line this.Line(context, r, { Color: this.config.Color, With: this.config.Width, Blur: this.config.Blur, BlurColor: this.config.BlurColor, Alpha: this.config.Alpha }); refv = r; } } else { this.Circle(context, to, lR); } } Line(context, v, c) { context.beginPath(); context.strokeStyle = c.Color; context.lineWidth = c.With; context.moveTo(v.X, v.Y); context.lineTo(v.X1, v.Y1); context.globalAlpha = c.Alpha; context.shadowBlur = c.Blur; context.shadowColor = c.BlurColor; context.stroke(); } Circle(context, p, lR) { context.beginPath(); context.arc(p.X1 + Math.random() * 10 * lR, p.Y1 + Math.random() * 10 * lR, 5, 0, 2 * Math.PI, false); context.fillStyle = 'white'; context.shadowBlur = 100; context.shadowColor = "#2319FF"; context.fill(); } Random(min, max) { return Math.floor(Math.random() * (max - min)) + min; } } class Vector { constructor(x, y, x1, y1) { this.X = x; this.Y = y; this.X1 = x1; this.Y1 = y1; } dX() { return this.X1 - this.X; } dY() { return this.Y1 - this.Y; } Normalized() { var l = this.Length(); return new Vector(this.X, this.Y, this.X + (this.dX() / l), this.Y + (this.dY() / l)); } Length() { return Math.sqrt(Math.pow(this.dX(), 2) + Math.pow(this.dY(), 2)); } Multiply(n) { return new Vector(this.X, this.Y, this.X + this.dX() * n, this.Y + this.dY() * n); } Clone() { return new Vector(this.x, this.y, this.X1, this.Y1); } } var LightnMap = { _map: null, _data: [], _canvas: null, _context: null, _options: { Alpha: "0.5", Blur: "5", BlurColor: "white", Color: "white", GlowAlpha: "30", GlowBlur: "10", GlowColor: "#000055", GlowWidth: "40", Segments: "600", Threshold: "0.5", Width: "2" }, _lts: [], _animation: null, _timer: 0, init: function(map, data) { const self = this; self._map = map; self._data = data; let canvas = document.createElement('canvas'); canvas.id = 'lightCanvas'; canvas.width = map.getCanvas().width; canvas.height = map.getCanvas().height; canvas.style.position = 'absolute'; canvas.style.top = 0; canvas.style.left = 0; map.getCanvasContainer().appendChild(canvas); self._context = canvas.getContext("2d"); self._canvas = canvas; self._clearAndRestart(); map.on("dragstart", function() { self._clear(); }); map.on("dragend", function() { self._clearAndRestart(); }); map.on("zoomstart", function() { self._clear(); }); map.on("zoomend", function() { self._clearAndRestart(); }); map.on("resize", function() { self._clear(); }); }, _getPoints: function(x, y, size) { var self = this; points = []; var num = self._randomNum(1, 4); for (var i = 0; i < num; i++) { points.push(new Vector( x + self._randomNum(-size, size), y + self._randomNum(-size, size), x + self._randomNum(-size, size), y + self._randomNum(-size, size))); } return points; }, _clearAndRestart: function() { var self = this; self._clear(); // 初始化雷电数据 self._lts = []; for (var i = 0; i < self._data.length; i++) { var d = self._data[i]; var xy = self._map.project(d); var x = xy.x + self._randomNum(-50, 50); var y = xy.y + self._randomNum(-50, 50); var size = self._randomNum(20, 50); var lt = { lt: new Lightning(self._options), x: x, y: y, size: size }; self._lts.push(lt); } self._animation = window.requestAnimationFrame(function() { self._Animate(); }); }, _Animate() { var self = this; self._clear(); for (var i = 0; i < self._data.length; i++) { var lt = self._lts[i]; var x = lt.x; var y = lt.y; var size = lt.size; var points = self._getPoints(x, y, size); var target = new Vector( x - size, y - size, x + self._randomNum(-10, 10), y + self._randomNum(-10, 10) ); points.forEach(p => { lt.lt.Cast(self._context, p, target, self._map); }); } if (self._timer) clearTimeout(self._timer); self._timer = setTimeout(() => { self._Animate(); }, 100); }, _randomNum(minNum, maxNum) { switch (arguments.length) { case 1: return parseInt(Math.random() * minNum + 1, 10); break; case 2: return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10); break; default: return 0; break; } }, _clear: function() { const self = this; self._context.clearRect(0, 0, self._canvas.width, self._canvas.height); if (self._animation) cancelAnimationFrame(self._animation); if (self._timer) clearTimeout(self._timer); }, destory: function() { this._canvas.parentNode.removeChild(this._canvas); } }3、调用实现LightnMap.init(map, data); ---来自腾讯云社区的---lzugis

关于作者: 瞎采新闻

这里可以显示个人介绍!这里可以显示个人介绍!

热门文章

留言与评论(共有 0 条评论)
   
验证码: