/** * 单个台风对象 * @class Typhoon */ class Typhoon { //========== 构造方法 ========== constructor(options, map) { this.options = options; this.map = map; //创建台风相关矢量图层 this.typhoonLayer = new mars3d.layer.GraphicLayer(); map.addLayer(this.typhoonLayer); this.clickPtLayer = new mars3d.layer.GraphicLayer(); map.addLayer(this.clickPtLayer); this.showTyphoonToMap(options.path); } //========== 对外属性 ========== //显示隐藏 get show() { return this.options.show; } set show(val) { this.options.show = val; this.typhoonLayer.show = val; this.clickPtLayer.show = val; } getPointById(id) { return this.typhoonLayer.getGraphicById(id); } flyTo(options) { this.typhoonLayer.flyTo(options); } getPointTooltip(event, isYB) { let item = event.graphic?.attr; if (!item) { return; } let ybHtml = ""; if (isYB) { ybHtml = `

预报机构:  中央气象台

`; } let fqHtml = ''; if (item.circle7) { fqHtml += ` `; if (item.circle10) { fqHtml += ` `; if (item.circle12) { fqHtml += ``; } } } fqHtml += "
风圈半径 东北 东南 西南 西北
七级 ${item.circle7.radius1} ${item.circle7.radius2} ${item.circle7.radius3} ${item.circle7.radius4} (KM)
十级 ${item.circle10.radius1} ${item.circle10.radius2} ${item.circle10.radius3} ${item.circle10.radius4} (KM)
十二级 ${item.circle12.radius1} ${item.circle12.radius2} ${item.circle12.radius3} ${item.circle12.radius4} (KM)
"; return `

${this.options.typnumber} ${this.options.name_cn}

${ybHtml}

过去时间:  ${item.time_str}

中心位置:  ${item.lat}N/${item.lon}E

最大风速:  ${item.centerSpeed}米/秒

中心气压:  ${item.strength}百帕

移动方向:  ${item.moveTo_str}

移动速度:  ${item.windSpeed}公里/小时

${fqHtml}
`; } addNameGraphic(firstItem) { //[起点]绘制台风起点名字 var nameGraphic = new mars3d.graphic.RectanglePrimitive({ positions: [ [firstItem.lon, firstItem.lat], [firstItem.lon + 0.7, firstItem.lat - 0.4], ], style: { material: mars3d.MaterialUtil.createMaterial(mars3d.MaterialType.Text, { text: this.options.name_cn, font_size: 60, fillColor: "red", }), zIndex: 2, }, attr: firstItem, }); this.typhoonLayer.addGraphic(nameGraphic); } //绘制一个台风到地图上 showTyphoonToMap(arr) { if (arr.length < 1) { return; } let firstItem = arr[0]; let endItem = arr[arr.length - 1]; let lastType; var arrPoint = []; //路径点 for (let i = 0, len = arr.length; i < len; i++) { let item = arr[i]; let point = [item.lon, item.lat]; //在图层上绘画出所有的点 let pointEntity = new mars3d.graphic.PointEntity({ id: item.id, position: point, style: { pixelSize: 6, color: item.color, }, attr: item, }); this.typhoonLayer.addGraphic(pointEntity); //轨迹点绑定点击事件 pointEntity.on(mars3d.EventType.click, (event) => { this.showPointFQ(event.graphic.attr); }); pointEntity.bindTooltip( (event) => { return this.getPointTooltip(event); }, { template: "", anchor: [260, -20], } ); arrPoint.push(point); //判断台风的typlevel if (lastType !== item.level || i == len - 1) { //绘制线 let graphicLine = new mars3d.graphic.PolylineEntity({ positions: arrPoint, style: { color: getColor(lastType), }, }); this.typhoonLayer.addGraphic(graphicLine); lastType = item.level; arrPoint = [point]; } } //[起点]绘制台风起点名字 this.addNameGraphic(firstItem); //[终点]绘制台风当前位置gif点 let gifGraphic = new mars3d.graphic.DivGraphic({ position: [endItem.lon, endItem.lat], style: { html: ``, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER, }, }); this.typhoonLayer.addGraphic(gifGraphic); this.gifGraphic = gifGraphic; //显示最后所在点的对应风圈等。 this.showPointFQ(endItem); } //点击事件,点击出现台风icon showPointFQ(item, availability) { if (!availability) { this.clickPtLayer.clear(); } let position = [item.lon, item.lat]; //台风实时位置gif点更新 if (this.gifGraphic) { this.gifGraphic.position = position; } // 绘制7级风圈面 if (item.circle7) { let points7 = []; points7 = points7.concat(getPoints(position, item.circle7.radius1, 0)); //东北方向 points7 = points7.concat(getPoints(position, item.circle7.radius2, 90)); //东南 points7 = points7.concat(getPoints(position, item.circle7.radius3, 180)); //西南 points7 = points7.concat(getPoints(position, item.circle7.radius4, 270)); //西北 let graphic = new mars3d.graphic.PolygonEntity({ positions: points7, availability: availability, style: { setHeight: 900, color: "#eed139", opacity: 0.3, outline: true, outlineWidth: 2, outlineColor: "#eed139", }, }); this.clickPtLayer.addGraphic(graphic); } //绘制10级风圈面 if (item.circle10) { let points10 = []; points10 = points10.concat(getPoints(position, item.circle10.radius1, 0)); //东北方向 points10 = points10.concat(getPoints(position, item.circle10.radius2, 90)); points10 = points10.concat(getPoints(position, item.circle10.radius3, 180)); points10 = points10.concat(getPoints(position, item.circle10.radius4, 270)); let tenGraphic = new mars3d.graphic.PolygonEntity({ positions: points10, availability: availability, style: { setHeight: 800, color: "#fe9c45", opacity: 0.3, outline: true, outlineWidth: 2, outlineColor: "#fe9c45", arcType: Cesium.ArcType.GEODESIC, }, }); this.clickPtLayer.addGraphic(tenGraphic); } //绘制12级风圈面 if (item.circle12) { let points12 = []; points12 = points12.concat(getPoints(position, item.circle12.radius1, 0)); //东北方向 points12 = points12.concat(getPoints(position, item.circle12.radius2, 90)); points12 = points12.concat(getPoints(position, item.circle12.radius3, 180)); points12 = points12.concat(getPoints(position, item.circle12.radius4, 270)); let tenGraphic = new mars3d.graphic.PolygonEntity({ positions: points12, availability: availability, style: { setHeight: 700, color: "#ffff00", opacity: 0.3, outline: true, outlineWidth: 2, outlineColor: "#ffff00", arcType: Cesium.ArcType.GEODESIC, }, }); this.clickPtLayer.addGraphic(tenGraphic); } //台风预测路径绘制 if (item.forecast) { let linePoint = [position]; item.forecast.forEach((element) => { let forecastPt = [element.lon, element.lat]; linePoint.push(forecastPt); //在图层上绘画出所有的点 let pointEntity = new mars3d.graphic.PointEntity({ position: forecastPt, availability: availability, style: { pixelSize: 6, color: element.color, //不同typlevel显示不同的颜色 opacity: 0.8, }, attr: item, }); this.clickPtLayer.addGraphic(pointEntity); pointEntity.bindTooltip( (event) => { return this.getPointTooltip(event, true); }, { template: "", anchor: [260, -20], } ); //预测路线 let graphicLine = new mars3d.graphic.PolylineEntity({ positions: linePoint, availability: availability, style: { material: mars3d.MaterialUtil.createMaterialProperty(mars3d.MaterialType.PolylineDash, { dashLength: 20.0, color: "red", }), }, }); this.clickPtLayer.addGraphic(graphicLine); }); } } //释放 destroy() { this.show = false; if (this.typhoonLayer) { this.typhoonLayer.destroy(); delete this.typhoonLayer; } if (this.clickPtLayer) { this.clickPtLayer.destroy(); delete this.clickPtLayer; } } } /** * 动态播放 单个台风对象 * @class PlayTyphoon */ class PlayTyphoon extends Typhoon { //========== 对外属性 ========== //显示隐藏 get isStart() { return this._isStart; } set isStart(val) { this._isStart = val; } //绘制一个台风对应的对象。 showTyphoonToMap(arr) { if (arr.length < 1) { return; } let firstItem = arr[0]; let endItem = arr[arr.length - 1]; this.startTime = Cesium.JulianDate.fromDate(firstItem.time); //开始时间 this.stopTime = Cesium.JulianDate.fromDate(endItem.time); //结束时间 let lastType = arr[0].level; let property = new Cesium.SampledPositionProperty(); for (let i = 0, len = arr.length; i < len; i++) { let item = arr[i]; let point = [item.lon, item.lat]; let position = Cesium.Cartesian3.fromDegrees(item.lon, item.lat); //经度、纬度坐标转化 let pointTime = Cesium.JulianDate.fromDate(item.time); //将时间转化成需要的格式 property.addSample(pointTime, position); //绘制点 let pointEntity = new mars3d.graphic.PointEntity({ id: item.id, position: point, availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: pointTime, stop: this.stopTime, }), ]), style: { pixelSize: 6, color: item.color, }, attr: item, }); pointEntity.bindTooltip( (event) => { return this.getPointTooltip(event); }, { template: "", anchor: [260, -20], } ); this.typhoonLayer.addGraphic(pointEntity); if (lastType !== item.level || i == len - 1) { //绘制线 let graphicLine = new mars3d.graphic.PathEntity({ position: property, style: { leadTime: 0, color: getColor(lastType), }, }); this.typhoonLayer.addGraphic(graphicLine); lastType = item.level; property = new Cesium.SampledPositionProperty(); //控制动画播放的对象 property.addSample(pointTime, position); } //显示每个点的风圈和预测路线 let lastTime; if (i == len - 1) { lastTime = this.lastTime; } else { lastTime = Cesium.JulianDate.fromDate(arr[i + 1].time); } let availability = new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: pointTime, stop: lastTime, }), ]); this.showPointFQ(item, availability); } //[起点]绘制台风起点名字 this.addNameGraphic(firstItem); } //开始播放 start() { this._isStart = true; this.map.clock.startTime = this.startTime.clone(); this.map.clock.stopTime = this.stopTime.clone(); this.map.clock.currentTime = this.startTime.clone(); this.map.clock.clockRange = Cesium.ClockRange.CLAMPED; //到达时间点后终止 this.map.clock.multiplier = 16000; if (this.map.viewer.timeline) { this.map.viewer.timeline.zoomTo(this.startTime, this.stopTime); } this.show = true; this.map.clock.shouldAnimate = true; } //停止播放 stop() { this._isStart = false; this.show = false; let now = Cesium.JulianDate.fromDate(new Date()); this.map.clock.startTime = now.clone(); this.map.clock.stopTime = Cesium.JulianDate.addDays(now, 1.0, new Cesium.JulianDate()); this.map.clock.currentTime = now.clone(); this.map.clock.clockRange = Cesium.ClockRange.UNBOUNDED; this.map.clock.multiplier = 1; } } //不同等级的台风对应不同的颜色 function getColor(level) { switch (level) { default: case "TD": //热带低压 return "rgb(238,209,57)"; case "TS": //热带风暴 return "rgb(0,0,255)"; case "STS": //强热带风暴 return "rgb(15,128,0)"; case "TY": //台风 return "rgb(254,156,69)"; case "STY": //强台风 return "rgb(254,0,254)"; case "SuperTY": //超强台风 return "rgb(254,0,0)"; } } // 根据经纬度 直径 以及方向计算方法 function getPoints(center, cradius, startAngle) { let points = []; let radius = cradius / 100; let pointNum = 90; let endAngle = startAngle + 90; let sin, cos, x, y, angle; for (let i = 0; i <= pointNum; i++) { angle = startAngle + ((endAngle - startAngle) * i) / pointNum; sin = Math.sin((angle * Math.PI) / 180); cos = Math.cos((angle * Math.PI) / 180); x = center[0] + radius * sin; y = center[1] + radius * cos; points.push([x, y]); } return points; }