import { FrameAnimation } from '@/model/FrameAnimation'; import calculate from '@/utils/map/calculate'; import Layer from '@/utils/map/3dLayer'; import sector from '@/utils/map/sector'; import { map } from '@/utils/map/index_old'; import util from '@/utils/map/util'; import car_driving from '@/assets/mipmap/car_driving.png'; import boat_driving from '@/assets/mipmap/boat_driving.png'; function MapAnimation() { // 非连续坐标点最大距离(米) this.maxD = 500; // 当前绘制的监测因子类型 this.factorType; this.factorDatas; // 载具类型 this.vehicleType = 0; // 0: 车辆;1:无人机:2:无人船 // 帧动画控制工具 this.frameAnimation = new FrameAnimation(); // 动画帧数 this._fps = this.frameAnimation.fps; // 绘制图形缓存 this.moveViews = {}; this.clear = true; } MapAnimation.prototype = { setFactorType: function (factorType) { this.factorType = factorType; }, /** * 设置载具类型,对应显示不同的图标 */ setVehicleType: function (t) { this.vehicleType = t; this.moveViews = {}; }, /** * 车辆移动动画 * @param {*} factorDatas * @param {*} factorType */ moveAnimation: function (factorDatas, factorType, startIndex) { // MapUtil.drawLine(factorDatas.lnglats_GD) // 设置当前数据的最新时间 this.frameAnimation.lastestTime = factorDatas.times[factorDatas.times.length - 1]; // 当数据缓存不为空时,说明上一次的绘制还未结束,所以只更新数据源即可 if (this.factorDatas != undefined) { this.factorType = factorType; this.factorDatas = factorDatas; return; } this.factorType = factorType; this.factorDatas = factorDatas; this.startIndex = startIndex == undefined ? 0 : startIndex; // 一次性最多计算[this.frameAnimation.maxTasks]个坐标点的绘制轨迹,绘制完成后再次计算,提升前端网页响应速度 this.endIndex = this.startIndex + this.frameAnimation.maxTasks; if (this.endIndex >= factorDatas.length()) { this.endIndex = factorDatas.length() - 1; } // console.log(new Date()); this.nextAnimation(this.startIndex, factorDatas, this.endIndex); // console.log(new Date()); }, nextAnimation: function (start, factorDatas, endIndex) { if (factorDatas == undefined) { return; } var that = this; // 数据格式转换 for (let i = start; i < factorDatas.length(); i++) { // 终点 if (i == endIndex || i == factorDatas.length() - 1) { break; } // 动画轨迹(已绘制部分) var animationData = factorDatas.getByIndex(0, i + 1); // 路径点 var sPos = factorDatas.lnglats_GD[i]; var ePos = factorDatas.lnglats_GD[i + 1]; // 终点相对起点的角度 var angle = this._getAngle(sPos, ePos); // 路径总长度 // eslint-disable-next-line no-undef var distance = AMap.GeometryUtil.distance(sPos, ePos); // 时间差 var d1 = new Date(factorDatas.times[i]); var d2 = new Date(factorDatas.times[i + 1]); var duration = (d2 - d1) / 1000; // 总帧数 var count = duration * this._fps; // 单帧距离 var d = distance / count; // 每个fps对应的实际时长(默认1秒) var t = 1; // 两点间不连续时,使用默认时长,避免 if (distance > this.maxD) { count = this.frameAnimation.taskPeriod * this._fps; d = distance / count; t = duration / (count / this._fps); } // 监测数据(待绘制数据点,在已绘制部分和该数据点之间,插入动画帧数据点) // var fData1 = factorDatas.getByIndex(i, i + 1) var fData2 = factorDatas.getByIndex(i + 1, i + 2); // 计算动画轨迹 for (let i = 0; i < count; i++) { // path var length = d * (i + 1); if (isNaN(angle)) { animationData.lnglats_GD.push(sPos); } else { var point = this._getLatLon(sPos, length, angle); animationData.lnglats_GD.push(point); } // time var time = d1.format('yyyy-MM-dd hh:mm:ss'); if ((i + 1) % this._fps == 0) { var t1 = d1.getTime(); d1.setTime(t1 + t * 1000); time = d1.format('yyyy-MM-dd hh:mm:ss'); } animationData.times.push(time); } // 给每个监测因子进行插帧 for (const key in animationData.factor) { var factor = animationData.factor[key]; factor.insertFrame(fData2.factor[key], count, distance <= this.maxD); } animationData.refreshHeight(); var coor_GD = calculate.lngLatToGeodeticCoord(animationData.lnglats_GD); animationData.coors_GD = coor_GD; this.frameAnimation.addTask( count, animationData, function (data, index, count) { var length = data.length(); var start = length - count; // 1.获取数据 var d = data.getByIndex(0, start + index + 1); var f = d.factor[that.factorType]; // 2.绘制图形 if (length > count || index > 0) { // 3d图形 Layer.drawMesh(d, f); // 风向风速 sector.drawSectorAna(d, start + index); // 执行监听函数 if (typeof that.OnEachFrameCallback === 'function') { that.OnEachFrameCallback(d, start + index); } // 绘制3D图形时,最少需要2个点才可绘制图形 // 因此此处索引只到倒数第二个点就结束,此时执行这段任务结束的监听回调 if (typeof that.OnEachTaskEndCallback === 'function') { that.OnEachTaskEndCallback(d); } } var pos = d.lnglats_GD[d.lnglats_GD.length - 1]; var time = d.times[d.times.length - 1].slice(10); // 绘制车辆图标和时间文本 var status = 0; // 停止 if (index + 1 == count) { status = 1; } // 行驶中 else { status = 2; } that._setPosition(pos, time, status); // console.log("animation"); } ); } // 当endIndex已经是最后一个坐标点时,路径绘制结束,否则开始下一段路径绘制 if (that.endIndex < that.factorDatas.length() - 1) { that.startIndex = that.endIndex; that.endIndex = that.startIndex + that.frameAnimation.maxTasks; if (that.endIndex >= that.factorDatas.length) { that.endIndex = that.factorDatas.length - 1; } var cb = function () { that.nextAnimation(that.startIndex, that.factorDatas, that.endIndex); }; that.frameAnimation.addOnNextTasks(cb); } // 当全部数据绘制完成时,清空数据 else { that.factorDatas = undefined; that.frameAnimation.addOnNextTasks(undefined); } this.start(); }, /** * 设置每一帧的监听函数 * @param {Function} callback */ setOnEachFrameCallback(callback) { this.OnEachFrameCallback = callback; }, /** * 设置每一段任务结束的监听函数 * @param {Function} callback */ setOnEachTaskEndCallback(callback) { this.OnEachTaskEndCallback = callback; }, /*******************************动画任务逻辑 -start ******************************/ start: function () { if (this.frameAnimation.isStop) { sector.clearSector(); } this.frameAnimation.start(); }, changeSpeed: function (speed) { this.frameAnimation.changeSpeed(speed); }, pause: function () { this.frameAnimation.pause(); }, stop: function () { this.factorDatas = undefined; this.frameAnimation.addOnNextTasks(undefined); // this.OnEachFrameCallback = undefined; // this.OnEachTaskEndCallback = undefined; this.frameAnimation.stop(); this._clearMap(); }, setOnStopCallback: function (callback) { this.frameAnimation.setOnStopCallback( function () { callback(); }.bind(this) ); }, runStatus: function () { return this.frameAnimation.runStatus(); }, /** * 设置是否开启动态绘制速度 */ setDynamicSpeed: function (b, sec) { if (b) { this.frameAnimation.dynamicSpeed = true; this.frameAnimation.taskPeriod = sec; } else { this.frameAnimation.dynamicSpeed = false; this.frameAnimation.taskPeriod = sec; } }, /*******************************动画任务逻辑 -end ******************************/ _clearMap: function () { if (!this.clear) return; var list = []; for (const key in this.moveViews) { list.push(this.moveViews[key]); } map.remove(list); this.moveViews = {}; sector.clearSector(); }, _setPosition: function (pos, time, status) { // eslint-disable-next-line no-undef var lnglat = new AMap.LngLat(...pos); if (this.moveViews['text'] == undefined) { var url; switch (this.vehicleType) { case 0: url = car_driving; break; case 1: url = car_driving; break; case 2: url = boat_driving; break; default: url = car_driving; break; } // var url = "./asset/mipmap/car_offline.png"; // switch (status) { // case 0: // url = "./asset/mipmap/car_offline.png"; // break; // case 1: // url = "./asset/mipmap/car_stop.png"; // break; // case 2: // url = "./asset/mipmap/car_driving.png"; // break; // default: // url = "./asset/mipmap/car_stop.png"; // break; // } // eslint-disable-next-line no-undef var icon = new AMap.Icon({ // eslint-disable-next-line no-undef size: new AMap.Size(60, 30), // eslint-disable-next-line no-undef imageSize: new AMap.Size(54, 21), image: url // imageOffset: new AMap.Pixel(-16, -16) // 相对于基点的偏移位置 }); // eslint-disable-next-line no-undef var car = new AMap.Marker({ icon: icon, position: lnglat, // 基点位置 // eslint-disable-next-line no-undef offset: new AMap.Pixel(-20, -15) // 相对于基点的偏移位置 }); map.add(car); this.moveViews['car'] = car; // 时间 // eslint-disable-next-line no-undef var text = new AMap.Text({ text: time, position: lnglat, // eslint-disable-next-line no-undef offset: new AMap.Pixel(5, 20), style: { 'font-size': '13px', 'text-align': 'center', color: 'black', 'background-color': 'white', // 'text-shadow': 'black 2px 2px 2px', 'border-radius': '2px', border: '0px', padding: '0 4px' } }); map.add(text); this.moveViews['text'] = text; } else { util.setCenter(lnglat); this.moveViews['car'].setPosition(lnglat); this.moveViews['text'].setPosition(lnglat); this.moveViews['text'].setText(time); } }, _setStatus: function (status) {}, /** * 根据坐标点、距离和角度,得到另一个坐标点 * @param {*} pos * @param {*} distance 米 * @param {*} angle */ _getLatLon: function (pos, distance, angle) { var Ea = 6378137; // 赤道半径 var Eb = 6356725; // 极半径 var dx = distance * Math.sin((angle * Math.PI) / 180); var dy = distance * Math.cos((angle * Math.PI) / 180); var ec = Eb + ((Ea - Eb) * (90.0 - pos[1])) / 90.0; var ed = ec * Math.cos((pos[1] * Math.PI) / 180); var lng = ((dx / ed + (pos[0] * Math.PI) / 180.0) * 180.0) / Math.PI; var lat = ((dy / ec + (pos[1] * Math.PI) / 180.0) * 180.0) / Math.PI; return [lng, lat]; }, /** * 根据两个坐标点获得相对角度 * @param {*} sPos * @param {*} ePos */ _getAngle: function (sPos, ePos) { var lng_a = sPos[0]; var lat_a = sPos[1]; var lng_b = ePos[0]; var lat_b = ePos[1]; var a = ((90 - lat_b) * Math.PI) / 180; var b = ((90 - lat_a) * Math.PI) / 180; var AOC_BOC = ((lng_b - lng_a) * Math.PI) / 180; var cosc = Math.cos(a) * Math.cos(b) + Math.sin(a) * Math.sin(b) * Math.cos(AOC_BOC); var sinc = Math.sqrt(1 - cosc * cosc); var sinA = (Math.sin(a) * Math.sin(AOC_BOC)) / sinc; var A = (Math.asin(sinA) * 180) / Math.PI; var res = 0; if (lng_b > lng_a && lat_b > lat_a) res = A; else if (lng_b > lng_a && lat_b < lat_a) res = 180 - A; else if (lng_b < lng_a && lat_b < lat_a) res = 180 - A; else if (lng_b < lng_a && lat_b > lat_a) res = 360 + A; else if (lng_b > lng_a && lat_b == lat_a) res = 90; else if (lng_b < lng_a && lat_b == lat_a) res = 270; else if (lng_b == lng_a && lat_b > lat_a) res = 0; else if (lng_b == lng_a && lat_b < lat_a) res = 180; return res; } }; const realTimeMapAnimation = new MapAnimation(); // 开启动态绘制速度 realTimeMapAnimation.setDynamicSpeed(true, 4); // realTimeMapAnimation.clear = false; export { realTimeMapAnimation, MapAnimation };