本篇的重点内容是利用openlayers实现台风轨迹功能,效果图如下:
台风轨迹效果图:
实现思路
- 界面设计
//台风 "<div style='height:25px;background:#30A4D5;margin-top:10px;width: 98%;margin-left: 3px;float: left;'>" + "<span style='margin-left:5px;font-size: 13px;color:white;'>台风</span>" + "</div>" + '<div id="typhoonLayer" style="padding:5px;float: left;">' + '<input type="checkbox" name="typhoonlayer" style="width: 15px;height: 15px;vertical-align: middle;margin: auto;"/>' + '<label style="font-weight: normal;vertical-align: middle;margin: auto;">台风</label>' + '</div>'
- 点击事件
//台风 $("#typhoonLayer input").bind("click", function () { if (this.checked) { listDialog = new bxmap.TyphoonListDialog(); listDialog.setTyphoonMap(bmap); listDialog.show(); var map = bmap.getMap(); map.getView().setCenter([13286590.004642466, 2562780.6843453925]); map.getView().setZoom(6); //图例面板显示 $("#map_tl").css("display","block"); $("#map_tl>img").attr('src', GLOBAL.domainResource+"/Content/img/typhoonLegend.png"); $("#map_tl>img").css("width","auto"); $("#map_tl>img").css("height","350px"); } else { if(listDialog){ listDialog.close(); } //图例面板隐藏 $("#map_tl").hide(); } })
- 台风轨迹初始化
/** * @description 初始化图层 * @param bmap * @private */ bxmap.Typhoon.prototype._initializeLayers = function () { //24小时48小时警戒线 this.picketLineLayer = new bxmap.layer.Vector({ source: new ol.source.Vector() }); //台风实际路线节点 this.realNodesLayer = new bxmap.layer.Vector({ source: new ol.source.Vector(), property: "symbol", style: null, context: function (feature) { return feature["symbol"]; } }); var symbolizer = new bxmap.symbol.UniqueValueSymbolizer(); var styles = this.styles; symbolizer.addRule({ruleName: "default", styles: styles["TyphoonNodes_Unselected"]}); symbolizer.addRule({ruleName: "selected", styles: styles["TyphoonNodes_Selected"]}); symbolizer.addRule({ruleName: "unselected", styles: styles["TyphoonNodes_Unselected"]}); this.realNodesLayer.setSymbolizer(symbolizer); //台风预测路线节点 this.forecastNodesLayer = new bxmap.layer.Vector({ source: new ol.source.Vector(), property: "symbol", style: null, context: function (feature) { return feature["symbol"]; } }); symbolizer = new bxmap.symbol.UniqueValueSymbolizer(); symbolizer.addRule({ruleName: "default", styles: styles["TyphoonNodes_Unselected"]}); symbolizer.addRule({ruleName: "selected", styles: styles["TyphoonNodes_Selected"]}); symbolizer.addRule({ruleName: "unselected", styles: styles["TyphoonNodes_Unselected"]}); this.forecastNodesLayer.setSymbolizer(symbolizer); //其他数据 this.resourceLayer = new bxmap.layer.Vector({ source: new ol.source.Vector() }); }
- 台风轨迹样式设置代码
/** * @description 创建样式 * @return {JSON} */ bxmap.Typhoon.prototype.createStyles = function () { var output = {}; //台风节点 output["TyphoonNodes_Unselected"] = { "热带低压": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngRddy}) }) ,"热带风暴": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngRdfb}) }) ,"强热带风暴": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngQrdfb}) }) ,"台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngTf}) }) ,"强台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngQtf}) }) ,"超强台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 0.8, scale: 0.8, src: bxmap.Resource.TyphoonPngCqtf}) }) }; output["TyphoonNodes_Selected"] = { "热带低压": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngRddy}) }) ,"热带风暴": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngRdfb}) }) ,"强热带风暴": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngQrdfb}) }) ,"台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngTf}) }) ,"强台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngQtf}) }) ,"超强台风": new ol.style.Style({ image: new ol.style.Icon({opacity: 1, scale: 1, src: bxmap.Resource.TyphoonPngCqtf}) }) }; return output; }
- 绘制默认警戒线
/** * @description 绘制默认警戒线 */ bxmap.Typhoon.prototype.drawDefaultPicketLine = function () { //警戒线数据 var picketLine24 = ''; var picketLine48 = ''; if(this.isProjected){ picketLine24 = 'LINESTRING(14137575.3307 4028802.0261, 14137575.3307 2391878.5879, 12245143.9873 1689200.1396)'; picketLine48 = 'LINESTRING(14694172.7847 4028802.0261, 14694172.7847 1689200.1396, 11688546.5333 0)'; }else { picketLine24 = 'LINESTRING(127 34, 127 21, 110 15)'; picketLine48 = 'LINESTRING(132 34, 132 15, 105 0)'; } var WKTReader = new ol.format.WKT(); var feature24 = WKTReader.readFeature(picketLine24); var feature48 = WKTReader.readFeature(picketLine48); feature24.setStyle(new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#ff0000', width: 1 }) })); feature48.setStyle(new ol.style.Style({ stroke: new ol.style.Stroke({ color: '#ffff99', width: 1 }) })); this.picketLineLayer.getSource().addFeatures([feature24, feature48]); }
- 设置风圈
/** * @description 设置风圈 * @param node - {JSON} 格式{"WD":"20.9","JD":"116.2","EN7Radii":"220","ES7Radii":"220","WS7Radii":"260","WN7Radii":"240","EN10Radii":"50","ES10Radii":"80","WS10Radii":"80","WN10Radii":"50"} */ bxmap.Typhoon.prototype.setWindCircle = function (node) { if(node == null) return; var n = node; var center = [n.X,n.Y]; //台风位置 this._typhoonFeature.setGeometry(new ol.geom.Point([Number(center[0]),Number(center[1])])); //7级风圈 if(n.EN7Radii){ var path = this.getSectorPoints(center, n.EN7Radii,0,90,30); this._windEN7.setGeometry(new ol.geom.Polygon([path])); }else{ this._windEN7.setGeometry(null); } if(n.ES7Radii){ var path = this.getSectorPoints(center, n.ES7Radii,90,180,30); this._windES7.setGeometry(new ol.geom.Polygon([path])); }else{ this._windES7.setGeometry(null); } if(n.WS7Radii){ var path = this.getSectorPoints(center, n.WS7Radii,180,270,30); this._windWS7.setGeometry(new ol.geom.Polygon([path])); }else{ this._windWS7.setGeometry(null); } if(n.WN7Radii){ var path = this.getSectorPoints(center, n.WN7Radii,270,360,30); this._windWN7.setGeometry(new ol.geom.Polygon([path])); }else{ this._windWN7.setGeometry(null); } //10级风圈 if(n.EN10Radii){ var path = this.getSectorPoints(center, n.EN10Radii,0,90,30); this._windEN10.setGeometry(new ol.geom.Polygon([path])); }else{ this._windEN10.setGeometry(null); } if(n.ES10Radii){ var path = this.getSectorPoints(center, n.ES10Radii,90,180,30); this._windES10.setGeometry(new ol.geom.Polygon([path])); }else{ this._windES10.setGeometry(null); } if(n.WS10Radii){ var path = this.getSectorPoints(center, n.WS10Radii,180,270,30); this._windWS10.setGeometry(new ol.geom.Polygon([path])); }else{ this._windWS10.setGeometry(null); } if(n.WN10Radii){ var path = this.getSectorPoints(center, n.WN10Radii,270,360,30); this._windWN10.setGeometry(new ol.geom.Polygon([path])); }else{ this._windWN10.setGeometry(null); } }
/** * @description 逆时针计算扇形风圈的点集合 * @param center - {Array<String|Number>}中心点,例如[117.23,23.123] * @param radius - {String|Number} 半径km * @param startAngle - {String|Number} 起始角度(单位°) * @param endAngle - {String|Number} 结束角度(单位°) * @param pointNum - {String|Number} 返回构成的弧点个数,默认30 * @return {Array} */ bxmap.Typhoon.prototype.getSectorPoints = function(center,radius,startAngle,endAngle,pointNum) { radius = Number(radius) * 1000; if(!this.isProjected){ var MetersPerUnit = 111319.49079327358; //1度多少米 radius = radius/MetersPerUnit;//转化为度 } center = [Number(center[0]),Number(center[1])]; startAngle = Number(startAngle); endAngle = Number(endAngle); pointNum = Number(pointNum || 30); var sin; var cos; var x; var y; var angle; var points = new Array(); var pointsLL = new Array(); var lonlat = center; points.push([center[0], center[1]]); for (var 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[i + 1] = [x, y]; } points.push([center[0], center[1]]); for (var j = 0; j < points.length; j++) { pointsLL[j] = points[j]; } return pointsLL; }