空品測站正/反軌跡kml檔案產生系統
Table of contents
前言
或參自動版:臺灣地區高解析度軌跡產生/自動分析系統
五、traj 網頁計算服務網址:http://125.229.149.182/traj.html @iMacKuang1 畫面:
畫面左側的5個物件,主要是3個下拉選單(selectmenu)、一個日期選單(datepicker)、以及一個button submit物件做為整體提交並呼叫cgi_python(traj/surf_traj3.py)的觸發。右方則為一典型範例,說明模式計算能力(軌跡會繞山)。
選單都是jquery套件,其中測站較為複雜,是連動下拉選單,主要應用append方法,按照前一選擇結果,依序帶出後一選單的內容。
提供cgi_python的變數:dirFB(正/反軌跡的方向選擇)、AQSname(測站代碼)、date(日期)、number(小時),4項變數。
traj.html
11.5 KB
$ cat -n traj.html
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <title>TRAJ Selectmenu</title>
6 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
7 <link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
8 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
9 <link rel="stylesheet" href="/resources/demos/style.css">
10 <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/themes/smoothness/jquery-ui.css">
11 <style>
12 fieldset {
13 border: 0;
14 }
15 label {
16 display: block;
17 margin: 30px 0 0 0;
18 }
19 .overflow {
20 height: 200px;
21 }
22 </style>
23 <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
24 <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
25 <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
26 <script>
27 $( function() {
28 $( "#dirFB" ).selectmenu();
29 $( "#KPQname" )
30 .selectmenu( "menuWidget" )
31 .addClass( "overflow" );
32 $( "#CNTname" ).selectmenu();
33 $( "#AQSname" ).selectmenu();
34 $( "#number" )
35 .selectmenu()
36 .selectmenu( "menuWidget" )
37 .addClass( "overflow" );
38 $( "#emailadd" ).selectmenu();
39 } );
40 </script>
41 <style>
42 #SIDE {
43
44 width:900px; /* <div> 要設定寬度,才能配合 float 做水平靠左或靠右排列 */
45
46 float:right; /* 使用 float 讓這個 <div> 做水平靠左排列 */
47 }
48 </style>
49 </head>
50 <body>
51
52 <header class="subhead" id="overview">
53 <div class="container">
54 <h1>空品測站正/反軌跡kml檔案產生系統</h1>
55 <p class="lead">
56 選取正/反軌跡、環保署空氣品質測站、以及到達(起始)之時間,系統將在遠端工作站進行計算。
57 點選檔案下載到使用者電腦即可進行google map/OSM繪圖。(恕僅保留24小時)
58 </p>
59 <h6>
60 <p>觀測數據:中央氣象局逐時自動站(2016/1/1至昨日) </p>
61 <p>內插網格:臺灣本島範圍、解析度1公里 </p>
62 <p>軌跡點時間間距:15秒(曲線)、1小時(圓點) </p>
63 </h6>
64 </div>
65 </header>
66 <div id="SIDE"> <img src="chaozhou.PNG" width="600" height="400" > </div>
67 <div class="container">
68 <div class="col-md-4">
69 <form enctype="multipart/form-data" action="/cgi-bin/traj/surf_traj3.py" method="post">
70
71 <fieldset>
72 <label for="dirFB">正/反軌跡</label>
73 <select name="dirFB" id="dirFB">
74 <option value="btrj">反軌跡</option>
75 <option value="ftrj">正軌跡</option>
76 </select>
77
78 <label for="KPQname"> 空氣品質區及測站 </label>
79 <select name="KPQname" id="KPQname">
80 <option value="0">請選擇</option>
81 <option value="1">北部空品區</option>
82 <option value="2">竹苗空品區</option>
83 <option value="3">中部空品區</option>
84 <option value="4">雲嘉南空品區</option>
85 <option value="5">高屏空品區</option>
86 <option value="6">宜蘭花東</option>
87 <option value="7">離島</option>
88 </select>
89 <select name="CNTname" id="CNTname"></select>
90 <select name="AQSname" id="AQSname"></select>
91
92 <label for="date">到達(起始)日期(昨天以前) </label><p> <input type="text" name="date" id="dt1"></p>
93 <label for="number">到達(起始)時間 </label>
94 <select name="number" id="number">
95 <option value="01">1</option>
96 <option value="02">2</option>
97 <option value="03">3</option>
98 <option value="04">4</option>
99 <option value="05">5</option>
100 <option value="06">6</option>
101 <option value="07">7</option>
102 <option value="08">8</option>
103 <option value="09">9</option>
104 <option value="10">10</option>
105 <option value="11">11</option>
106 <option value="12" selected="selected">12</option>
107 <option value="13">13</option>
108 <option value="14">14</option>
109 <option value="15">15</option>
110 <option value="16">16</option>
111 <option value="17">17</option>
112 <option value="18">18</option>
113 <option value="19">19</option>
114 <option value="20">20</option>
115 <option value="21">21</option>
116 <option value="22">22</option>
117 <option value="23">23</option>
118 <option value="24">24</option>
119 </select>
120
121 </fieldset>
122 <p style="text-align:left;"> <input type="submit" value="OK and Run TRAJ remotely..." /></p>
123 <h6><p>Contact: Dr. Yungchuan Kuang, sinotec2@gmail.com</p></h6>
124 </form>
125
126 </div>
127 </div>
128
129 <script>
130 $("#KPQname").change(function(){
131 switch (parseInt($(this).val())){
132 default:
133 case 0:
134 $("#CNTname option").remove();
135 break;
136 case 1:
137 $("#CNTname option").remove();
138 var array = [ "請選擇", "基隆市", "台北市", "新北市", "桃園市" ];
139 var CNTva = [ "0", "1", "3", "2", "4" ];
140 $.each(array, function(i, val) {
141 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + array[i] + "</option>"));
142 });
143 break;
144 case 2:
145 $("#CNTname option").remove();
146 var CNTnm = [ "請選擇", "竹苗" ];
147 var CNTva = [ "0", "5", ];
148 $.each(CNTnm, function(i, val) {
149 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
150 });
151 break;
152 case 3:
153 $("#CNTname option").remove();
154 var CNTnm = [ "請選擇", "台中市", "彰化南投" ];
155 var CNTva = [ "0", "6", "7" ];
156 $.each(CNTnm, function(i, val) {
157 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
158 });
159 break;
160 case 4:
161 $("#CNTname option").remove();
162 var CNTnm = [ "請選擇", "雲林縣", "嘉義縣市", "台南市" ];
163 var CNTva = [ "0", "8", "9", "10" ];
164 $.each(CNTnm, function(i, val) {
165 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
166 });
167 break;
168 case 5:
169 $("#CNTname option").remove();
170 var CNTnm = [ "請選擇", "高雄市","(原高雄縣)", "屏東縣" ];
171 var CNTva = [ "0", "12", "11", "13"];
172 $.each(CNTnm, function(i, val) {
173 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
174 });
175 break;
176 case 6:
177 $("#CNTname option").remove();
178 var CNTnm = [ "請選擇", "宜蘭花東" ];
179 var CNTva = [ "0", "14" ];
180 $.each(CNTnm, function(i, val) {
181 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
182 });
183 break;
184 case 7:
185 $("#CNTname option").remove();
186 var CNTnm = [ "not available" ];
187 var CNTva = [ "0" ];
188 $.each(CNTnm, function(i, val) {
189 $("#CNTname").append($("<option value='" + CNTva[i] + "'>" + CNTnm[i] + "</option>"));
190 });
191 break;
192 }
193 });
194 </script>
195 <script>
196 $("#CNTname").change(function(){
197 switch (parseInt($(this).val())){
198 default:
199 case 0:
200 $("#AQSname option").remove();
201 break;
202 case 1:
203 $("#AQSname option").remove();
204 var AQSnm = [ "基隆" ];
205 var AQSva = [ "1" ];
206 $.each(AQSnm, function(i, val) {
207 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
208 });
209 break;
210 case 2:
211 $("#AQSname option").remove();
212 var array = [ "汐止","萬里","新店","土城","板橋","新莊","菜寮","林口","淡水","三重","永和" ];
213 var AQSva = [ "2","3","4","5","6","7","8","9","10","67","70" ];
214 $.each(array, function(i, val) {
215 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + array[i] + "</option>"));
216 });
217 break;
218 case 3:
219 $("#AQSname option").remove();
220 var AQSnm = [ "士林","中山","萬華","古亭","松山","大同","陽明" ];
221 var AQSva = [ "11","12","13","14","15","16","64" ];
222 $.each(AQSnm, function(i, val) {
223 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
224 });
225 break;
226 case 4:
227 $("#AQSname option").remove();
228 var AQSnm = [ "桃園","大園","觀音","平鎮","龍潭","中壢" ];
229 var AQSva = [ "17","18","19","20","21","68"];
230 $.each(AQSnm, function(i, val) {
231 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
232 });
233 break;
234 case 5:
235 $("#AQSname option").remove();
236 var AQSnm = [ "湖口","竹東","新竹","頭份","苗栗","三義" ];
237 var AQSva = [ "22", "23","24","25","26","27" ];
238 $.each(AQSnm, function(i, val) {
239 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
240 });
241 break;
242 case 6:
243 $("#AQSname option").remove();
244 var AQSnm = [ "豐原","沙鹿","大里","忠明","西屯" ];
245 var AQSva = ["28","29","30","31","32" ];
246 $.each(AQSnm, function(i, val) {
247 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
248 });
249 break;
250 case 7:
251 $("#AQSname option").remove();
252 var AQSnm = ["彰化","線西","二林","南投","竹山","埔里" ];
253 var AQSva = [ "33","34","35","36","69","72" ];
254 $.each(AQSnm, function(i, val) {
255 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
256 });
257 break;
258 case 8:
259 $("#AQSname option").remove();
260 var AQSnm = [ "斗六","崙背","台西","麥寮" ];
261 var AQSva = [ "37","38","41","83"];
262 $.each(AQSnm, function(i, val) {
263 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
264 });
265 break;
266 case 9:
267 $("#AQSname option").remove();
268 var AQSnm = [ "新港","朴子","嘉義" ];
269 var AQSva = [ "39","40","42" ];
270 $.each(AQSnm, function(i, val) {
271 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
272 });
273 break;
274 case 10:
275 $("#AQSname option").remove();
276 var AQSnm = ["新營","善化","安南","台南" ];
277 var AQSva = [ "43","44","45","46" ];
278 $.each(AQSnm, function(i, val) {
279 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
280 });
281 break;
282 case 11:
283 $("#AQSname option").remove();
284 var AQSnm = ["美濃","橋頭","仁武","鳳山","大寮","林園","楠梓" ];
285 var AQSva = ["47","48","49","50","51","52","53" ];
286 $.each(AQSnm, function(i, val) {
287 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
288 });
289 break;
290 case 12:
291 $("#AQSname option").remove();
292 var AQSnm = [ "左營","前金","前鎮","小港","復興" ];
293 var AQSva = [ "54","56","57","58","71" ];
294 $.each(AQSnm, function(i, val) {
295 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
296 });
297 break;
298 case 13:
299 $("#AQSname option").remove();
300 var AQSnm = [ "屏東","潮州","恆春" ];
301 var AQSva = [ "59","60","61" ];
302 $.each(AQSnm, function(i, val) {
303 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
304 });
305 break;
306 case 14:
307 $("#AQSname option").remove();
308 var AQSnm = ["花蓮","宜蘭","冬山","關山","臺東" ];
309 var AQSva = [ "63","65","66","80","62" ];
310 $.each(AQSnm, function(i, val) {
311 $("#AQSname").append($("<option value='" + AQSva[i] + "'>" + AQSnm[i] + "</option>"));
312 });
313 break;
314 }
315 });
316 </script>
317 <script>
318 $(function () {
319 $("#dt1").datepicker({
320 dateFormat: "yymmdd",
321 onSelect: function () {
322 var startDate = $(this).datepicker('getDate');
323 }
324 });
325 });
326 </script>
327
328 </body>
329 </html>
surf_traj3.py
主要為地面軌跡計算程式負責計算(traj2kml.py),在程式中以os.system()呼叫,立即執行。主要理由是因為:
程式執行時間較短,很快會有結果,再加上...
系統會尋找過去執行成果,如果已經計算過了,將會直接提交結果,不再另行計算,以減省需要時間。
此處以測站代碼,而非測站名稱進行計算,traj2km.py有因而進版。
調用jquery的data-auto-download,直接下載成果檔案到客戶端的「下載」目錄。
提供Leaflet連結,讓客戶可以馬上檢視成果,自行研判是否合理。
Leaflet的設定在index.js裏(詳下)
surf_traj3.py
2.1 KB
$ cat -n surf_traj3.py
1 #!/usr/bin/python
2 # -*- coding: UTF-8 -*-
3
4 import cgi, os, sys
5 import cgitb
6 import tempfile as tf
7 import json
8
9 form = cgi.FieldStorage()
10 dirTJ={'b':'T','f':'F'} #back->true; foreward->false
11 nam = form.getvalue('AQSname')
12 try:
13 ist=int(nam)
14 except:
15 AQ=nam
16 else:
17 fn = open('/Users/Data/cwb/e-service/surf_trj/sta_list.json')
18 d_nstnam = json.load(fn)
19 AQ=d_nstnam[nam]
20 os.system('echo '+AQ+'>&/tmp/trj.out')
21 DIR = form.getvalue("dirFB")
22 TF=dirTJ[DIR[0]]
23 num = form.getvalue("number")
24 dat = form.getvalue("date")
25 message='../../trj_results/'+DIR+AQ+dat+num+'.csv'
26 print """\
27 Content-Type: text/html\n\n
28 <html>
29 <head>
30 <title>TRAJ KML result</title>
31 <meta name="viewport" content="width=device-width, initial-scale=1">
32 <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
33 <script>
34 $(function() {
35 $('a[data-auto-download]').each(function(){
36 var $this = $(this);
37 setTimeout(function() {
38 window.location = $this.attr('href');
39 }, 2000);
40 });
41 });
42 </script>
43 </head>
44 """
45 if os.path.isfile('/Library/WebServer/Documents/'+message[6:]):
46 print """\
47 <body>
48 <p>The assigned KML file has been created and maybe downloaded in your Downloads directory.</p>
49 <p>You may re-download by clicking this <a href="%s">link</a>, or...</p>
50 <p> submit the KML file at Google Maps or OpenStreet interface at the
51 <a href=http://114.32.164.198/Leaflet/docs/index.html>Leaflet</a>.</p>
52 <p> return to the previous page and redefine the trajectory.</p>
53 </body>
54 </html>
55 """ % (message+'.kml')
56 else:
57 os.system('cd /Library/WebServer/Documents; \
58 /Users/Data/cwb/e-service/surf_trj/traj2kml.py -t '+AQ+' -d '+dat+num+' -b '+TF+ '>>/tmp/trj.out')
59 print """\
60 <body>
61 <p>The KML download should start shortly. If it doesn't, click
62 <a data-auto-download href="%s">here</a>.</p>
63 <p>The KML may be posted on google map or OpenStreet interface:
64 <a href=http://114.32.164.198/Leaflet/docs/index.html>Leaflet</a>.</p>
65 </body>
66 </html>
67 """ % (message+'.kml')
index.js
此js檔為調用D3js(Leaflet提供)的橋梁,主要使用者設定都在此一檔案內,包括了:
起始值中心點的位置(line 11)
起始地圖的縮放比例(line 12)
貼圖的顏色、透明度等(line 15~17)
起始站的標籤與文字內容(line 37~45),由layer第1個物件中提取。
$ cat -n index.js
1 (function (window) {
2 'use strict';
3 var L = window.L;
4
5 function initMap() {
6 var control;
7 var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
8 attribution: 'Map data © 2013 OpenStreetMap contributors'
9 });
10 var map = L.map('map', {
11 center: [23.6, 120.9,],
12 zoom: 7
13 }).addLayer(osm);
14 var style = {
15 color: 'blue',
16 opacity: 0.5,
17 fillOpacity: 0.3,
18 weight: 1,
19 clickable: false
20 };
21 L.Control.FileLayerLoad.LABEL = '<img class="icon" src="https://upload.wikimedia.org/wikipedia/commons/f/fe/Gnome-folder.svg" alt="file icon"/>';
22 control = L.Control.fileLayerLoad({
23 fitBounds: true,
24 layerOptions: {
25 style: style,
26 pointToLayer: function (data, latlng) {
27 return L.circleMarker(
28 latlng,
29 { style: style }
30 );
31 }
32 }
33 });
34 control.addTo(map);
35 control.loader.on('data:loaded', function (e) {
36 var layer = e.layer;
37 var kk=Object.keys(layer._layers);
38 var i=kk[0];
39 var lat0=layer._layers[i]["_latlng"]["lat"];
40 var lon0=layer._layers[i]["_latlng"]["lng"];
41 var ymd=layer._layers[i]["feature"]["properties"]["description"];
42 console.log(layer._layers[i]["feature"],layer._layers[i]["_latlng"]);
43 L.marker([lat0, lon0]).addTo(map)
44 .bindPopup(ymd)
45 .openPopup();
46 });
47 }
48
49 window.addEventListener('load', function () {
50 initMap();
51 });
52 }(window));
125.229.149.182為Hinet給定,如遇機房更新或系統因素,將不會保留。敬請逕洽作者:sinotec2@gmail.com. ↩