diff --git a/README.md b/README.md index 994696a8..1f621ba5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ ![](https://img.shields.io/github/downloads/ExpTechTW/TREM-Lite/total) +> **Note** +> 2.0.0 版本修正新版 API(需進一步測試) + > **Note** > 1.9.0 及後續版本加入 `P2P(中繼) 備援伺服器` `EEW 備援伺服器` > - `p2p-1.exptech.com.tw:1015` @@ -34,7 +37,7 @@ TREM Lite 是一款開源地震速報軟體,提供給您即時的地震資訊 ## 注意事項 1. 使用過程中,請務必謹慎閱讀提示和注意事項 2. 使用過程中可能遇到無法理解的錯誤,但大部份不影響系統運作,如遇到錯誤請向開發人員回報 -3. 即時測站資訊僅供參考,實際請以中央氣象局為主 +3. 即時測站資訊僅供參考,實際請以中央氣象署為主 4. 此軟體僅供研究、學術及教育用途(不得營利),若使用則需接受相關風險 5. 任何不被官方所認可的行為均有可能被列入伺服器黑名單中,請務必遵守相關規範 6. 此程式為免費開源程式,不保證能永久營運 diff --git a/src/core/index/action.js b/src/core/index/action.js index 1469f2e8..d5a25c21 100644 --- a/src/core/index/action.js +++ b/src/core/index/action.js @@ -19,11 +19,16 @@ document.getElementById("setting_button").onclick = () => { ipcRenderer.send("openChildWindow"); }; +document.getElementById("refresh_button").onclick = () => { + close(); + setTimeout(() => ipcMain.emit("reload"), 500); +}; + const location_button = document.getElementById("location_button"); location_button.style.border = "1px solid white"; location_button.onclick = () => { - if (location_button.style.color == "white") { - location_button.style.color = "grey"; + if (location_button.style.color == "grey") { + location_button.style.color = "white"; location_button.style.border = "1px solid white"; focus_lock = false; TREM.Maps.main.setView([23.6, 120.4], 7.8); diff --git a/src/core/index/api.js b/src/core/index/api.js index c8a24584..8d1a1fdb 100644 --- a/src/core/index/api.js +++ b/src/core/index/api.js @@ -2,6 +2,7 @@ let report_data = {}; let report_now_id = 0; let start = false; +let eew_last = ''; const info_list = []; const item_disable_geojson_vt = storage.getItem("disable_geojson_vt") ?? false; @@ -31,22 +32,50 @@ function intensity_float_to_int(float) { function fetch_eew() { const controller = new AbortController(); - setTimeout(() => controller.abort(), 2500); - fetch("https://api.exptech.com.tw/api/v1/eq/eew", { signal: controller.signal }) + setTimeout(() => controller.abort(), 1000); + fetch(`https://${api_domain}/api/v1/eq/eew?type=cwa`, { signal: controller.signal }) .then((ans) => ans.json()) .then((ans) => { - const _now = Now().getTime(); - for (const eew of ans.eew) { - eew.timestamp = _now; - get_data(eew, "http"); - } if (!start) { refresh_report_list(true); } + const _now = Now().getTime(); + last_get_eew_time = _now; + type_list.time = now_time(); + type_list.http = _now; + if (ans.length == 0) return; + const eew = ans[ans.length - 1]; + if (eew.id === eew_last) { + return; + } + eew_last = eew.id; + eew.time = _now; + eew.type = "eew-cwb"; + get_data(eew, "http"); }) .catch((err) => { + if(err.type == "aborted") return; + if (now_time() - disconnect_info > 60_000) { + disconnect_info = now_time(); + add_info("fa-solid fa-satellite-dish fa-2x info_icon", "#FF0000", "網路異常", "#00BB00", "無法取得速報資訊
請檢查網路狀態或稍後重試", 30000); + } + if(err.type == "system") return; log(err, 3, "api", "fetch_eew"); - setTimeout(() => fetch_eew(), 3000); + }); +} + +function fetch_rts() { + if(rts_replay_time) return; + const controller = new AbortController(); + setTimeout(() => controller.abort(), 2500); + fetch(`https://${api_domain}/api/v1/trem/rts/`, { signal: controller.signal }) + .then(async (ans) => { + ans = await ans.json(); + on_rts_data(ans); + }) + .catch((err) => { + if(err.type == "aborted" || err.type == "system") return; + log(err, 3, "loop", "fetch_rts"); }); } @@ -57,7 +86,7 @@ async function fetch_trem_eq(id) { const controller = new AbortController(); setTimeout(() => controller.abort(), 2500); return await new Promise((c) => { - fetch(`https://exptech.com.tw/api/v1/earthquake/trem-info/${id}`, { signal: controller.signal }) + fetch(`https://${api_domain}/api/v2/eq/report/${id}`, { signal: controller.signal }) .then((ans) => ans.json()) .then((ans) => { c(ans); @@ -78,15 +107,15 @@ async function fetch_report() { if (typeof _report_data != "object") { _report_data = []; } - fetch(`https://data.exptech.com.tw/api/v1/eq/report?limit=50${(storage.getItem("show_reportInfo") ?? false) ? (storage.getItem("key") ?? false) ? `&key=${storage.getItem("key")}` : "" : ""}`, { + fetch(`https://${api_domain}/api/v2/eq/report?limit=50${(storage.getItem("show_reportInfo") ?? false) ? (storage.getItem("key") ?? false) ? `&key=${storage.getItem("key")}` : "" : ""}`, { signal: controller.signal, }) .then(async (ans) => { ans = await ans.json(); for (let i = 0; i < ans.length; i++) { - const id = ans[i].identifier; + const id = ans[i].id; for (let _i = 0; _i < _report_data.length; _i++) { - if (_report_data[_i].identifier == id) { + if (_report_data[_i].id == id) { _report_data.splice(_i, 1); break; } @@ -97,7 +126,7 @@ async function fetch_report() { } for (let i = 0; i < _report_data.length - 1; i++) { for (let _i = 0; _i < _report_data.length - 1; _i++) { - if (new Date(_report_data[_i].originTime.replaceAll("/", "-")).getTime() < new Date(_report_data[_i + 1].originTime.replaceAll("/", "-")).getTime()) { + if (_report_data[_i].time < _report_data[_i + 1].time) { const temp = _report_data[_i + 1]; _report_data[_i + 1] = _report_data[_i]; _report_data[_i] = temp; @@ -117,6 +146,24 @@ async function fetch_report() { }); } +async function fetch_report_single(i, id) { + return await new Promise((c) => { + const controller = new AbortController(); + setTimeout(() => controller.abort(), 2500); + fetch(`https://${api_domain}/api/v2/eq/report/${id}`, { + signal: controller.signal, + }) + .then(async (ans) => { + ans = await ans.json(); + report_report(i, ans); + }) + .catch((err) => { + log(err, 3, "api", "fetch_report"); + c(false); + }); + }); +} + async function refresh_report_list(_fetch = false, data = {}) { if (_fetch) { const ans = await fetch_report(); @@ -188,13 +235,8 @@ async function refresh_report_list(_fetch = false, data = {}) { report.className = "report"; report.id = i; if (i == -1) { - const now = new Date(data.time); - const _Now = now.getFullYear() - + "/" + (now.getMonth() + 1 < 10 ? "0" : "") + (now.getMonth() + 1) - + "/" + (now.getDate() < 10 ? "0" : "") + now.getDate() - + " " + (now.getHours() < 10 ? "0" : "") + now.getHours() - + ":" + (now.getMinutes() < 10 ? "0" : "") + now.getMinutes() - + ":" + (now.getSeconds() < 10 ? "0" : "") + now.getSeconds(); + ts_to_time(data.time) + const _Now = ts_to_time(data.time); const report_text_intensity = document.createElement("div"); report_text_intensity.className = `report_text report_intensity intensity_${data.i}`; report_text_intensity.style = `font-size: ${(data.i > 4 && data.i != 7) ? "50" : "60"}px;`; @@ -212,14 +254,14 @@ async function refresh_report_list(_fetch = false, data = {}) { report_text_box.append(report_text, report_text_time); report.append(report_text_intensity, report_text_box); } else { - const originTime = new Date((new Date(`${report_data[i].originTime} GMT+08:00`)).toLocaleString("en-US", { timeZone: "Asia/Taipei" })); + const originTime = new Date(report_data[i].time + 28800); if (report_now_id == originTime.getTime()) { report.className = "report replay"; } - const intensity = report_data[i].data[0]?.areaIntensity ?? 0; - const time = report_data[i].originTime.substring(0, 16); + const intensity = report_data[i].int ?? 0; + const time = ts_to_time(report_data[i].time); const cwb_code = "EQ" - + report_data[i].earthquakeNo + + report_data[i].id + "-" + (originTime.getMonth() + 1 < 10 ? "0" : "") + (originTime.getMonth() + 1) + (originTime.getDate() < 10 ? "0" : "") + originTime.getDate() @@ -227,7 +269,7 @@ async function refresh_report_list(_fetch = false, data = {}) { + (originTime.getHours() < 10 ? "0" : "") + originTime.getHours() + (originTime.getMinutes() < 10 ? "0" : "") + originTime.getMinutes() + (originTime.getSeconds() < 10 ? "0" : "") + originTime.getSeconds(); - let loc = report_data[i].location; + let loc = report_data[i].loc; loc = loc.substring(loc.indexOf("(") + 3, loc.indexOf(")")); const resize = (intensity > 4 && intensity != 7) ? true : false; const intensity_level = (intensity == 0) ? "--" : int_to_intensity(intensity); @@ -253,8 +295,8 @@ async function refresh_report_list(_fetch = false, data = {}) { report_text_magnitudeValue_depth.style = "display: flex;"; const report_text_magnitudeValue = document.createElement("div"); report_text_magnitudeValue.className = "report_text"; - report_text_magnitudeValue.style.color = (report_data[i].earthquakeNo.toString().includes("000")) ? "white" : "goldenrod"; - report_text_magnitudeValue.innerHTML = `M ${report_data[i].magnitudeValue.toFixed(1)}`; + report_text_magnitudeValue.style.color = (report_data[i].id.includes("000")) ? "white" : "goldenrod"; + report_text_magnitudeValue.innerHTML = `M ${report_data[i].mag.toFixed(1)}`; const report_text_depth = document.createElement("div"); report_text_depth.className = "report_text report_scale"; report_text_depth.style = "width: 100%;text-align: right;"; @@ -278,9 +320,6 @@ async function refresh_report_list(_fetch = false, data = {}) { } report_click_replay.id = `${originTime.getTime()}_click_replay`; report_click_replay.onclick = () => { - if (!WS) { - return; - } if (rts_replay_timestamp) { const skip = (report_now_id == originTime.getTime()) ? true : false; replay_stop(); @@ -303,13 +342,13 @@ async function refresh_report_list(_fetch = false, data = {}) { "originTime" : originTime.getTime(), "type" : "eew-report", "time" : _now + 3000, - "lon" : report_data[i].epicenterLon, - "lat" : report_data[i].epicenterLat, + "lon" : report_data[i].lon, + "lat" : report_data[i].lat, "depth" : Math.round(report_data[i].depth), - "scale" : Number(report_data[i].magnitudeValue.toFixed(1)), + "scale" : Number(report_data[i].mag.toFixed(1)), "timestamp" : _now, "number" : 1, - "id" : report_data[i].ID + "R", + "id" : report_data[i].id + "R", "location" : loc, "cancel" : false, "replay_timestamp" : Date.now(), @@ -319,9 +358,9 @@ async function refresh_report_list(_fetch = false, data = {}) { const report_click_web = document.createElement("i"); report_click_web.className = "report_click_text fa fa-globe fa-2x"; report_click_web.id = `${originTime.getTime()}_click_web`; - if (report_data[i].trem || !report_data[i].location.startsWith("地震資訊")) { + if (report_data[i].trem || !report_data[i].loc.startsWith("地震資訊")) { report_click_web.onclick = () => { - shell.openExternal((report_data[i].trem) ? `https://exptech.com.tw/api/v1/file/trem-info.html?id=${report_data[i].trem}` : `https://www.cwa.gov.tw/V8/C/E/EQ/${cwb_code}.html`); + shell.openExternal((report_data[i].trem) ? `https://exptech.com.tw/file/images/report/${report_data[i].id}.png` : `https://www.cwa.gov.tw/V8/C/E/EQ/${cwb_code}.html`); }; } else { report_click_web.style = "color: red;"; @@ -348,8 +387,8 @@ async function refresh_report_list(_fetch = false, data = {}) { report_text_time.textContent = `${time}`; const report_text_magnitudeValue = document.createElement("div"); report_text_magnitudeValue.className = "report_text report_scale"; - report_text_magnitudeValue.style.color = (report_data[i].earthquakeNo.toString().includes("000")) ? "white" : "goldenrod"; - report_text_magnitudeValue.innerHTML = `M ${report_data[i].magnitudeValue.toFixed(1)}`; + report_text_magnitudeValue.style.color = (report_data[i].id.includes("000")) ? "white" : "goldenrod"; + report_text_magnitudeValue.innerHTML = `M ${report_data[i].mag.toFixed(1)}`; report_text_box.append(report_text_loc, report_text_time); report_info.append(report_text, report_text_box, report_text_magnitudeValue); const report_click_box = document.createElement("div"); @@ -368,9 +407,6 @@ async function refresh_report_list(_fetch = false, data = {}) { } report_click_replay.id = `${originTime.getTime()}_click_replay`; report_click_replay.onclick = () => { - if (!WS) { - return; - } if (rts_replay_timestamp) { const skip = (report_now_id == originTime.getTime()) ? true : false; replay_stop(); @@ -393,13 +429,13 @@ async function refresh_report_list(_fetch = false, data = {}) { "originTime" : originTime.getTime(), "type" : "eew-report", "time" : _now + 3000, - "lon" : report_data[i].epicenterLon, - "lat" : report_data[i].epicenterLat, + "lon" : report_data[i].lon, + "lat" : report_data[i].lat, "depth" : Math.round(report_data[i].depth), - "scale" : Number(report_data[i].magnitudeValue.toFixed(1)), + "scale" : Number(report_data[i].mag.toFixed(1)), "timestamp" : _now, "number" : 1, - "id" : report_data[i].ID + "R", + "id" : report_data[i].id + "R", "location" : loc, "cancel" : false, "replay_timestamp" : Date.now(), @@ -409,9 +445,9 @@ async function refresh_report_list(_fetch = false, data = {}) { const report_click_web = document.createElement("i"); report_click_web.className = "report_click_text fa fa-globe fa-2x"; report_click_web.id = `${originTime.getTime()}_click_web`; - if (report_data[i].trem || !report_data[i].location.startsWith("地震資訊")) { + if (report_data[i].trem || !report_data[i].loc.startsWith("地震資訊")) { report_click_web.onclick = () => { - shell.openExternal((report_data[i].trem) ? `https://exptech.com.tw/api/v1/file/trem-info.html?id=${report_data[i].trem}` : `https://www.cwa.gov.tw/V8/C/E/EQ/${cwb_code}.html`); + shell.openExternal((report_data[i].trem) ? `https://exptech.com.tw/file/images/report/${report_data[i].id}.png` : `https://www.cwa.gov.tw/V8/C/E/EQ/${cwb_code}.html`); }; } else { report_click_web.style = "color: red;"; @@ -421,9 +457,9 @@ async function refresh_report_list(_fetch = false, data = {}) { } if (!start) { start = true; - if (!Object.keys(TREM.EQ_list).length) { + /* if (!Object.keys(TREM.EQ_list).length) { report_report(i); - } + } */ } report.onmouseenter = () => { document.getElementById(`${originTime.getTime()}_click_box`).style.height = document.getElementById(`${originTime.getTime()}_info`).offsetHeight; @@ -541,12 +577,12 @@ function eew_location_intensity(data, depth) { for (const city of Object.keys(region)) { for (const town of Object.keys(region[city])) { const info = region[city][town]; - const dist_surface = dis(data.lat, data.lon, info.lat, info.lon); - const dist = Math.sqrt(pow(dist_surface) + pow(data.depth)); - const pga = 1.657 * Math.pow(Math.E, (1.533 * data.scale)) * Math.pow(dist, -1.607); + const dist_surface = dis(data.eq.lat, data.eq.lon, info.lat, info.lon); + const dist = Math.sqrt(pow(dist_surface) + pow(data.eq.depth)); + const pga = 1.657 * Math.pow(Math.E, (1.533 * data.eq.mag)) * Math.pow(dist, -1.607); let i = pga_to_float(pga); if (i > 3) { - i = eew_i([data.lat, data.lon], [info.lat, info.lon], data.depth, data.scale); + i = eew_i([data.eq.lat, data.eq.lon], [info.lat, info.lon], data.eq.depth, data.eq.mag); } if (i > eew_max_i) { eew_max_i = i; @@ -562,12 +598,12 @@ function eew_location_intensity(data, depth) { } function eew_location_info(data) { - const dist_surface = dis(data.lat, data.lon, TREM.user.lat, TREM.user.lon); - const dist = Math.sqrt(pow(dist_surface) + pow(data.depth)); - const pga = 1.657 * Math.pow(Math.E, (1.533 * data.scale)) * Math.pow(dist, -1.607) * (storage.getItem("site") ?? 1.751); + const dist_surface = dis(data.eq.lat, data.eq.lon, TREM.user.lat, TREM.user.lon); + const dist = Math.sqrt(pow(dist_surface) + pow(data.eq.depth)); + const pga = 1.657 * Math.pow(Math.E, (1.533 * data.eq.mag)) * Math.pow(dist, -1.607) * (storage.getItem("site") ?? 1.751); let i = pga_to_float(pga); if (i > 3) { - i = eew_i([data.lat, data.lon], [TREM.user.lat, TREM.user.lon], data.depth, data.scale); + i = eew_i([data.eq.lat, data.eq.lon], [TREM.user.lat, TREM.user.lon], data.eq.depth, data.eq.mag); } return { dist, @@ -618,14 +654,26 @@ function int_to_color(int) { return list[int]; } -async function report_report(info) { +function ts_to_time(ts) { + const now = new Date(ts); + const YYYY = now.getFullYear(); + const MM = (now.getMonth() + 1).toString().padStart(2, "0"); + const DD = now.getDate().toString().padStart(2, "0"); + const hh = now.getHours().toString().padStart(2, "0"); + const mm = now.getMinutes().toString().padStart(2, "0"); + const ss = now.getSeconds().toString().padStart(2, "0"); + const t = `${YYYY}/${MM}/${DD} ${hh}:${mm}:${ss}`; + return t; +} + +async function report_report(info, report_detail=null) { if (Object.keys(TREM.EQ_list).length) { return; } - if (TREM.report_time) { + if (TREM.report_time && !report_detail) { report_off(); } - if (click_report_id == info) { + if (click_report_id == info && !report_detail) { click_report_id = -1; return; } @@ -636,42 +684,45 @@ async function report_report(info) { iconUrl : "../resource/images/cross.png", iconSize : [30, 30], }); - const intensity = data.data[0]?.areaIntensity ?? 0; + const intensity = data.int ?? 0; const intensity_level = (intensity == 0) ? "--" : int_to_intensity(intensity); - TREM.report_epicenterIcon = L.marker([data.epicenterLat, data.epicenterLon], + if (TREM.report_epicenterIcon) { + TREM.report_epicenterIcon.remove(); + } + TREM.report_epicenterIcon = L.marker([data.lat, data.lon], { icon: epicenterIcon, zIndexOffset: 6000 }).addTo(TREM.Maps.main); - TREM.report_bounds.extend([data.epicenterLat, data.epicenterLon]); - if (!data.location.startsWith("地震資訊")) { - for (let _i = 0; _i < data.data.length; _i++) { - const station_data = data.data[_i].eqStation; - for (let i = 0; i < station_data.length; i++) { - const station_Intensity = station_data[i].stationIntensity; + TREM.report_bounds.extend([data.lat, data.lon]); + if(!report_detail){ + fetch_report_single(info, data.id); + } else { + for (const city of Object.keys(report_detail.list)) { + for (const town of Object.keys(report_detail.list[city].town)) { const icon = L.divIcon({ - className : `dot intensity_${station_Intensity}`, - html : `${int_to_intensity(station_Intensity)}`, + className : `dot intensity_${report_detail.list[city].town[town].int}`, + html : `${int_to_intensity(report_detail.list[city].town[town].int)}`, iconSize : [30, 30], }); - TREM.report_icon_list[`${station_data[i].stationName}-${Date.now()}`] = L.marker([station_data[i].stationLat, station_data[i].stationLon], { icon: icon, zIndexOffset: station_Intensity * 10 }) - .bindTooltip(`
站名: ${data.data[_i].areaName} ${station_data[i].stationName}
位置: ${station_data[i].stationLat} °N ${station_data[i].stationLon} °E
距離: ${station_data[i].distance} km
震度: ${int_to_intensity(station_Intensity)}
`, { opacity: 1 }) + TREM.report_icon_list[`${city}${town}-${Date.now()}`] = L.marker([report_detail.list[city].town[town].lat, report_detail.list[city].town[town].lon], { icon: icon, zIndexOffset: report_detail.list[city].town[town].int * 10 }) + .bindTooltip(`
地點: ${city} ${town}
位置: ${report_detail.list[city].town[town].lat} °N ${report_detail.list[city].town[town].lon} °E
震度: ${int_to_intensity(report_detail.list[city].town[town].int)}
`, { opacity: 1 }) .addTo(TREM.Maps.main); - TREM.report_bounds.extend([station_data[i].stationLat, station_data[i].stationLon]); + TREM.report_bounds.extend([report_detail.list[city].town[town].lat, report_detail.list[city].town[town].lon]); } } } Zoom = true; TREM.Maps.main.setView(TREM.report_bounds.getCenter(), TREM.Maps.main.getBoundsZoom(TREM.report_bounds) - 0.5); show_icon(true); - document.getElementById("report_title_text").textContent = `${get_lang_string("report.title").replace("${type}", (data.location.startsWith("地震資訊")) ? get_lang_string("report.title.Local") : ((data.earthquakeNo % 1000) ? data.earthquakeNo : get_lang_string("report.title.Small")))}`; - document.getElementById("report_max_intensity").textContent = (data.location.startsWith("地震資訊")) ? "最大震度" : `${data.data[0].areaName} ${data.data[0].eqStation[0].stationName}`; + document.getElementById("report_title_text").textContent = `${get_lang_string("report.title").replace("${type}", (data.loc.startsWith("地震資訊")) ? get_lang_string("report.title.Local") : get_lang_string("report.title.Small"))}`; + document.getElementById("report_max_intensity").textContent = (data.loc.startsWith("地震資訊")) ? "最大震度" : `${data.int}`; const eew_intensity = document.getElementById("report_intensity"); eew_intensity.className = `intensity_${intensity} intensity_center`; eew_intensity.textContent = intensity_level; const report_location = document.getElementById("report_location"); - const loc = data.location.substring(data.location.indexOf("(") + 1, data.location.indexOf(")")).replace("位於", ""); + const loc = data.loc; report_location.style.fontSize = (loc.length > 10) ? "16px" : (loc.length > 7) ? "20px" : "24px"; report_location.textContent = loc; - document.getElementById("report_time").textContent = get_lang_string("eew.time").replace("${time}", data.originTime); - let report_magnitudeValue = data.magnitudeValue.toString(); + document.getElementById("report_time").textContent = get_lang_string("eew.time").replace("${time}", ts_to_time(data.time)); + let report_magnitudeValue = data.mag.toString(); if (report_magnitudeValue.length == 1) { report_magnitudeValue = report_magnitudeValue + ".0"; } @@ -696,7 +747,7 @@ async function report_report(info) { } TREM.report_epicenterIcon_trem = L.marker([trem_eew.lat, trem_eew.lon], { icon: epicenterIcon_trem, zIndexOffset: 6000 }) - .bindTooltip(`
報數: 共 ${trem_eq.trem.eew.length} 報
位置: ${trem_eew.location} | ${trem_eew.lat}°N ${trem_eew.lon} °E
類型: ${trem_eew.model}
規模: M ${trem_eew.scale}
深度: ${trem_eew.depth} km
預估最大震度: ${int_to_intensity(trem_eew.max)}
`, { opacity: 1 }) + .bindTooltip(`
報數: 共 ${trem_eq.trem.eew.length} 報
位置: ${trem_eew.location} | ${trem_eew.lat}°N ${trem_eew.lon} °E
規模: M ${trem_eew.scale}
深度: ${trem_eew.depth} km
預估最大震度: ${int_to_intensity(trem_eew.max)}
`, { opacity: 1 }) .addTo(TREM.Maps.main); if (TREM.report_circle_trem) { TREM.report_circle_trem.remove(); diff --git a/src/core/index/client.jar b/src/core/index/client.jar deleted file mode 100644 index 07ea1c79..00000000 Binary files a/src/core/index/client.jar and /dev/null differ diff --git a/src/core/index/core.js b/src/core/index/core.js index 52edc627..4a2d25f7 100644 --- a/src/core/index/core.js +++ b/src/core/index/core.js @@ -1,55 +1,6 @@ /* eslint-disable no-undef */ -const crypto = require("crypto"); -const dgram = require("dgram"); -const client = dgram.createSocket("udp4"); - -const EventEmitter = require("events").EventEmitter; -const event = new EventEmitter(); - const win = BrowserWindow.fromId(process.env.window * 1); -// if (fs.existsSync(path.resolve(app.getAppPath(), "./core/index/client.js"))) { -// const vm = require("vm"); -// const v8 = require("v8"); -// v8.setFlagsFromString("--no-lazy"); -// const code = fs.readFileSync(path.resolve(app.getAppPath(), "./core/index/client.js"), "utf-8"); -// const script = new vm.Script(code); -// const bytecode = script.createCachedData(); -// fs.writeFileSync(path.resolve(app.getAppPath(), "./core/index/client.jar"), bytecode); -// } - -bytenode.runBytecodeFile(path.resolve(app.getAppPath(), "./core/index/client.jar")); - -event.on("data", (data) => get_data(data, "p2p")); - -event.on("log", (data) => log(data.msg, data.type)); - -client.on("listening", () => { - const address = client.address(); - log(`Client listening on ${address.address}:${address.port}`, 1); -}); - -get_server_info(); -async function get_server_info() { - try { - const controller = new AbortController(); - setTimeout(() => controller.abort(), 1500); - let ans = await fetch("https://cdn.jsdelivr.net/gh/ExpTechTW/API@master/resource/server_list.json", { signal: controller.signal }) - .catch((err) => void 0); - if (controller.signal.aborted || !ans) { - setTimeout(() => get_server_info(), 500); - return; - } - ans = await ans.json(); - init(client, event, { - server_list: ans.p2p, - }, crypto); - } catch (err) { - log(err, 3, "core", "get_server_info"); - setTimeout(() => get_server_info(), 500); - } -} - log("Start", 1, "log", "~"); ipcMain.on("replay_start", (e, time) => { diff --git a/src/core/index/eew.js b/src/core/index/eew.js index 6ece42b2..644196e6 100644 --- a/src/core/index/eew.js +++ b/src/core/index/eew.js @@ -29,26 +29,22 @@ function eew(_eew) { const data = TREM.EQ_list[show_eew_id].data; const eew_max_intensity = TREM.EQ_list[show_eew_id].eew; const alert = TREM.EQ_list[show_eew_id].alert; - const unit = (data.type == "eew-jma") ? "JMA" : (data.type == "eew-nied") ? "NIED" : (data.type == "eew-kma") ? "KMA" : (data.type == "eew-scdzj") ? "SCDZJ" : (data.type == "eew-cwb") ? "CWA" : "TREM"; + const unit = data.author; document.getElementById("eew_title_text").textContent = `${unit} ${get_lang_string("eew.title").replace("${type}", (data.cancel) ? get_lang_string("eew.cancel") : (data.Test) ? get_lang_string("eew.test") : (alert) ? get_lang_string("eew.alert") : get_lang_string("eew.warn"))}${(eew_list.length == 1) ? "" : ` ${eew_number + 1}/${eew_list.length}`}`; - document.getElementById("eew_title_text_number").textContent = `${get_lang_string("eew.number").replace("${number}", data.number)}${(data.final) ? `(${get_lang_string("eew.final")})` : ""}`; - document.getElementById("eew_box").style.backgroundColor = (data.cancel) ? "#333439" : (data.Test) ? "darkviolet" : (data.model == "nsspe" || data.scale == 1) ? "darkblue" : (alert) ? "red" : "#FF9224"; + document.getElementById("eew_title_text_number").textContent = `${get_lang_string("eew.number").replace("${number}", data.serial)}${(data.final) ? `(${get_lang_string("eew.final")})` : ""}`; + document.getElementById("eew_box").style.backgroundColor = (data.status == 2) ? "#333439" : (data.status == 3) ? "darkviolet" : (data.eq.mag == 1) ? "darkblue" : (alert) ? "red" : "#FF9224"; const eew_body = document.getElementById("eew_body"); eew_body.style.backgroundColor = "#514339"; eew_body.style.border = "2px solid black"; const eew_intensity = document.getElementById("eew_intensity"); eew_intensity.className = `intensity_${eew_max_intensity} intensity_center`; - eew_intensity.textContent = (data.model == "nsspe" && !eew_max_intensity) ? "不明" : int_to_intensity(eew_max_intensity); - if (data.model == "nsspe" && !eew_max_intensity) { - eew_intensity.style.fontSize = 30; - } else { - eew_intensity.style.fontSize = 50; - } + eew_intensity.textContent = int_to_intensity(eew_max_intensity); + eew_intensity.style.fontSize = 50; const eew_location = document.getElementById("eew_location"); - eew_location.style.fontSize = (data.location.length > 10) ? "16px" : (data.location.length > 7) ? "20px" : "24px"; - eew_location.textContent = `${data.location}`; + eew_location.style.fontSize = (data.eq.loc.length > 10) ? "16px" : (data.eq.loc.length > 7) ? "20px" : "24px"; + eew_location.textContent = `${data.eq.loc}`; - const now = new Date((data.replay_time) ? data.replay_time : data.time); + const now = new Date((data.replay_time) ? data.replay_time : data.eq.time); let eew_time = now.getFullYear().toString(); eew_time += "/"; if ((now.getMonth() + 1) < 10) { @@ -80,31 +76,25 @@ function eew(_eew) { } else { eew_time += now.getSeconds().toString(); } - let eew_scale = data.scale.toString(); + let eew_scale = data.eq.mag.toString(); if (eew_scale.length == 1) { eew_scale = eew_scale + ".0"; } document.getElementById("eew_time").textContent = get_lang_string("eew.time").replace("${time}", eew_time); const text_title = document.getElementById("eew_scale"); const text_body = document.getElementById("eew_args"); - if (data.scale == 1) { + if (data.eq.mag == 1) { text_title.style.fontSize = 18; text_title.textContent = "PLUM"; text_body.style.fontSize = 12; text_body.style.textAlign = "start"; text_body.textContent = "局部無阻尼運動傳播法"; - } else if (data.model == "nsspe") { - text_title.style.fontSize = 18; - text_title.textContent = "NSSPE"; - text_body.style.fontSize = 14; - text_body.style.textAlign = "start"; - text_body.textContent = "無震源參數推算"; } else { text_title.style.fontSize = 26; text_body.style.fontSize = 18; text_body.style.textAlign = "right"; text_title.textContent = `M ${eew_scale}`; - text_body.innerHTML = `${get_lang_string("word.depth")}: ${data.depth} km`; + text_body.innerHTML = `${get_lang_string("word.depth")}: ${data.eq.depth} km`; } } } \ No newline at end of file diff --git a/src/core/index/event.js b/src/core/index/event.js index 309cdbc0..8eb1ef63 100644 --- a/src/core/index/event.js +++ b/src/core/index/event.js @@ -15,8 +15,6 @@ let _id = ""; let type_list = { time : 0, http : 0, - p2p : 0, - fcm : 0, websocket : 0, }; @@ -44,11 +42,7 @@ const item_audio_eew2 = storage.getItem("audio.EEW2") ?? true; function get_data(data, type = "websocket") { if (data.type != "trem-rts") { type_list.time = now_time(); - if (type == "p2p") { - type_list.p2p = now_time(); - } else if (type == "fcm") { - type_list.fcm = now_time(); - } else if (type == "websocket") { + if (type == "websocket") { type_list.websocket = now_time(); } else if (type == "http") { type_list.http = now_time(); @@ -80,12 +74,6 @@ function get_data(data, type = "websocket") { if (data_cache.length > 15) { data_cache.splice(0, 1); } - if (data.type == "trem-eew" && !item_trem_eew) { - return; - } - if (data.model == "eew") { - data.type = "eew-trem"; - } if (data.type == "trem-rts") { if (!rts_replay_time) { on_rts_data(data.raw); @@ -140,7 +128,7 @@ function get_data(data, type = "websocket") { eq_station_list[station.stationIntensity].push(`${city.areaName}${station.stationName}`); } } - console.log(eq_station_list); + // console.log(eq_station_list); let count = 0; for (let i = 9; i >= 1; i--) { if (!eq_station_list[i].length) { @@ -174,25 +162,7 @@ function get_data(data, type = "websocket") { refresh_report_list(false, data); screenshot_id = `report_${now_time()}`; plugin.emit("trem.report.on-report", data); - } else if (data.type == "eew-report" || data.type == "eew-trem" || data.type == "eew-cwb" || data.type == "eew-scdzj" || data.type == "eew-kma" || data.type == "eew-jma" || data.type == "eew-nied") { - if ((data.type == "eew-jma" || data.type == "eew-nied") && data.location == "台湾付近") { - return; - } - if (data.type == "eew-jma" && !item_jma_eew) { - return; - } - if (data.type == "eew-kma" && !item_kma_eew) { - return; - } - if (data.type == "eew-nied" && !item_nied_eew) { - return; - } - if (data.type == "eew-scdzj" && !item_scdzj_eew) { - return; - } - if (data.type == "eew-cwb" && !item_cwb_eew) { - return; - } + } else if (data.type == "eew-report" || data.type == "eew-cwb") { if (Now().getTime() - data.time > 240_000 && !data.replay_timestamp) { return; } @@ -225,6 +195,7 @@ function get_data(data, type = "websocket") { } function on_eew(data, type) { + // console.log(data) TREM.eew = true; let skip = false; if (item_eew_level != -1) { @@ -251,8 +222,8 @@ function on_eew(data, type) { eew : 0, alert : false, }; - if (!eew_cache.includes(data.id + data.number)) { - eew_cache.push(data.id + data.number); + if (!eew_cache.includes(data.id + data.serial)) { + eew_cache.push(data.id + data.serial); if (!skip && item_audio_eew) { TREM.audio.push("EEW"); } @@ -262,14 +233,14 @@ function on_eew(data, type) { TREM.EQ_list[data.id].loc = eew; plugin.emit("trem.eew.on-eew-create", data); } else { - if (!data.location) { - data.location = TREM.EQ_list[data.id].data.location; + if (!data.eq.loc) { + data.eq.loc = TREM.EQ_list[data.id].data.eq.loc; } - if (!data.lat) { - data.lat = TREM.EQ_list[data.id].data.lat; + if (!data.eq.lat) { + data.eq.lat = TREM.EQ_list[data.id].data.eq.lat; } - if (!data.lon) { - data.lon = TREM.EQ_list[data.id].data.lon; + if (!data.eq.lon) { + data.eq.lon = TREM.EQ_list[data.id].data.eq.lon; } TREM.EQ_list[data.id].data = data; if (data.cancel) { @@ -286,19 +257,19 @@ function on_eew(data, type) { } } else { if (TREM.EQ_list[data.id].p_wave) { - TREM.EQ_list[data.id].p_wave.setLatLng([data.lat, data.lon]); + TREM.EQ_list[data.id].p_wave.setLatLng([data.eq.lat, data.eq.lon]); } if (TREM.EQ_list[data.id].s_wave) { - TREM.EQ_list[data.id].s_wave.setLatLng([data.lat, data.lon]); + TREM.EQ_list[data.id].s_wave.setLatLng([data.eq.lat, data.eq.lon]); } if (TREM.EQ_list[data.id].s_wave_back) { - TREM.EQ_list[data.id].s_wave_back.setLatLng([data.lat, data.lon]); + TREM.EQ_list[data.id].s_wave_back.setLatLng([data.eq.lat, data.eq.lon]); } } if (item_audio_update) { TREM.audio.push("update"); } - const eew = eew_location_intensity(data, data.depth); + const eew = eew_location_intensity(data, data.eq.depth); data.max = intensity_float_to_int(eew.max_i); TREM.EQ_list[data.id].loc = eew; TREM.EQ_list[data.id].eew = intensity_float_to_int(TREM.EQ_list[data.id].loc.max_i); @@ -314,8 +285,8 @@ function on_eew(data, type) { TREM.EQ_list[data.id].epicenterIcon.remove(); delete TREM.EQ_list[data.id].epicenterIcon; } - if (data.type == "eew-cwb" && data.location.includes("海") && Number(data.depth) <= 35) { - if (Number(data.scale) >= 7) { + if (data.type == "eew-cwb" && data.eq.loc.includes("海") && Number(data.eq.depth) <= 35) { + if (Number(data.eq.mag) >= 7) { if (!TREM.EQ_list[data.id].alert_tsunami) { TREM.EQ_list[data.id].alert_tsunami = true; if (!skip && speecd_use) { @@ -323,7 +294,7 @@ function on_eew(data, type) { } add_info("fa-solid fa-house-tsunami fa-2x info_icon", "#0072E3", "注意海嘯", "#FF5809", "震源位置及規模表明
可能發生海嘯
沿岸地區應慎防海水位突變
並留意 中央氣象署(CWA)
是否發布 [ 海嘯警報 ]"); } - } else if (Number(data.scale) >= 6) { + } else if (Number(data.eq.mag) >= 6) { if (!TREM.EQ_list[data.id].alert_sea) { TREM.EQ_list[data.id].alert_sea = true; if (!skip && speecd_use) { @@ -333,28 +304,30 @@ function on_eew(data, type) { } } } - const notification = new Notification(`🚨 地震預警 第${data.number}報 | ${unit}`, { - body : `${time_to_string((data.replay_time) ? data.replay_time : data.time)}\n${data.location} ${(data.cancel) ? "取消" : `發生 M${data.scale.toFixed(1)} 地震`}`, - icon : "../TREM.ico", - }); - notification.addEventListener("click", () => MainWindow.focus()); - if (_id != data.id) { - _id = data.id; - _list = ""; - _max = -1; - _location = ""; + if (!data.replay_timestamp) { + const notification = new Notification(`🚨 地震預警 第${data.serial}報 | ${unit}`, { + body : `${time_to_string((data.eq.time) ? data.eq.time : data.time)}\n${data.eq.loc} ${(data.status == 2) ? "取消" : `發生 M${data.eq.mag.toFixed(1)} 地震`}`, + icon : "../TREM.ico", + }); + notification.addEventListener("click", () => MainWindow.focus()); + if (_id != data.id) { + _id = data.id; + _list = ""; + _max = -1; + _location = ""; + } } - if (data.cancel) { + if (data.status == 2) { if (!skip && speecd_use) { loc_speech_clock = false; eew_speech_clock = false; - speech.speak({ text: `${data.location},取消` }); + speech.speak({ text: `${data.eq.loc},取消` }); } plugin.emit("trem.eew.on-eew-cancel", data); } else if (!skip && speecd_use) { eew_speech = { - loc : data.location, - max : data.max, + loc : data.eq.loc, + max : data.eq.max, }; eew_speech_clock = true; } @@ -390,20 +363,20 @@ function on_eew(data, type) { } if (TREM.EQ_list[_data.id].epicenterIcon) { TREM.EQ_list[_data.id].epicenterIcon.setIcon(epicenterIcon); - TREM.EQ_list[_data.id].epicenterIcon.setLatLng([_data.lat + offsetY, _data.lon + offsetX]); + TREM.EQ_list[_data.id].epicenterIcon.setLatLng([_data.eq.lat + offsetY, _data.eq.lon + offsetX]); } else { - TREM.EQ_list[_data.id].epicenterIcon = L.marker([_data.lat + offsetY, _data.lon + offsetX], { icon: epicenterIcon, zIndexOffset: 6000 }).addTo(TREM.Maps.main); + TREM.EQ_list[_data.id].epicenterIcon = L.marker([_data.eq.lat + offsetY, _data.eq.lon + offsetX], { icon: epicenterIcon, zIndexOffset: 6000 }).addTo(TREM.Maps.main); } } } else if (TREM.EQ_list[data.id].epicenterIcon) { - TREM.EQ_list[data.id].epicenterIcon.setLatLng([data.lat, data.lon]); + TREM.EQ_list[data.id].epicenterIcon.setLatLng([data.eq.lat, data.eq.lon]); } else { epicenterIcon = L.icon({ iconUrl : "../resource/images/cross.png", iconSize : [40 + TREM.size * 3, 40 + TREM.size * 3], className : "flash", }); - TREM.EQ_list[data.id].epicenterIcon = L.marker([data.lat, data.lon], { icon: epicenterIcon, zIndexOffset: 6000 }) + TREM.EQ_list[data.id].epicenterIcon = L.marker([data.eq.lat, data.eq.lon], { icon: epicenterIcon, zIndexOffset: 6000 }) .addTo(TREM.Maps.main); } const _loc_list = TREM.EQ_list[data.id].loc; diff --git a/src/core/index/globals.js b/src/core/index/globals.js index 19bfa57c..a8de9ce2 100644 --- a/src/core/index/globals.js +++ b/src/core/index/globals.js @@ -12,7 +12,5 @@ const speech = new Speech.default(); await speech.init(); speech.setLanguage("zh-TW"); speech.setVoice("Microsoft Zhiwei - Chinese (Traditional, Taiwan)"); - // speech.setLanguage("ja-JP"); - // speech.setVoice("Microsoft Sayaka - Japanese (Japan)"); speech.setRate(1.8); })(); \ No newline at end of file diff --git a/src/core/index/loop.js b/src/core/index/loop.js index ee670402..aabc6da1 100644 --- a/src/core/index/loop.js +++ b/src/core/index/loop.js @@ -56,14 +56,14 @@ map.onmousedown = () => { Zoom = false; focus_lock = true; const location_button = document.getElementById("location_button"); - location_button.style.color = "white"; + location_button.style.color = "grey"; location_button.style.border = "1px solid red"; }; map.onwheel = () => { focus_lock = true; const location_button = document.getElementById("location_button"); - location_button.style.color = "white"; + location_button.style.color = "grey"; location_button.style.border = "1px solid red"; }; @@ -78,10 +78,27 @@ time.onclick = () => { time.style.cursor = ""; }; +fetch_eew(); +fetch_rts(); +setInterval(() => { + if(WS) return; + fetch_eew(); + if(sleep_state || parseInt(Date.now()/1000)%5!=0) return; + fetch_rts(); /* 每五秒抓一次RTS (CDN有快取時間) */ +}, 1_000); + +setInterval(() => { + if(sleep_state) return; + refresh_report_list(); +}, 120_000); + setInterval(() => { setTimeout(() => { const now = (rts_replay_time) ? rts_replay_time : Now().getTime(); - if (WS) { + if (rts_replay_time || Now().getTime() - last_get_rts_time < 10000) { + if(!rts_replay_time) { + time.style.color = "white"; + } time.innerHTML = `${time_to_string(now)}`; if (!check_file_replay) { check_file_replay = true; @@ -90,6 +107,8 @@ setInterval(() => { replay_run(); } } + } else { + time.style.color = "red"; } for (const item of document.getElementsByClassName("flash")) { item.style.visibility = "hidden"; @@ -142,63 +161,42 @@ setInterval(() => { if (screenshot_id != "") { const _screenshot_id = screenshot_id; screenshot_id = ""; - setTimeout(() => { - ipcRenderer.send("screenshot_auto", { id: _screenshot_id }); - }, 1750); } if (!sleep_state) { let _status_text = ""; if (rts_replay_time) { _status_text = "🔁 重播資料"; - } else if (rts_lag < 100) { + } else if (rts_lag < 6000) { _status_text = `⚡ 即時資料 ${(rts_lag / 1000).toFixed(1)}s`; - } else if (rts_lag < 1000) { + } else if (rts_lag < 10000) { _status_text = `📶 延遲較高 ${(rts_lag / 1000).toFixed(1)}s`; } else { _status_text = `⚠️ 延遲資料 ${(rts_lag / 1000).toFixed(1)}s`; } - if (rts_lag > 1500 && !rts_replay_time) { + if (rts_lag > 15000 && !rts_replay_time) { icon_lag.style.display = ""; } else { icon_lag.style.display = "none"; } - if (!WS) { - icon_server.style.display = ""; - } else { + if (WS || Now().getTime() - last_get_eew_time < 2500) { icon_server.style.display = "none"; - } - if (!FCM) { - icon_fcm.style.display = ""; - } else { - icon_fcm.style.display = "none"; - } - if (!info.in.length) { - icon_p2p.style.display = ""; } else { - icon_p2p.style.display = "none"; + icon_server.style.display = ""; } + icon_fcm.style.display = "none"; + icon_p2p.style.display = "none"; _status.textContent = _status_text; _get_data.innerHTML = ""; if (now_time() - type_list.time < 1000) { _get_data.style.display = ""; if (now_time() - type_list.http < 1000) { const div = document.createElement("div"); - div.textContent = "🟩 Http"; - _get_data.append(div); - } - if (now_time() - type_list.p2p < 1000) { - const div = document.createElement("div"); - div.textContent = "🟦 P2P"; + div.textContent = "🟩 HTTP"; _get_data.append(div); } if (now_time() - type_list.websocket < 1000) { const div = document.createElement("div"); - div.textContent = "⬜ Websocket"; - _get_data.append(div); - } - if (now_time() - type_list.fcm < 1000) { - const div = document.createElement("div"); - div.textContent = "🟥 FCM"; + div.textContent = "⬜ WebSocket"; _get_data.append(div); } } else { @@ -240,15 +238,8 @@ setInterval(() => { setTimeout(() => controller.abort(), 2500); const _replay_time = Math.round(rts_replay_time / 1000); rts_replay_time += 1000; - const now = new Date(_replay_time * 1000); - const YYYY = now.getFullYear(); - const MM = (now.getMonth() + 1).toString().padStart(2, "0"); - const DD = now.getDate().toString().padStart(2, "0"); - const hh = now.getHours().toString().padStart(2, "0"); - const mm = now.getMinutes().toString().padStart(2, "0"); - const ss = now.getSeconds().toString().padStart(2, "0"); - const t = `${YYYY}${MM}${DD}${hh}${mm}${ss}`; - fetch(`https://api.exptech.com.tw/api/v1/trem/rts/${t}`, { signal: controller.signal }) + const t = _replay_time * 1000 + fetch(`https://${api_domain}/api/v1/trem/rts/${t}`, { signal: controller.signal }) .then(async (ans) => { ans = await ans.json(); if (!rts_replay_time) { @@ -259,14 +250,16 @@ setInterval(() => { .catch((err) => { log(err, 3, "loop", "replay_rts"); }); - fetch(`https://api.exptech.com.tw/api/v1/eq/eew/${t}?type=all`, { signal: controller.signal }) + fetch(`https://${api_domain}/api/v1/eq/eew/${t}?type=cwa`, { signal: controller.signal }) .then(async (ans_eew) => { ans_eew = await ans_eew.json(); if (!rts_replay_time) { return; } const _now = Now().getTime(); - for (const eew of ans_eew.eew) { + type_list.time = now_time(); + type_list.http = _now; + for (const eew of ans_eew) { // if (eew.type == "trem-eew") { // eew.time = eew_list[eew.number - 1].time; // eew.lat = eew_list[eew.number - 1].lat; @@ -274,7 +267,8 @@ setInterval(() => { // eew.depth = Math.round(eew_list[eew.number - 1].depth); // eew.location = "未知區域"; // } - eew.replay_timestamp = eew.timestamp; + eew.type = "eew-cwb"; + eew.replay_timestamp = eew.eq.time; eew.replay_time = eew.time; eew.time = _now - (_replay_time * 1000 - eew.time); eew.timestamp = _now - (_replay_time * 1000 - eew.timestamp); @@ -320,8 +314,9 @@ setInterval(() => { refresh_report_list(true); }, 300_000); +let is_playing = false; setInterval(() => { - if (TREM.audio.length) { + if (TREM.audio.length && !is_playing) { const audioContext = new AudioContext(); const nextAudioPath = TREM.audio.shift(); if (!source_data[nextAudioPath]) { @@ -334,8 +329,10 @@ setInterval(() => { source.connect(audioContext.destination); source.playbackRate = 1.1; source.start(); + is_playing = true; source.onended = () => { source.disconnect(); + is_playing = false; fs.readFile(path.resolve(app.getAppPath(), `./resource/audios/${nextAudioPath}.wav`), (err, data) => { source_data[nextAudioPath] = data.buffer; audioContext.close(); @@ -409,10 +406,10 @@ setInterval(() => { continue; } const _eew_location_info = eew_location_info(data); - const tr_time = _speed(data.depth, _eew_location_info.dist); + const tr_time = _speed(data.eq.depth, _eew_location_info.dist); const intensity = intensity_float_to_int(_eew_location_info.i); if (data.type == "eew-report") { - data.time = _now - (rts_replay_time - data.originTime); + data.time = _now - (rts_replay_time - data.eq.time); } if (intensity > user_max_intensity) { user_max_intensity = intensity; @@ -450,7 +447,7 @@ setInterval(() => { let p_dist = 0; let s_dist = 0; - const _time_table = time_table[findClosest(time_table_list, data.depth)]; + const _time_table = time_table[findClosest(time_table_list, data.eq.depth)]; let prev_table = null; for (const table of _time_table) { if (!p_dist && table.P > (_now - data.time) / 1000) { @@ -482,19 +479,19 @@ setInterval(() => { } if (!p_dist) { - p_dist = Math.sqrt(pow((_now - data.time) / 1000 * 7) - pow(data.depth)); + p_dist = Math.sqrt(pow((_now - data.time) / 1000 * 7) - pow(data.eq.depth)); } if (!s_dist) { - s_dist = Math.sqrt(pow((_now - data.time) / 1000 * 4) - pow(data.depth)); + s_dist = Math.sqrt(pow((_now - data.time) / 1000 * 4) - pow(data.eq.depth)); } p_dist *= 1000; s_dist *= 1000; TREM.EQ_list[key].dist = s_dist; - if (p_dist > data.depth) { + if (p_dist > data.eq.depth) { if (!TREM.EQ_list[key].p_wave) { - TREM.EQ_list[key].p_wave = L.circle([data.lat, data.lon], { + TREM.EQ_list[key].p_wave = L.circle([data.eq.lat, data.eq.lon], { color : "#00FFFF", fillColor : "transparent", radius : p_dist, @@ -505,12 +502,12 @@ setInterval(() => { TREM.EQ_list[key].p_wave.setRadius(p_dist); } } - if (s_dist < data.depth) { + if (s_dist < data.eq.depth) { if (TREM.EQ_list[key].s_wave) { TREM.EQ_list[key].s_wave.remove(); delete TREM.EQ_list[key].s_wave; } - const progress = Math.round(((_now - data.time) / 1000 / time_table[data.depth][0].S) * 100); + const progress = Math.round(((_now - data.time) / 1000 / time_table[data.eq.depth][0].S) * 100); const progress_bar = `
`; TREM.EQ_list[key].epicenterTooltip = true; TREM.EQ_list[key].epicenterIcon.bindTooltip(progress_bar, { opacity: 1, permanent: true, direction: "right", offset: [10, 0], className: "progress-tooltip" }); @@ -520,7 +517,7 @@ setInterval(() => { delete TREM.EQ_list[key].epicenterTooltip; } if (!TREM.EQ_list[key].s_wave) { - TREM.EQ_list[key].s_wave = L.circle([data.lat, data.lon], { + TREM.EQ_list[key].s_wave = L.circle([data.eq.lat, data.eq.lon], { color : (data.type == "eew-report") ? "grey" : (data.type == "eew-trem") ? "#73BF00" : (TREM.EQ_list[key].alert) ? "red" : "#FF8000", fillColor : "transparent", radius : s_dist, @@ -532,7 +529,7 @@ setInterval(() => { } if (item_disable_geojson_vt) { if (!TREM.EQ_list[key].s_wave_back) { - TREM.EQ_list[key].s_wave_back = L.circle([data.lat, data.lon], { + TREM.EQ_list[key].s_wave_back = L.circle([data.eq.lat, data.eq.lon], { color : "transparent", fillColor : (data.type == "eew-report") ? "grey" : (data.type == "eew-trem") ? "#73BF00" : (TREM.EQ_list[key].alert) ? "red" : "#FF8000", radius : s_dist, @@ -565,7 +562,7 @@ setInterval(() => { } } if (key == show_eew_id) { - TREM.eew_bounds.extend([data.lat, data.lon]); + TREM.eew_bounds.extend([data.eq.lat, data.eq.lon]); } } diff --git a/src/core/index/main.js b/src/core/index/main.js index bbaa57b9..3e643853 100644 --- a/src/core/index/main.js +++ b/src/core/index/main.js @@ -2,7 +2,6 @@ require("leaflet"); require("leaflet-edgebuffer"); require("leaflet-geojson-vt"); -fetch_eew(); const TREM = { Maps: { @@ -11,7 +10,7 @@ const TREM = { EQ_list : {}, Timers : {}, setting : { - rts_station: "H-711-11334880-12", + rts_station: "H-711-11334880", }, audio : [], rts_audio : { @@ -37,6 +36,7 @@ const TREM = { lon : 0, }, report_icon_list : {}, + report_epicenterIcon: null, size : 0, }; @@ -68,7 +68,7 @@ TREM.Maps.main.on("zoomend", () => { icon.options.iconSize = [40 + TREM.size * 3, 40 + TREM.size * 3]; } TREM.EQ_list[key].epicenterIcon.remove(); - TREM.EQ_list[key].epicenterIcon = L.marker([data.lat, data.lon], { icon: icon, zIndexOffset: 6000 }) + TREM.EQ_list[key].epicenterIcon = L.marker([data.eq.lat, data.eq.lon], { icon: icon, zIndexOffset: 6000 }) .addTo(TREM.Maps.main); if (TREM.EQ_list[key].epicenterIcon._tooltip) { TREM.EQ_list[key].epicenterIcon.bindTooltip(TREM.EQ_list[key].epicenterIcon._tooltip._content, { opacity: 1, permanent: true, direction: "right", offset: [10, 0], className: "progress-tooltip" }); diff --git a/src/core/index/rts.js b/src/core/index/rts.js index 13769368..0aef9431 100644 --- a/src/core/index/rts.js +++ b/src/core/index/rts.js @@ -34,6 +34,7 @@ let last_package_lost_time = 0; const icon_package = document.getElementById("icon-package"); const battery = document.getElementById("battery"); +battery.style.display = "none"; const detection_data = JSON.parse(fs.readFileSync(path.resolve(app.getAppPath(), "./resource/data/detection.json")).toString()); @@ -44,35 +45,79 @@ async function get_station_info() { setTimeout(() => { controller.abort(); }, 1500); - let ans = await fetch("https://data.exptech.com.tw/file/resource/station.json", { signal: controller.signal }) + let ans = await fetch("https://cdn.jsdelivr.net/gh/ExpTechTW/API@master/resource/station.json", { signal: controller.signal }) .catch((err) => void 0); if (controller.signal.aborted || !ans) { setTimeout(() => get_station_info(), 500); return; } - station = await ans.json(); + station = station_exec(await ans.json()); } catch (err) { log(err, 3, "rts", "get_station_info"); setTimeout(() => get_station_info(), 500); } } +function station_exec(station_data) { + let stations = {}; + for (let k = 0, k_ks = Object.keys(station_data), n = k_ks.length; k < n; k++) { + const station_id = k_ks[k]; + const station_ = station_data[station_id]; + const station_net = station_.net === "MS-Net" ? "H" : "L"; -function on_rts_data(data) { - console.log(data); - if (!WS) { - return; + let station_new_id = ""; + let station_code = "000"; + let Loc = ""; + let area = ""; + let Lat = 0; + let Long = 0; + + let latest = station_.info[0]; + + if (station_.info.length > 1) + for (let i = 1; i < station_.info.length; i++) { + const currentTime = new Date(station_.info[i].time); + const latestTime = new Date(latest.time); + + if (currentTime > latestTime) + latest = station_.info[i]; + } + + for (let i = 0, ks = Object.keys(region), j = ks.length; i < j; i++) { + const reg_id = ks[i]; + const reg = region[reg_id]; + + for (let r = 0, r_ks = Object.keys(reg), l = r_ks.length; r < l; r++) { + const ion_id = r_ks[r]; + const ion = reg[ion_id]; + + if (ion.code === latest.code) { + station_code = latest.code.toString(); + Loc = `${reg_id} ${ion_id}`; + area = ion.area; + Lat = latest.lat; + Long = latest.lon; + } + } + } + station_new_id = `${station_net}-${station_code}-${station_id}`; + stations[station_id] = { uuid: station_new_id, Lat, Long, Loc, area }; } + return stations; +} + +function on_rts_data(data) { + data.Alert = (Object.keys(detection_list).length !== 0); // 測試 const _now = Date.now(); - if (_now - last_get_data_time > 1500) { + if (_now - last_get_rts_time > 10000) { last_package_lost_time = _now; } - last_get_data_time = _now; + last_get_rts_time = _now; if (!last_package_lost_time) { icon_package.style.display = "none"; } else { icon_package.style.display = ""; } - if (_now - last_package_lost_time > 3000) { + if (_now - last_package_lost_time > 30000) { last_package_lost_time = 0; } let target_count = 0; @@ -100,378 +145,370 @@ function on_rts_data(data) { const list = Object.keys(TREM.EQ_list); if (data.station) { - for (const id of Object.keys(data.station)) { + for (const station_id of Object.keys(data.station)) { const icon = L.divIcon({ - className : `pga_dot pga_${data.station[id].i.toString().replace(".", "_")}`, + className : `pga_dot pga_${data.station[station_id].i.toString().replace(".", "_")}`, html : "", iconSize : [10 + TREM.size, 10 + TREM.size], }); - const info = station[id].info[0]; - - if (!station_icon[id]) { - station_icon[id] = L.marker([info.lat, info.lon], { icon: icon }) - // .bindTooltip(station_info_text, { opacity: 1 }) + if (!station_icon[station_id]) { + station_icon[station_id] = L.marker([station[station_id].Lat, station[station_id].Long], { icon: icon }) + .bindTooltip("", { opacity: 1 }) .addTo(TREM.Maps.main); } else { - station_icon[id].setIcon(icon); - // station_icon[uuid].setTooltipContent(station_info_text); + station_icon[station_id].setIcon(icon); + station_icon[uuid].setTooltipContent(""); } } - } - - // for (const uuid of Object.keys(data)) { - // if (!station[uuid]) { - // continue; - // } - // const info = station[uuid]; - // const station_data = data[uuid]; - // const intensity = intensity_float_to_int(station_data.i); - // if (data.Alert) { - // if (station_data.alert && station_data.v > max_pga) { - // max_pga = station_data.v; - // } - // } else if (station_data.v > max_pga) { - // max_pga = station_data.v; - // } - // let icon; - // if (data.Alert && station_data.alert) { - // if ((level_list[uuid] ?? 0) < station_data.v) { - // level_list[uuid] = station_data.v; - // } - // target_count++; - // if (map_style_v == "2" || map_style_v == "4") { - // let int = 2 * Math.log10(station_data.v) + 0.7; - // int = Number((int).toFixed(1)); - // icon = L.divIcon({ - // className : `pga_dot pga_${int.toString().replace(".", "_")}`, - // html : "", - // iconSize : [10 + TREM.size, 10 + TREM.size], - // }); - // } else - // if (intensity == 0) { - // icon = L.divIcon({ - // className : "pga_dot pga_intensity_0", - // html : "", - // iconSize : [10 + TREM.size, 10 + TREM.size], - // }); - // } else { - // let _up = false; - // if (!pga_up_level[uuid] || pga_up_level[uuid] < station_data.v) { - // pga_up_level[uuid] = station_data.v; - // pga_up_timestamp[uuid] = now_time(); - // } - // if (now_time() - (pga_up_timestamp[uuid] ?? 0) < 5000) { - // _up = true; - // } - // icon = L.divIcon({ - // className : `${(_up) ? "dot_max" : "dot"} intensity_${intensity}`, - // html : `${int_to_intensity(intensity)}`, - // iconSize : [20 + TREM.size, 20 + TREM.size], - // }); - // } - // } else { - // icon = L.divIcon({ - // className : `pga_dot pga_${station_data.i.toString().replace(".", "_")}`, - // html : "", - // iconSize : [10 + TREM.size, 10 + TREM.size], - // }); - // } - // if (!station_data.alert) { - // delete level_list[uuid]; - // } - // const station_info_text = `
${info.Loc}T${(station[uuid].UUID.includes("H")) ? "V" : "A"}S-Net_${uuid}
加速度${station_data.v.toFixed(1)}
震度${station_data.i.toFixed(1)}
`; - // if (map_style_v != "3") { - // if (!station_icon[uuid]) { - // station_icon[uuid] = L.marker([info.Lat, info.Long], { icon: icon }) - // .bindTooltip(station_info_text, { opacity: 1 }) - // .addTo(TREM.Maps.main); - // } else { - // station_icon[uuid].setIcon(icon); - // station_icon[uuid].setTooltipContent(station_info_text); - // } - // } - // if (station_icon[uuid]) { - // if ((list.length && !station_data.alert && !(map_style_v == "2" || map_style_v == "4")) || TREM.report_time) { - // station_icon[uuid].getElement().style.visibility = "hidden"; - // } else { - // station_icon[uuid].getElement().style.visibility = ""; - // } - // station_icon[uuid].setZIndexOffset((intensity == 0) ? Math.round(station_data.v + 5) : intensity * 10); - // } - // if (TREM.setting.rts_station.includes(uuid)) { - // rts_sation_loc = info.Loc; - // rts_sation_intensity = station_data.i; - // rts_sation_intensity_number = intensity; - // rts_sation_pga = station_data.v; - // } - // } - // if (rts_clock == null) { - // battery.style.color = "lawngreen"; - // } else { - // battery.style.color = "red"; - // } + for (const station_id of Object.keys(data.station)) { + if (!station[station_id]) { + continue; + } + const info = station[station_id]; + const station_data = data.station[station_id]; + const intensity = intensity_float_to_int(station_data.i); + if (data.Alert) { + if (station_data.alert && station_data.pga > max_pga) { + max_pga = station_data.pga; + } + } else if (station_data.pga > max_pga) { + max_pga = station_data.pga; + } + let icon; + if (data.Alert && station_data.alert) { + if ((level_list[station_id] ?? 0) < station_data.pga) { + level_list[station_id] = station_data.pga; + } + target_count++; + if (map_style_v == "2" || map_style_v == "4") { + let int = 2 * Math.log10(station_data.pga) + 0.7; + int = Number((int).toFixed(1)); + icon = L.divIcon({ + className : `pga_dot pga_${int.toString().replace(".", "_")}`, + html : "", + iconSize : [10 + TREM.size, 10 + TREM.size], + }); + } else + if (intensity == 0) { + icon = L.divIcon({ + className : "pga_dot pga_intensity_0", + html : "", + iconSize : [10 + TREM.size, 10 + TREM.size], + }); + } else { + let _up = false; + if (!pga_up_level[station_id] || pga_up_level[station_id] < station_data.pga) { + pga_up_level[station_id] = station_data.pga; + pga_up_timestamp[station_id] = now_time(); + } + if (now_time() - (pga_up_timestamp[station_id] ?? 0) < 5000) { + _up = true; + } + icon = L.divIcon({ + className : `${(_up) ? "dot_max" : "dot"} intensity_${intensity}`, + html : `${int_to_intensity(intensity)}`, + iconSize : [20 + TREM.size, 20 + TREM.size], + }); + } + } else { + icon = L.divIcon({ + className : `pga_dot pga_${station_data.i.toString().replace(".", "_")}`, + html : "", + iconSize : [10 + TREM.size, 10 + TREM.size], + }); + } + if (!station_data.alert) { + delete level_list[station_id]; + } + const station_info_text = `
${info.Loc}${info.uuid}
加速度${station_data.pga.toFixed(1)}
震度${station_data.i.toFixed(1)}
`; + if (map_style_v != "3") { + if (!station_icon[station_id]) { + station_icon[station_id] = L.marker([station_data.Lat, station_data.Long], { icon: icon }) + .bindTooltip(station_info_text, { opacity: 1 }) + .addTo(TREM.Maps.main); + } else { + station_icon[station_id].setIcon(icon); + station_icon[station_id].setTooltipContent(station_info_text); + } + } + if (station_icon[station_id]) { + if ((list.length && !station_data.alert && !(map_style_v == "2" || map_style_v == "4")) || TREM.report_time) { + station_icon[station_id].getElement().style.visibility = "hidden"; + } else { + station_icon[station_id].getElement().style.visibility = ""; + } + station_icon[station_id].setZIndexOffset((intensity == 0) ? Math.round(station_data.pga + 5) : intensity * 10); + } + if (TREM.setting.rts_station.includes(info.uuid)) { + rts_sation_loc = info.Loc; + rts_sation_intensity = station_data.i; + rts_sation_intensity_number = intensity; + rts_sation_pga = station_data.pga; + } + } + } - // if (!data.Alert) { - // level_list = {}; - // } - // document.getElementById("rts_location").textContent = rts_sation_loc; - // document.getElementById("rts_pga").textContent = `${get_lang_string("word.pga")} ${rts_sation_pga}`; - // document.getElementById("rts_intensity").textContent = `${get_lang_string("word.intensity")} ${rts_sation_intensity}`; - // const rts_intensity_level = document.getElementById("rts_intensity_level"); - // rts_intensity_level.textContent = int_to_intensity(rts_sation_intensity_number); - // rts_intensity_level.className = `intensity_center intensity_${rts_sation_intensity_number}`; - // const max_pga_text = document.getElementById("max_pga"); - // const max_intensity_text = document.getElementById("max_intensity"); - // const detection_location_1 = document.getElementById("detection_location_1"); - // const detection_location_2 = document.getElementById("detection_location_2"); - // let skip = false; - // if (max_intensity < item_rts_level) { - // skip = true; - // } - // if (data.eew) { - // if (!eew_alert_state) { - // eew_alert_state = true; - // TREM.audio.push("Warn"); - // add_info("fa-solid fa-bell fa-2x info_icon", "#FF0080", "地震檢測", "#00EC00", "請留意 中央氣象署
是否發布 地震預警", 15000); - // if (alert_timestamp && now_time() - alert_timestamp < 300_000) { - // add_info("fa-solid fa-triangle-exclamation fa-2x info_icon", "yellow", "不穩定", "#E800E8", "受到地震的影響
即時測站可能不穩定"); - // } - // alert_timestamp = now_time(); - // } - // } else { - // eew_alert_state = false; - // } - // if (data.Alert) { - // if (TREM.report_time) { - // report_off(); - // } - // if (!skip && !rts_show) { - // rts_show = true; - // show_screen("rts"); - // } - // if (max_intensity > TREM.rts_audio.intensity && TREM.rts_audio.intensity != 10) { - // const loc = detection_location[0] ?? "未知區域"; - // if (max_intensity > 3) { - // TREM.rts_audio.intensity = 10; - // if (!skip && item_audio_shindo2) { - // TREM.audio.push("Shindo2"); - // } - // const notification = new Notification("🟥 強震檢測", { - // body : `${loc}`, - // icon : "../TREM.ico", - // }); - // notification.addEventListener("click", () => { - // MainWindow.focus(); - // }); - // rts_screenshot(); - // plugin.emit("trem.rts.detection-strong"); - // } else if (max_intensity > 1) { - // TREM.rts_audio.intensity = 3; - // if (!skip && item_audio_shindo1) { - // TREM.audio.push("Shindo1"); - // } - // const notification = new Notification("🟨 震動檢測", { - // body : `${loc}`, - // icon : "../TREM.ico", - // }); - // notification.addEventListener("click", () => { - // MainWindow.focus(); - // }); - // rts_screenshot(); - // plugin.emit("trem.rts.detection-shake"); - // } else { - // TREM.rts_audio.intensity = 1; - // if (!skip && item_audio_shindo0) { - // TREM.audio.push("Shindo0"); - // } - // const notification = new Notification("🟩 弱反應", { - // body : `${loc}`, - // icon : "../TREM.ico", - // }); - // notification.addEventListener("click", () => { - // MainWindow.focus(); - // }); - // rts_screenshot(); - // plugin.emit("trem.rts.detection-weak"); - // } - // if (!rts_tts) { - // rts_tts = true; - // if (speecd_use) { - // speech.speak({ text: `${loc},偵測到晃動` }); - // } - // } - // } - // if (max_pga > TREM.rts_audio.pga && TREM.rts_audio.pga <= 200) { - // if (max_pga > 200) { - // TREM.rts_audio.pga = 250; - // if (!skip && item_audio_pga2) { - // TREM.audio.push("PGA2"); - // } - // rts_screenshot(); - // plugin.emit("trem-rts.pga-high"); - // } else if (max_pga > 8) { - // TREM.rts_audio.pga = 200; - // if (!skip && item_audio_pga1) { - // TREM.audio.push("PGA1"); - // } - // rts_screenshot(); - // plugin.emit("trem.rts.pga-low"); - // } - // } - // if (!list.length) { - // document.getElementById("eew_title_text").textContent = (max_intensity >= 4) ? get_lang_string("detection.high") : (max_intensity >= 2) ? get_lang_string("detection.middle") : get_lang_string("detection.low"); - // document.getElementById("eew_box").style.backgroundColor = (max_intensity >= 4) ? "#E80002" : (max_intensity >= 2) ? "#C79A00" : "#149A4C"; - // let _text_1 = ""; - // let _text_2 = ""; - // let count = 0; - // for (let i = 0; i < detection_location.length; i++) { - // const loc = detection_location[i]; - // if (count < 4) { - // _text_1 += `${loc}
`; - // } else { - // _text_2 += `${loc}
`; - // } - // count++; - // } - // detection_location_1.innerHTML = _text_1; - // detection_location_2.innerHTML = _text_2; - // detection_location_1.className = "detection_location_text"; - // detection_location_2.className = "detection_location_text"; - // } else { - // clear_eew_box(detection_location_1, detection_location_2); - // } - // } else { - // rts_tts = false; - // _max_intensity = 0; - // pga_up_level = {}; - // pga_up_timestamp = {}; - // rts_show = false; - // TREM.rts_audio.intensity = -1; - // TREM.rts_audio.pga = 0; - // if (!list.length) { - // document.getElementById("eew_title_text").textContent = get_lang_string("eew.null"); - // } - // max_intensity_text.textContent = ""; - // max_intensity_text.className = ""; - // if (!list.length) { - // document.getElementById("eew_box").style.backgroundColor = "#333439"; - // clear_eew_box(detection_location_1, detection_location_2); - // } - // } - // if (max_intensity > 0 && data.Alert) { - // max_intensity_text.textContent = int_to_intensity(max_intensity); - // max_intensity_text.className = `intensity_center intensity_${max_intensity}`; - // } - // max_pga_text.textContent = `${max_pga} gal`; - // max_pga_text.className = `intensity_center intensity_${(!data.Alert || max_pga < 4) ? 0 : (max_pga < 5) ? 1 : pga_to_intensity(max_pga)}`; - // const intensity_list = document.getElementById("intensity_list"); - // if (data.I) { - // i_list.data = data.I; - // i_list.time = 0; - // } else if (!i_list.time) { - // i_list.time = _now; - // } - // if (i_list.time && _now - i_list.time > 60000) { - // if (!list.length) { - // i_list.data = []; - // } - // i_list.time = 0; - // } - // if (i_list.data.length) { - // intensity_list.innerHTML = ""; - // intensity_list.style.visibility = "visible"; - // if (i_list.data.length > 8) { - // const city_I = {}; - // for (let i = 0; i < i_list.data.length; i++) { - // let loc = ""; - // for (const uuid of Object.keys(station)) { - // if (i_list.data[i].uuid.includes(uuid)) { - // loc = station[uuid].Loc; - // break; - // } - // } - // if (loc == "") { - // continue; - // } - // const _loc = loc.split(" ")[0]; - // if ((city_I[_loc] ?? -1) < i_list.data[i].intensity) { - // city_I[_loc] = i_list.data[i].intensity; - // } - // } - // const cities = Object.keys(city_I); - // const maxItems = Math.min(8, cities.length); + if (!data.Alert) { + level_list = {}; + } + document.getElementById("rts_location").textContent = rts_sation_loc; + document.getElementById("rts_pga").textContent = `${get_lang_string("word.pga")} ${rts_sation_pga}`; + document.getElementById("rts_intensity").textContent = `${get_lang_string("word.intensity")} ${rts_sation_intensity}`; + const rts_intensity_level = document.getElementById("rts_intensity_level"); + rts_intensity_level.textContent = int_to_intensity(rts_sation_intensity_number); + rts_intensity_level.className = `intensity_center intensity_${rts_sation_intensity_number}`; + const max_pga_text = document.getElementById("max_pga"); + const max_intensity_text = document.getElementById("max_intensity"); + const detection_location_1 = document.getElementById("detection_location_1"); + const detection_location_2 = document.getElementById("detection_location_2"); + let skip = false; + if (max_intensity < item_rts_level) { + skip = true; + } + if (data.eew) { + if (!eew_alert_state) { + eew_alert_state = true; + TREM.audio.push("Warn"); + add_info("fa-solid fa-bell fa-2x info_icon", "#FF0080", "地震檢測", "#00EC00", "請留意 中央氣象署
是否發布 地震預警", 15000); + if (alert_timestamp && now_time() - alert_timestamp < 300_000) { + add_info("fa-solid fa-triangle-exclamation fa-2x info_icon", "yellow", "不穩定", "#E800E8", "受到地震的影響
即時測站可能不穩定"); + } + alert_timestamp = now_time(); + } + } else { + eew_alert_state = false; + } + if (data.Alert) { + if (TREM.report_time) { + report_off(); + } + if (!skip && !rts_show) { + rts_show = true; + show_screen("rts"); + } + if (max_intensity > TREM.rts_audio.intensity && TREM.rts_audio.intensity != 10) { + const loc = detection_location[0] ?? "未知區域"; + if (max_intensity > 3) { + TREM.rts_audio.intensity = 10; + if (!skip && item_audio_shindo2) { + TREM.audio.push("Shindo2"); + } + const notification = new Notification("🟥 強震檢測", { + body : `${loc}`, + icon : "../TREM.ico", + }); + notification.addEventListener("click", () => { + MainWindow.focus(); + }); + rts_screenshot(); + plugin.emit("trem.rts.detection-strong"); + } else if (max_intensity > 1) { + TREM.rts_audio.intensity = 3; + if (!skip && item_audio_shindo1) { + TREM.audio.push("Shindo1"); + } + const notification = new Notification("🟨 震動檢測", { + body : `${loc}`, + icon : "../TREM.ico", + }); + notification.addEventListener("click", () => { + MainWindow.focus(); + }); + rts_screenshot(); + plugin.emit("trem.rts.detection-shake"); + } else { + TREM.rts_audio.intensity = 1; + if (!skip && item_audio_shindo0) { + TREM.audio.push("Shindo0"); + } + const notification = new Notification("🟩 弱反應", { + body : `${loc}`, + icon : "../TREM.ico", + }); + notification.addEventListener("click", () => { + MainWindow.focus(); + }); + rts_screenshot(); + plugin.emit("trem.rts.detection-weak"); + } + if (!rts_tts) { + rts_tts = true; + if (speecd_use) { + speech.speak({ text: `${loc},偵測到晃動` }); + } + } + } + if (max_pga > TREM.rts_audio.pga && TREM.rts_audio.pga <= 200) { + if (max_pga > 200) { + TREM.rts_audio.pga = 250; + if (!skip && item_audio_pga2) { + TREM.audio.push("PGA2"); + } + rts_screenshot(); + plugin.emit("trem-rts.pga-high"); + } else if (max_pga > 8) { + TREM.rts_audio.pga = 200; + if (!skip && item_audio_pga1) { + TREM.audio.push("PGA1"); + } + rts_screenshot(); + plugin.emit("trem.rts.pga-low"); + } + } + if (!list.length) { + document.getElementById("eew_title_text").textContent = (max_intensity >= 4) ? get_lang_string("detection.high") : (max_intensity >= 2) ? get_lang_string("detection.middle") : get_lang_string("detection.low"); + document.getElementById("eew_box").style.backgroundColor = (max_intensity >= 4) ? "#E80002" : (max_intensity >= 2) ? "#C79A00" : "#149A4C"; + let _text_1 = ""; + let _text_2 = ""; + let count = 0; + for (let i = 0; i < detection_location.length; i++) { + const loc = detection_location[i]; + if (count < 4) { + _text_1 += `${loc}
`; + } else { + _text_2 += `${loc}
`; + } + count++; + } + detection_location_1.innerHTML = _text_1; + detection_location_2.innerHTML = _text_2; + detection_location_1.className = "detection_location_text"; + detection_location_2.className = "detection_location_text"; + } else { + clear_eew_box(detection_location_1, detection_location_2); + } + } else { + rts_tts = false; + _max_intensity = 0; + pga_up_level = {}; + pga_up_timestamp = {}; + rts_show = false; + TREM.rts_audio.intensity = -1; + TREM.rts_audio.pga = 0; + if (!list.length) { + document.getElementById("eew_title_text").textContent = get_lang_string("eew.null"); + } + max_intensity_text.textContent = ""; + max_intensity_text.className = ""; + if (!list.length) { + document.getElementById("eew_box").style.backgroundColor = "#333439"; + clear_eew_box(detection_location_1, detection_location_2); + } + } + if (max_intensity > 0 && data.Alert) { + max_intensity_text.textContent = int_to_intensity(max_intensity); + max_intensity_text.className = `intensity_center intensity_${max_intensity}`; + } + max_pga_text.textContent = `${max_pga} gal`; + max_pga_text.className = `intensity_center intensity_${(!data.Alert || max_pga < 4) ? 0 : (max_pga < 5) ? 1 : pga_to_intensity(max_pga)}`; + /*const intensity_list = document.getElementById("intensity_list"); + if (data.I) { + i_list.data = data.I; + i_list.time = 0; + } else if (!i_list.time) { + i_list.time = _now; + } + if (i_list.time && _now - i_list.time > 60000) { + if (!list.length) { + i_list.data = []; + } + i_list.time = 0; + } + if (i_list.data.length) { + intensity_list.innerHTML = ""; + intensity_list.style.visibility = "visible"; + if (i_list.data.length > 8) { + const city_I = {}; + for (let i = 0; i < i_list.data.length; i++) { + let loc = ""; + for (const station_id of Object.keys(station)) { + if (i_list.data[i].uuid.includes(station_id)) { + loc = station[station_id].Loc; + break; + } + } + if (loc == "") { + continue; + } + const _loc = loc.split(" ")[0]; + if ((city_I[_loc] ?? -1) < i_list.data[i].intensity) { + city_I[_loc] = i_list.data[i].intensity; + } + } + const cities = Object.keys(city_I); + const maxItems = Math.min(8, cities.length); - // for (let i = 0; i < maxItems; i++) { - // const city = cities[i]; - // const intensity = int_to_intensity(city_I[city]); - // const intensity_list_item = document.createElement("intensity_list_item"); - // intensity_list_item.className = "intensity_list_item"; - // intensity_list_item.innerHTML = `
${intensity}
${city}
`; - // intensity_list.appendChild(intensity_list_item); - // } - // } else { - // for (let i = 0; i < i_list.data.length; i++) { - // if (i > 7) { - // break; - // } - // const intensity_list_item = document.createElement("intensity_list_item"); - // intensity_list_item.className = "intensity_list_item"; - // let loc = ""; - // for (const uuid of Object.keys(station)) { - // if (i_list.data[i].uuid.includes(uuid)) { - // loc = station[uuid].Loc; - // break; - // } - // } - // if (loc == "") { - // continue; - // } - // intensity_list_item.innerHTML = `
${int_to_intensity(i_list.data[i].intensity)}
${loc}
`; - // intensity_list.appendChild(intensity_list_item); - // } - // } - // } else { - // intensity_list.style.visibility = "hidden"; - // } - // if (list.length || data.Alert) { - // show_icon(true); - // } else if (!TREM.report_time) { - // show_icon(false); - // } - // let level = 0; - // for (const uuid of Object.keys(level_list)) { - // level += level_list[uuid]; - // } + for (let i = 0; i < maxItems; i++) { + const city = cities[i]; + const intensity = int_to_intensity(city_I[city]); + const intensity_list_item = document.createElement("intensity_list_item"); + intensity_list_item.className = "intensity_list_item"; + intensity_list_item.innerHTML = `
${intensity}
${city}
`; + intensity_list.appendChild(intensity_list_item); + } + } else { + for (let i = 0; i < i_list.data.length; i++) { + if (i > 7) { + break; + } + const intensity_list_item = document.createElement("intensity_list_item"); + intensity_list_item.className = "intensity_list_item"; + let loc = ""; + for (const station_id of Object.keys(station)) { + if (i_list.data[i].uuid.includes(station_id)) { + loc = station[station_id].Loc; + break; + } + } + if (loc == "") { + continue; + } + intensity_list_item.innerHTML = `
${int_to_intensity(i_list.data[i].intensity)}
${loc}
`; + intensity_list.appendChild(intensity_list_item); + } + } + } else { + intensity_list.style.visibility = "hidden"; + }*/ + if (list.length || data.Alert) { + show_icon(true); + } else if (!TREM.report_time) { + show_icon(false); + } + let level = 0; + for (const station_id of Object.keys(level_list)) { + level += level_list[station_id]; + } // document.getElementById("intensity_level_num").textContent = Math.round(level); // document.getElementById("intensity_level_station").textContent = target_count; - // if (!rts_replay_timestamp) { - // if (data.investigate != undefined) { - // if (data.investigate > palert_level) { - // if (item_audio_palert) { - // TREM.audio.push("palert"); - // } - // palert_level = data.investigate; - // refresh_report_list(false, { - // type : "palert", - // time : _now, - // i : palert_level, - // }); - // show_screen("palert"); - // screenshot_id = `palert_${now_time()}`; - // plugin.emit("trem.palert.on-palert", data); - // } - // palert_time = _now; - // } else { - // palert_level = -1; - // if (palert_time && _now - palert_time > 600000) { - // palert_time = 0; - // refresh_report_list(); - // } - // } - // } + if (!rts_replay_timestamp) { + if (data.investigate != undefined) { + if (data.investigate > palert_level) { + if (item_audio_palert) { + TREM.audio.push("palert"); + } + palert_level = data.investigate; + refresh_report_list(false, { + type : "palert", + time : _now, + i : palert_level, + }); + show_screen("palert"); + screenshot_id = `palert_${now_time()}`; + plugin.emit("trem.palert.on-palert", data); + } + palert_time = _now; + } else { + palert_level = -1; + if (palert_time && _now - palert_time > 600000) { + palert_time = 0; + refresh_report_list(); + } + } + } } function clear_eew_box(detection_location_1, detection_location_2) { diff --git a/src/core/index/server.js b/src/core/index/server.js index 4f84c968..186cf3f1 100644 --- a/src/core/index/server.js +++ b/src/core/index/server.js @@ -1,12 +1,5 @@ /* eslint-disable no-undef */ -const { - NOTIFICATION_RECEIVED, - NOTIFICATION_SERVICE_STARTED, - START_NOTIFICATION_SERVICE, -} = require("electron-fcm-push-receiver/src/constants"); - let WS = false; -let FCM = false; let ws; let ServerT = 0; let Reconnect = 0; @@ -15,9 +8,11 @@ let init_ = false; let sleep_state = false; let time_ntp = 0; let time_local = 0; -let last_get_data_time = Date.now(); +let last_get_eew_time = Date.now(); +let last_get_rts_time = Date.now(); -let rts_clock = null; +const api_domain = "api-" + Math.ceil(Math.random() * 2) + ".exptech.com.tw"; +const lb_domain = "lb-" + Math.ceil(Math.random() * 4) + ".exptech.com.tw"; function _server_init() { if (init_) { @@ -28,7 +23,11 @@ function _server_init() { } function close() { - ws.close(); + if (ws && ws.readyState == 1){ + ws.close(); + } + ws = null; + WS = false; } function reconnect() { @@ -44,18 +43,20 @@ function reconnect() { } function createWebSocket() { - try { - ws = new WebSocket("wss://exptech.com.tw/api"); - initEventHandle(); - } catch (e) { - reconnect(); + if(storage.getItem("key")){ + try { + ws = new WebSocket(`wss://${lb_domain}/websocket`); + initEventHandle(); + } catch (e) { + reconnect(); + } + } else { + WS = false; + log("Using http fetch", 1, "log", "~"); } } function sleep(_state = null) { - if (!WS) { - return; - } if (_state != null) { if (_state == sleep_state) { return; @@ -68,20 +69,24 @@ function sleep(_state = null) { plugin.emit("trem.core.awake"); } } + if (!WS) { + return; + } if (!_state) { last_get_data_time = Date.now(); } - ws.send(JSON.stringify({ + /*ws.send(JSON.stringify({ uuid : localStorage.UUID, function : "subscriptionService", value : ["trem-rts-v2", "trem-eew-v1", "report-trem-v1", "eew-v1", "report-v1"], key : storage.getItem("key") ?? "", addition : { "trem-rts-v2": { sleep: (_state == null) ? sleep_state : _state } }, - })); + }));*/ } function initEventHandle() { ws.onclose = () => { + if (storage.getItem("key")) add_info("fa-solid fa-satellite-dish fa-2x info_icon", "#FF0000", "連線錯誤", "#00BB00", "WebSocket 已斷線
正在使用 HTTP 連線", 5000); void 0; }; ws.onerror = () => { @@ -89,45 +94,44 @@ function initEventHandle() { }; ws.onopen = () => { const config = { - uuid : localStorage.UUID, - function : "subscriptionService", - value : ["trem-rts-v2", "trem-eew-v1", "report-trem-v1", "eew-v1", "report-v1"], - key : storage.getItem("key") ?? "", - addition : { "trem-rts-v2": { sleep: !win.isVisible() } }, + type : "start", + service : ["trem.rts", "trem.eew", "websocket.eew", "websocket.report"], + key : storage.getItem("key") ?? "", }; ws.send(JSON.stringify(config)); - sleep_state = config.addition["trem-rts-v2"].sleep; plugin.emit("trem.core.websocket-connect"); - if (!FCM) { - ipcRenderer.send(START_NOTIFICATION_SERVICE, "583094702393"); - } }; ws.onmessage = (evt) => { - if (!WS) { + if(!rts_replay_time) { time.style.color = "white"; } WS = true; ServerT = now_time(); const json = JSON.parse(evt.data); - if (json.response == "Subscription Succeeded" && json.type == undefined) { - if (rts_clock) { - clearInterval(rts_clock); - rts_clock = null; - } - if (!json.list.includes("trem-rts-v2")) { - log("rts clock start", 1, "server", "rts-clock"); - rts_clock = setInterval(async () => { - try { - const ans = await fetchDataWithRetry("https://data.exptech.com.tw/api/v1/trem/rts"); - get_data({ - type : "trem-rts", - raw : ans, - }); - } catch (err) { - log(err, 3, "server", "rts-clock"); - } - }, 1000); - } + if (json.type == "info" && json.data.code != 200) { + add_info("fa-solid fa-satellite-dish fa-2x info_icon", "#FF0000", "連線錯誤", "#00BB00", "無法註冊 WebSocket 服務
請檢查 apiKey 是否正確", 5000); + log(`Websocket reg NG: ${json.data.message}`, 3, "log", "~"); + close(); + return; + } + // if (json.type != "data" && json.type != "ntp") { + // console.log(json) + // } + if (json.type == "verify") { + const config = { + type : "start", + service : ["trem.rts", "trem.eew", "websocket.eew", "websocket.report"], + key : storage.getItem("key") ?? "", + }; + ws.send(JSON.stringify(config)); + } else if (json.type == "info" && json.data.code == 200) { + add_info("fa-solid fa-network-wired fa-2x info_icon", "#00AA00", "連線成功", "#00BB00", "已連線並註冊 WebSocket 伺服器", 5000); + log("Websocket reg OK", 1, "log", "~"); + } else if (json.type == "data" && json.data.type == "rts") { + get_data({ + type : "trem-rts", + raw : json.data.data, + }); } else if (json.type == "ntp") { time_ntp = json.time; time_local = Date.now(); @@ -164,14 +168,16 @@ function Now() { } setInterval(() => { - if (now_time() - ServerT > 15_000) { + if(!WS) return; + if (now_time() - ServerT > 120_000) { plugin.emit("trem.core.websocket-disconnect"); WS = false; time.style.color = "red"; + log("Websocket long time no got msg, timeout", 1, "log", "~"); reconnect(); if (now_time() - disconnect_info > 60_000) { disconnect_info = now_time(); - add_info("fa-solid fa-satellite-dish fa-2x info_icon", "#FF0000", "網路異常", "#00BB00", "客戶端無法與伺服器建立連線
請檢查網路狀態或稍後重試", 30000); + add_info("fa-solid fa-satellite-dish fa-2x info_icon", "#FF0000", "網路異常", "#00BB00", "WebSocket 伺服器沒有回應
請檢查網路狀態或稍後重試", 5000); } } }, 3000); @@ -214,16 +220,4 @@ function _speed(depth, distance) { Stime = distance / 4; } return { Ptime: Ptime, Stime: Stime }; -} - -ipcRenderer.on(NOTIFICATION_SERVICE_STARTED, (_, token) => { - FCM = true; - localStorage.UUID = token; -}); - -ipcRenderer.on(NOTIFICATION_RECEIVED, (_, Notification) => { - FCM = true; - if (Notification.data.Data != undefined) { - get_data(JSON.parse(Notification.data.Data), "fcm"); - } -}); \ No newline at end of file +} \ No newline at end of file diff --git a/src/core/setting/init.js b/src/core/setting/init.js index e73b0951..ecd58921 100644 --- a/src/core/setting/init.js +++ b/src/core/setting/init.js @@ -23,10 +23,10 @@ for (const btn of document.querySelectorAll("button.nav")) { } -document.getElementById("jma").checked = storage.getItem("jma") ?? true; -document.getElementById("nied").checked = storage.getItem("nied") ?? true; -document.getElementById("kma").checked = storage.getItem("kma") ?? true; -document.getElementById("scdzj").checked = storage.getItem("scdzj") ?? true; +// document.getElementById("jma").checked = storage.getItem("jma") ?? true; +// document.getElementById("nied").checked = storage.getItem("nied") ?? true; +// document.getElementById("kma").checked = storage.getItem("kma") ?? true; +// document.getElementById("scdzj").checked = storage.getItem("scdzj") ?? true; document.getElementById("show_eew").checked = storage.getItem("show_eew") ?? true; document.getElementById("show_report").checked = storage.getItem("show_report") ?? true; diff --git a/src/core/setting/setting.js b/src/core/setting/setting.js index 678eec9d..83375762 100644 --- a/src/core/setting/setting.js +++ b/src/core/setting/setting.js @@ -4,8 +4,12 @@ const town = document.getElementById("town"); const input_lat = document.getElementById("lat"); const input_lon = document.getElementById("lon"); const site = document.getElementById("site"); -const key = document.getElementById("key"); const rts_station = document.getElementById("rts_station"); +const user_email = document.getElementById("email"); +const user_pass = document.getElementById("password"); +const login_btn = document.getElementById("login"); +const logout_btn = document.getElementById("logout"); +const register_btn = document.getElementById("register"); let rts_list_data = {}; @@ -26,10 +30,10 @@ function fetch_rts_station() { setTimeout(() => { controller.abort(); }, 1500); - fetch("https://cdn.jsdelivr.net/gh/ExpTechTW/API@master/Json/earthquake/station.json", { signal: controller.signal }) + fetch("https://cdn.jsdelivr.net/gh/ExpTechTW/API@master/resource/station.json", { signal: controller.signal }) .then((ans) => ans.json()) .then((ans) => { - rts_list_data = ans; + rts_list_data = station_v1(ans); rts_list(); }) .catch((err) => { @@ -37,6 +41,53 @@ function fetch_rts_station() { setTimeout(() => fetch_rts_station(), 3000); }); } +function station_v1(station_data) { + let stations = {}; + for (let k = 0, k_ks = Object.keys(station_data), n = k_ks.length; k < n; k++) { + const station_id = k_ks[k]; + const station_ = station_data[station_id]; + const station_net = station_.net === "MS-Net" ? "H" : "L"; + + let station_new_id = ""; + let station_code = "000"; + let Loc = ""; + let area = ""; + let Lat = 0; + let Long = 0; + + let latest = station_.info[0]; + + if (station_.info.length > 1) + for (let i = 1; i < station_.info.length; i++) { + const currentTime = new Date(station_.info[i].time); + const latestTime = new Date(latest.time); + + if (currentTime > latestTime) + latest = station_.info[i]; + } + + for (let i = 0, ks = Object.keys(region), j = ks.length; i < j; i++) { + const reg_id = ks[i]; + const reg = region[reg_id]; + + for (let r = 0, r_ks = Object.keys(reg), l = r_ks.length; r < l; r++) { + const ion_id = r_ks[r]; + const ion = reg[ion_id]; + + if (ion.code === latest.code) { + station_code = latest.code.toString(); + Loc = `${reg_id} ${ion_id}`; + area = ion.area; + Lat = latest.lat; + Long = latest.lon; + } + } + } + station_new_id = `${station_net}-${station_code}-${station_id}`; + stations[station_new_id] = { uuid: station_new_id, Lat, Long, Loc, area }; + } + return stations; +} function rts_list() { const locations = {}; @@ -56,7 +107,7 @@ function rts_list() { const o = document.createElement("option"); o.value = uuid; o.textContent = `${uuid} ${c} ${t}`; - if (uuid == (storage.getItem("rts_station") ?? "H-711-11334880-12")) { + if (uuid == (storage.getItem("rts_station") ?? "H-711-11334880")) { o.selected = true; } g.appendChild(o); @@ -132,6 +183,64 @@ const updateTownSelect = () => { updateSiteField(); }; +login_display(); +function login_display(){ + user_email.disabled = storage.getItem("key") ? true : false; + user_pass.disabled = storage.getItem("key") ? true : false; + + login_btn.style.display = storage.getItem("key") ? "none" : ""; + logout_btn.style.display = storage.getItem("key") ? "" : "none"; + register_btn.style.display = storage.getItem("key") ? "none" : ""; +} + +async function login() { + try { + const client_name = localStorage.UUID.substr(0, 4); + const client_ver = app.getVersion(); + const email = user_email.value; + const pass = user_pass.value; + const resp = await fetch("https://api.exptech.com.tw/api/v3/et/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ email: email, pass: pass, name: `TREM-Lite Client [${client_name}]/TREM-Lite/${client_ver}/0.0.0` }), + }); + const ans = await resp.text(); + if (!resp.ok){ + alert(ans); + throw new Error(`${resp.status} ${ans}`); + return false; + } + storage.setItem("key", ans); + storage.setItem("reset", true); + login_display(); + return true; + } catch (err) { + log(`Login failed: ${err}`, 3, "setting", "logout"); + } +} + +async function logout() { + try { + const api_key = storage.getItem("key"); + const resp = await fetch(`https://api.exptech.com.tw/api/v3/et/logout`, { + method: "DELETE", + headers: { Authorization: `Basic ${api_key}` }, + }); + const ans = await resp.text(); + if (!resp.ok){ + alert(ans); + throw new Error(`${resp.status} ${ans}`); + return false; + } + storage.setItem("key", ""); + storage.setItem("reset", true); + login_display(); + return true; + } catch (err) { + log(`Logout failed: ${err}`, 3, "setting", "logout"); + } +} + // init for (const _city in region) { const o = document.createElement("option"); @@ -206,12 +315,6 @@ site.onchange = () => { storage.setItem("site", site.value); }; -key.value = storage.getItem("key") ?? ""; -key.onchange = () => { - storage.setItem("key", key.value); - storage.setItem("reset", true); -}; - function _onclick(id) { const state = document.getElementById(id).checked; storage.setItem(id, state); diff --git a/src/css/main.css b/src/css/main.css index 3eb1c3fc..f48b0f0b 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -282,7 +282,7 @@ body { .version_text { position: absolute; bottom: 0px; - right: 395px; + right: 432px; color: white; font-size: 12px; } @@ -437,13 +437,26 @@ body { } .location_button { + position: absolute; + bottom: 7.2px; + right: 392px; + margin: 2px; + padding: 5px; + border-radius: 5px; + color: white; + cursor: pointer; + z-index: 9999; +} + +.refresh_button { position: absolute; bottom: 7.2px; right: 355px; margin: 2px; padding: 5px; + border: 1px solid white; border-radius: 5px; - color: grey; + color: white; cursor: pointer; z-index: 9999; } diff --git a/src/css/setting.css b/src/css/setting.css index 8197ed41..7c8ee87c 100644 --- a/src/css/setting.css +++ b/src/css/setting.css @@ -385,7 +385,7 @@ button[type="checkbox"] { margin: 4px; padding: 4px 8px; border-radius: 4px; - color: var(--md-on-surface-variant); + color: var(--md-on-primary); background-color: hsl(0deg 0% 20%); outline: 1px solid transparent; font-family: var(--font); diff --git a/src/main.js b/src/main.js index 737e52e7..051d90fa 100644 --- a/src/main.js +++ b/src/main.js @@ -40,6 +40,7 @@ function createWindow() { process.env.window = MainWindow.id; require("@electron/remote/main").initialize(); require("@electron/remote/main").enable(MainWindow.webContents); + // MainWindow.webContents.openDevTools(); MainWindow.loadFile("./view/index.html"); MainWindow.setMenu(null); MainWindow.webContents.on("did-finish-load", () => { @@ -135,6 +136,7 @@ function createSettingWindow() { SettingWindow.on("close", () => { SettingWindow = null; if (MainWindow) { + MainWindow.webContents.executeJavaScript("close()"); MainWindow.webContents.reload(); } }); @@ -186,6 +188,9 @@ function trayIcon() { } function restart() { + if (MainWindow) { + MainWindow.webContents.executeJavaScript("close()"); + } TREM.relaunch(); TREM.isQuiting = true; TREM.quit(); @@ -225,6 +230,9 @@ ipcMain.on("hide", () => { TREM.on("before-quit", () => { TREM.isQuiting = true; + if (MainWindow) { + MainWindow.webContents.executeJavaScript("close()"); + } if (tray) { tray.destroy(); } diff --git a/src/package.json b/src/package.json index 35e79a4d..4d23a518 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "trem_lite", - "version": "1.10.11", + "version": "2.0.0", "description": "Taiwan Real-time Earthquake Monitoring ( 臺灣即時地震監測 )", "homepage": "https://exptech.com.tw/", "main": "main.js", diff --git a/src/resource/data/detection.json b/src/resource/data/detection.json index 47f3d620..180d7c9f 100644 --- a/src/resource/data/detection.json +++ b/src/resource/data/detection.json @@ -1 +1 @@ -{"1":[[24.94,120.95],[24.94,121.5],[25.44,121.5],[25.44,120.95]],"2":[[24.94,121.5],[24.94,122.05],[25.44,122.05],[25.44,121.5]],"3":[[24.44,120.4],[24.44,120.95],[24.94,120.95],[24.94,120.4]],"4":[[24.44,120.95],[24.44,121.5],[24.94,121.5],[24.94,120.95]],"5":[[24.44,121.5],[24.44,122.05],[24.94,122.05],[24.94,121.5]],"6":[[23.94,120.2],[23.94,120.75],[24.44,120.75],[24.44,120.2]],"7":[[23.94,120.75],[23.94,121.3],[24.44,121.3],[24.44,120.75]],"8":[[23.94,121.3],[23.94,121.85],[24.44,121.85],[24.44,121.3]],"9":[[23.44,120.1],[23.44,120.65],[23.94,120.65],[23.94,120.1]],"10":[[23.44,120.65],[23.44,121.2],[23.94,121.2],[23.94,120.65]],"11":[[23.44,121.2],[23.44,121.75],[23.94,121.75],[23.94,121.2]],"12":[[22.94,120],[22.94,120.55],[23.44,120.55],[23.44,120]],"13":[[22.94,120.55],[22.94,121.1],[23.44,121.1],[23.44,120.55]],"14":[[22.94,121.1],[22.94,121.65],[23.44,121.65],[23.44,121.1]],"15":[[22.44,120.2],[22.44,120.75],[22.94,120.75],[22.94,120.2]],"16":[[22.44,120.75],[22.44,121.3],[22.94,121.3],[22.94,120.75]],"17":[[21.94,120.5],[21.94,121.05],[22.44,121.05],[22.44,120.5]],"18":[[23.44,119.3],[23.44,119.85],[23.94,119.85],[23.94,119.3]]} \ No newline at end of file +{"0":[[25.1,121.38],[25.46,121.38],[25.46,120.89],[25.1,120.89]],"1":[[25.1,121.86],[25.46,121.86],[25.46,121.38],[25.1,121.38]],"2":[[25.1,122.35],[25.46,122.35],[25.46,121.86],[25.1,121.86]],"3":[[24.74,121.38],[25.1,121.38],[25.1,120.89],[24.74,120.89]],"4":[[24.74,121.86],[25.1,121.86],[25.1,121.38],[24.74,121.38]],"5":[[24.74,122.35],[25.1,122.35],[25.1,121.86],[24.74,121.86]],"6":[[24.38,120.89],[24.74,120.89],[24.74,120.4],[24.38,120.4]],"7":[[24.38,121.38],[24.74,121.38],[24.74,120.89],[24.38,120.89]],"8":[[24.38,121.86],[24.74,121.86],[24.74,121.38],[24.38,121.38]],"9":[[24.38,122.35],[24.74,122.35],[24.74,121.86],[24.38,121.86]],"10":[[24.02,120.4],[24.38,120.4],[24.38,119.92],[24.02,119.92]],"11":[[24.02,120.89],[24.38,120.89],[24.38,120.4],[24.02,120.4]],"12":[[24.02,121.38],[24.38,121.38],[24.38,120.89],[24.02,120.89]],"13":[[24.02,121.86],[24.38,121.86],[24.38,121.38],[24.02,121.38]],"14":[[23.66,119.92],[24.02,119.92],[24.02,119.43],[23.66,119.43]],"15":[[23.66,120.4],[24.02,120.4],[24.02,119.92],[23.66,119.92]],"16":[[23.66,120.89],[24.02,120.89],[24.02,120.4],[23.66,120.4]],"17":[[23.66,121.38],[24.02,121.38],[24.02,120.89],[23.66,120.89]],"18":[[23.66,121.86],[24.02,121.86],[24.02,121.38],[23.66,121.38]],"19":[[23.3,119.43],[23.66,119.43],[23.66,118.95],[23.3,118.95]],"20":[[23.3,119.92],[23.66,119.92],[23.66,119.43],[23.3,119.43]],"21":[[23.3,120.4],[23.66,120.4],[23.66,119.92],[23.3,119.92]],"22":[[23.3,120.89],[23.66,120.89],[23.66,120.4],[23.3,120.4]],"23":[[23.3,121.38],[23.66,121.38],[23.66,120.89],[23.3,120.89]],"24":[[23.3,121.86],[23.66,121.86],[23.66,121.38],[23.3,121.38]],"25":[[22.94,119.43],[23.3,119.43],[23.3,118.95],[22.94,118.95]],"26":[[22.94,119.92],[23.3,119.92],[23.3,119.43],[22.94,119.43]],"27":[[22.94,120.4],[23.3,120.4],[23.3,119.92],[22.94,119.92]],"28":[[22.94,120.89],[23.3,120.89],[23.3,120.4],[22.94,120.4]],"29":[[22.94,121.38],[23.3,121.38],[23.3,120.89],[22.94,120.89]],"30":[[22.94,121.86],[23.3,121.86],[23.3,121.38],[22.94,121.38]],"31":[[22.58,120.4],[22.94,120.4],[22.94,119.92],[22.58,119.92]],"32":[[22.58,120.89],[22.94,120.89],[22.94,120.4],[22.58,120.4]],"33":[[22.58,121.38],[22.94,121.38],[22.94,120.89],[22.58,120.89]],"34":[[22.58,121.86],[22.94,121.86],[22.94,121.38],[22.58,121.38]],"35":[[22.22,120.4],[22.58,120.4],[22.58,119.92],[22.22,119.92]],"36":[[22.22,120.89],[22.58,120.89],[22.58,120.4],[22.22,120.4]],"37":[[22.22,121.38],[22.58,121.38],[22.58,120.89],[22.22,120.89]],"38":[[21.86,120.89],[22.22,120.89],[22.22,120.4],[21.86,120.4]],"39":[[21.86,121.38],[22.22,121.38],[22.22,120.89],[21.86,120.89]],"40":[[21.86,121.86],[22.22,121.86],[22.22,121.38],[21.86,121.38]],"41":[[24.38,118.46],[24.74,118.46],[24.74,117.97],[24.38,117.97]],"42":[[24.38,118.95],[24.74,118.95],[24.74,118.46],[24.38,118.46]],"7735548":[[37.41,127.02],[37.41,127.57],[37.91,127.57],[37.91,127.02]],"13379360":[[29.54,106.1],[29.54,106.65],[30.14,106.65],[30.14,106.1]]} \ No newline at end of file diff --git a/src/resource/data/region.json b/src/resource/data/region.json index 8057d0fc..4edc1673 100644 --- a/src/resource/data/region.json +++ b/src/resource/data/region.json @@ -1 +1 @@ -{"基隆市":{"中正區":{"code":1,"lat":25.1407924,"lon":121.7592534,"site":1.077,"site_s":1.3466,"site_d":2.3124},"七堵區":{"code":2,"lat":25.097653,"lon":121.7165013,"site":1.866,"site_s":1.346,"site_d":2.3113},"暖暖區":{"code":3,"lat":25.1001834,"lon":121.735933,"site":1.718,"site_s":1.3462,"site_d":2.3116},"仁愛區":{"code":4,"lat":25.125069,"lon":121.736754,"site":1.348,"site_s":1.3468,"site_d":2.3126},"中山區":{"code":5,"lat":25.152899,"lon":121.729552,"site":1.268,"site_s":1.3464,"site_d":2.312},"安樂區":{"code":6,"lat":25.121176,"lon":121.7230804,"site":1.16,"site_s":1.3465,"site_d":2.3121},"信義區":{"code":7,"lat":25.1294717,"lon":121.7512671,"site":1.353,"site_s":1.3468,"site_d":2.3127}},"臺北市":{"松山區":{"code":8,"lat":25.049847,"lon":121.577241,"site":1.96,"site_s":1.9475,"site_d":2.8642},"信義區":{"code":9,"lat":25.0331574,"lon":121.5668777,"site":2.106,"site_s":1.9478,"site_d":2.8646},"大安區":{"code":10,"lat":25.02642,"lon":121.534511,"site":1.833,"site_s":1.947,"site_d":2.8635},"中山區":{"code":11,"lat":25.0642771,"lon":121.5335776,"site":1.924,"site_s":1.9468,"site_d":2.8632},"中正區":{"code":12,"lat":25.0443212,"lon":121.5247613,"site":1.944,"site_s":1.9468,"site_d":2.8632},"大同區":{"code":13,"lat":25.0661934,"lon":121.515268,"site":2,"site_s":1.9463,"site_d":2.8624},"萬華區":{"code":14,"lat":25.034839,"lon":121.4997957,"site":1.724,"site_s":1.7938,"site_d":2.2365},"文山區":{"code":15,"lat":24.98964,"lon":121.5700826,"site":1.532,"site_s":1.9463,"site_d":2.8625},"南港區":{"code":16,"lat":25.0547059,"lon":121.6066929,"site":2.268,"site_s":1.9466,"site_d":2.8629},"內湖區":{"code":17,"lat":25.06929,"lon":121.588949,"site":2.023,"site_s":1.9467,"site_d":2.8632},"士林區":{"code":18,"lat":25.0927548,"lon":121.519565,"site":1.538,"site_s":1.9457,"site_d":2.8617},"北投區":{"code":19,"lat":25.1323666,"lon":121.5029268,"site":1.534,"site_s":1.518,"site_d":2.6464}},"新北市":{"板橋區":{"code":20,"lat":25.0096156,"lon":121.4592358,"site":2.065,"site_s":1.7948,"site_d":2.2378},"三重區":{"code":21,"lat":25.0607692,"lon":121.4884178,"site":1.926,"site_s":1.7933,"site_d":2.2359},"中和區":{"code":22,"lat":24.9985208,"lon":121.5007413,"site":1.948,"site_s":1.7939,"site_d":2.2366},"永和區":{"code":23,"lat":25.0091768,"lon":121.5202731,"site":1.873,"site_s":1.7934,"site_d":2.236},"新莊區":{"code":24,"lat":25.035976,"lon":121.450478,"site":2.623,"site_s":1.7941,"site_d":2.2369},"新店區":{"code":25,"lat":24.9749713,"lon":121.5431673,"site":1.931,"site_s":1.9457,"site_d":2.8616},"樹林區":{"code":26,"lat":24.9899673,"lon":121.4246321,"site":1.443,"site_s":1.7937,"site_d":2.2363},"鶯歌區":{"code":27,"lat":24.9560294,"lon":121.3544312,"site":0.959,"site_s":1.4265,"site_d":2.9728},"三峽區":{"code":28,"lat":24.9341863,"lon":121.369083,"site":1.325,"site_s":1.4259,"site_d":2.9716},"淡水區":{"code":29,"lat":25.1696463,"lon":121.4409722,"site":1.999,"site_s":1.5195,"site_d":2.6492},"汐止區":{"code":30,"lat":25.064261,"lon":121.65869,"site":2.09,"site_s":1.945,"site_d":2.8605},"瑞芳區":{"code":31,"lat":25.1087635,"lon":121.8098935,"site":1.286,"site_s":1.3455,"site_d":2.3104},"土城區":{"code":32,"lat":24.9723361,"lon":121.4429389,"site":1.667,"site_s":1.7936,"site_d":2.2363},"蘆洲區":{"code":33,"lat":25.0847112,"lon":121.4737354,"site":1.936,"site_s":1.7927,"site_d":2.2351},"五股區":{"code":34,"lat":25.0830393,"lon":121.4380781,"site":1.541,"site_s":1.7926,"site_d":2.2351},"泰山區":{"code":35,"lat":25.059291,"lon":121.431495,"site":2.448,"site_s":1.7932,"site_d":2.2358},"林口區":{"code":36,"lat":25.0768252,"lon":121.3886134,"site":2.111,"site_s":1.792,"site_d":2.2343},"深坑區":{"code":37,"lat":25.0025007,"lon":121.615944,"site":1.542,"site_s":1.946,"site_d":2.862},"石碇區":{"code":38,"lat":24.9914859,"lon":121.6579019,"site":1.423,"site_s":1.1106,"site_d":1.4761},"坪林區":{"code":39,"lat":24.9361367,"lon":121.7117653,"site":0.93,"site_s":1.112,"site_d":1.478},"三芝區":{"code":40,"lat":25.257748,"lon":121.5009345,"site":1.412,"site_s":1.5177,"site_d":2.6459},"石門區":{"code":41,"lat":25.291248,"lon":121.567631,"site":1.406,"site_s":1.5159,"site_d":2.6429},"八里區":{"code":42,"lat":25.1537592,"lon":121.4064305,"site":2.13,"site_s":1.5188,"site_d":2.6478},"平溪區":{"code":43,"lat":25.026689,"lon":121.73819,"site":1.543,"site_s":1.1102,"site_d":1.4756},"雙溪區":{"code":44,"lat":25.0337322,"lon":121.8657341,"site":1.622,"site_s":1.3435,"site_d":2.307},"貢寮區":{"code":45,"lat":25.021812,"lon":121.910293,"site":0.954,"site_s":1.3426,"site_d":2.3055},"金山區":{"code":46,"lat":25.222241,"lon":121.636629,"site":1.586,"site_s":1.3439,"site_d":2.3077},"萬里區":{"code":47,"lat":25.178066,"lon":121.689548,"site":1.581,"site_s":1.3454,"site_d":2.3103},"烏來區":{"code":48,"lat":24.8717802,"lon":121.5478634,"site":1.164,"site_s":1.3277,"site_d":2.1825}},"桃園市":{"桃園區":{"code":49,"lat":24.993919,"lon":121.3016657,"site":1.417,"site_s":1.428,"site_d":2.9759},"中壢區":{"code":50,"lat":24.9656124,"lon":121.2249927,"site":1.536,"site_s":1.4262,"site_d":2.9722},"大溪區":{"code":51,"lat":24.880548,"lon":121.287142,"site":1.498,"site_s":1.1562,"site_d":2.1567},"楊梅區":{"code":52,"lat":24.9128508,"lon":121.1444587,"site":1.328,"site_s":1.2597,"site_d":2.4895},"蘆竹區":{"code":53,"lat":25.046925,"lon":121.295077,"site":1.858,"site_s":1.4267,"site_d":2.9732},"大園區":{"code":54,"lat":25.0638556,"lon":121.1954603,"site":1.752,"site_s":1.425,"site_d":2.9698},"龜山區":{"code":55,"lat":24.9925139,"lon":121.337824,"site":2.038,"site_s":1.4272,"site_d":2.9743},"八德區":{"code":56,"lat":24.9289862,"lon":121.2846406,"site":1.568,"site_s":1.4264,"site_d":2.9726},"龍潭區":{"code":57,"lat":24.8704855,"lon":121.2224472,"site":1.427,"site_s":1.2579,"site_d":2.4859},"平鎮區":{"code":58,"lat":24.9456694,"lon":121.2181884,"site":1.549,"site_s":1.2583,"site_d":2.4867},"新屋區":{"code":59,"lat":24.9725439,"lon":121.105533,"site":1.309,"site_s":1.2588,"site_d":2.4875},"觀音區":{"code":60,"lat":25.0276516,"lon":121.0836028,"site":1.326,"site_s":1.2575,"site_d":2.485},"復興區":{"code":61,"lat":24.8147989,"lon":121.3511305,"site":1.148,"site_s":1.158,"site_d":2.16}},"新竹市":{"東區":{"code":62,"lat":24.8051881,"lon":120.9732327,"site":2.41,"site_s":1.6228,"site_d":2.7467},"北區":{"code":63,"lat":24.8163726,"lon":120.9703141,"site":1.373,"site_s":1.6228,"site_d":2.7466},"香山區":{"code":64,"lat":24.7940445,"lon":120.9422678,"site":1.902,"site_s":1.6222,"site_d":2.7457}},"新竹縣":{"竹北市":{"code":65,"lat":24.8395807,"lon":121.0040235,"site":2.246,"site_s":1.4016,"site_d":2.5963},"竹東鎮":{"code":66,"lat":24.7366942,"lon":121.0916513,"site":1.881,"site_s":1.6991,"site_d":2.6766},"新埔鎮":{"code":67,"lat":24.8256201,"lon":121.0740799,"site":1.555,"site_s":1.4006,"site_d":2.5945},"關西鎮":{"code":68,"lat":24.7922806,"lon":121.1759547,"site":1.558,"site_s":1.6975,"site_d":2.674},"湖口鄉":{"code":69,"lat":24.9010068,"lon":121.0478749,"site":1.07,"site_s":1.4,"site_d":2.5934},"新豐鄉":{"code":70,"lat":24.9007026,"lon":120.9852313,"site":1.395,"site_s":1.4001,"site_d":2.5935},"芎林鄉":{"code":71,"lat":24.773309,"lon":121.081855,"site":1.773,"site_s":1.6998,"site_d":2.6776},"橫山鄉":{"code":72,"lat":24.7167807,"lon":121.1414985,"site":1.653,"site_s":1.6979,"site_d":2.6747},"北埔鄉":{"code":73,"lat":24.7019901,"lon":121.0563354,"site":1.797,"site_s":1.6979,"site_d":2.6748},"寶山鄉":{"code":74,"lat":24.7654715,"lon":120.9913066,"site":1.758,"site_s":1.6217,"site_d":2.7447},"峨眉鄉":{"code":75,"lat":24.6887921,"lon":121.0195946,"site":1.696,"site_s":1.6971,"site_d":2.6734},"尖石鄉":{"code":76,"lat":24.705004,"lon":121.2020864,"site":1.262,"site_s":1.6964,"site_d":2.6723},"五峰鄉":{"code":77,"lat":24.6320786,"lon":121.119596,"site":1.275,"site_s":1.6959,"site_d":2.6716}},"苗栗縣":{"苗栗市":{"code":78,"lat":24.5616772,"lon":120.8190175,"site":1.705,"site_s":1.6629,"site_d":1.9209},"苑裡鎮":{"code":79,"lat":24.4396522,"lon":120.653261,"site":1.714,"site_s":1.0962,"site_d":1.3656},"通霄鎮":{"code":80,"lat":24.4912805,"lon":120.684249,"site":1.679,"site_s":1.6588,"site_d":1.9162},"竹南鎮":{"code":81,"lat":24.6838448,"lon":120.8733503,"site":2.078,"site_s":1.6593,"site_d":1.9167},"頭份市":{"code":82,"lat":24.6865276,"lon":120.9132454,"site":1.98,"site_s":1.6193,"site_d":2.7407},"後龍鎮":{"code":83,"lat":24.613682,"lon":120.792046,"site":1.839,"site_s":1.6614,"site_d":1.9192},"卓蘭鎮":{"code":84,"lat":24.3130501,"lon":120.8245152,"site":1.196,"site_s":1.4333,"site_d":1.4093},"大湖鄉":{"code":85,"lat":24.4234081,"lon":120.8661781,"site":1.116,"site_s":0.9111,"site_d":1.4285},"公館鄉":{"code":86,"lat":24.5058646,"lon":120.8284935,"site":1.292,"site_s":1.6613,"site_d":1.919},"銅鑼鄉":{"code":87,"lat":24.4870514,"lon":120.7878718,"site":1.456,"site_s":1.6606,"site_d":1.9182},"南庄鄉":{"code":88,"lat":24.5970648,"lon":121.000339,"site":1.119,"site_s":0.9096,"site_d":1.4262},"頭屋鄉":{"code":89,"lat":24.5778158,"lon":120.8511057,"site":1.399,"site_s":1.6621,"site_d":1.92},"三義鄉":{"code":90,"lat":24.4129179,"lon":120.7702392,"site":1.239,"site_s":1.4318,"site_d":1.4078},"西湖鄉":{"code":91,"lat":24.5567613,"lon":120.7570814,"site":1.544,"site_s":1.6613,"site_d":1.9191},"造橋鄉":{"code":92,"lat":24.638552,"lon":120.8651632,"site":1.807,"site_s":1.6606,"site_d":1.9182},"三灣鄉":{"code":93,"lat":24.6531425,"lon":120.9566265,"site":1.65,"site_s":1.6586,"site_d":1.9159},"獅潭鄉":{"code":94,"lat":24.539419,"lon":120.920496,"site":1.092,"site_s":0.9109,"site_d":1.4282},"泰安鄉":{"code":95,"lat":24.4471976,"lon":120.9081718,"site":0.985,"site_s":0.9117,"site_d":1.4295}},"臺中市":{"中區":{"code":96,"lat":24.1439458,"lon":120.6794414,"site":1.639,"site_s":1.7158,"site_d":2.5822},"東區":{"code":97,"lat":24.1366469,"lon":120.7037332,"site":1.24,"site_s":1.7152,"site_d":2.5812},"南區":{"code":98,"lat":24.1171412,"lon":120.6635905,"site":1.633,"site_s":1.7154,"site_d":2.5816},"西區":{"code":99,"lat":24.1413252,"lon":120.6710753,"site":1.431,"site_s":1.7159,"site_d":2.5824},"北區":{"code":100,"lat":24.1658534,"lon":120.6822936,"site":1.211,"site_s":1.716,"site_d":2.5825},"西屯區":{"code":101,"lat":24.1658213,"lon":120.6336717,"site":1.149,"site_s":1.7167,"site_d":2.5835},"南屯區":{"code":102,"lat":24.1345298,"lon":120.6442903,"site":1.506,"site_s":1.716,"site_d":2.5825},"北屯區":{"code":103,"lat":24.1826848,"lon":120.686403,"site":1.1,"site_s":1.7158,"site_d":2.5822},"豐原區":{"code":104,"lat":24.2419087,"lon":120.7181281,"site":1.207,"site_s":1.0978,"site_d":1.3675},"東勢區":{"code":105,"lat":24.2585728,"lon":120.8279546,"site":1.631,"site_s":1.2625,"site_d":1.2266},"大甲區":{"code":106,"lat":24.349083,"lon":120.622468,"site":1.403,"site_s":1.0973,"site_d":1.3668},"清水區":{"code":107,"lat":24.2681562,"lon":120.559717,"site":1.749,"site_s":1.7132,"site_d":2.5783},"沙鹿區":{"code":108,"lat":24.2333313,"lon":120.566317,"site":1.309,"site_s":1.7141,"site_d":2.5796},"梧棲區":{"code":109,"lat":24.2549063,"lon":120.5317002,"site":1.967,"site_s":1.7129,"site_d":2.5779},"后里區":{"code":110,"lat":24.3049377,"lon":120.7107454,"site":1.192,"site_s":1.099,"site_d":1.369},"神岡區":{"code":111,"lat":24.2579749,"lon":120.6614216,"site":1.119,"site_s":1.0978,"site_d":1.3675},"潭子區":{"code":112,"lat":24.2031708,"lon":120.7228978,"site":1.289,"site_s":1.7147,"site_d":2.5805},"大雅區":{"code":113,"lat":24.2291463,"lon":120.6478436,"site":1.063,"site_s":1.7152,"site_d":2.5812},"新社區":{"code":114,"lat":24.233957,"lon":120.809416,"site":1.299,"site_s":1.2625,"site_d":1.2265},"石岡區":{"code":115,"lat":24.274898,"lon":120.7803458,"site":1.227,"site_s":1.0976,"site_d":1.3673},"外埔區":{"code":116,"lat":24.3321248,"lon":120.654334,"site":1.276,"site_s":1.0979,"site_d":1.3676},"大安區":{"code":117,"lat":24.346126,"lon":120.5866075,"site":1.383,"site_s":1.0967,"site_d":1.3661},"烏日區":{"code":118,"lat":24.104605,"lon":120.6238467,"site":1.788,"site_s":1.715,"site_d":2.581},"大肚區":{"code":119,"lat":24.1511295,"lon":120.5457643,"site":1.81,"site_s":2.7664,"site_d":3.6392},"龍井區":{"code":120,"lat":24.1924488,"lon":120.5457999,"site":1.839,"site_s":1.7142,"site_d":2.5797},"霧峰區":{"code":121,"lat":24.0613153,"lon":120.7000868,"site":1.763,"site_s":1.7135,"site_d":2.5787},"太平區":{"code":122,"lat":24.1266572,"lon":120.7185562,"site":1.193,"site_s":1.7147,"site_d":2.5805},"大里區":{"code":123,"lat":24.0994693,"lon":120.6778413,"site":1.629,"site_s":1.7148,"site_d":2.5806},"和平區":{"code":124,"lat":24.1752225,"lon":120.8835809,"site":1.222,"site_s":1.2631,"site_d":1.2271}},"彰化縣":{"彰化市":{"code":125,"lat":24.0809056,"lon":120.5422565,"site":2.055,"site_s":2.7697,"site_d":3.6436},"鹿港鎮":{"code":126,"lat":24.0572566,"lon":120.4350548,"site":2.217,"site_s":2.7651,"site_d":3.6376},"和美鎮":{"code":127,"lat":24.1085584,"lon":120.4941497,"site":1.797,"site_s":2.7673,"site_d":3.6404},"線西鄉":{"code":128,"lat":24.1306678,"lon":120.470656,"site":2.288,"site_s":2.7658,"site_d":3.6385},"伸港鄉":{"code":129,"lat":24.1596067,"lon":120.4861141,"site":2.116,"site_s":2.7652,"site_d":3.6377},"福興鄉":{"code":130,"lat":24.0478713,"lon":120.4439546,"site":2.046,"site_s":2.7654,"site_d":3.6379},"秀水鄉":{"code":131,"lat":24.035321,"lon":120.5028098,"site":2.109,"site_s":2.7674,"site_d":3.6405},"花壇鄉":{"code":132,"lat":24.0296582,"lon":120.5382578,"site":1.661,"site_s":2.7678,"site_d":3.6411},"芬園鄉":{"code":133,"lat":24.013628,"lon":120.628964,"site":1.643,"site_s":2.7652,"site_d":3.6377},"員林市":{"code":134,"lat":23.9589162,"lon":120.5743943,"site":1.692,"site_s":2.9498,"site_d":2.9917},"溪湖鎮":{"code":135,"lat":23.9664245,"lon":120.4832787,"site":2.079,"site_s":2.9498,"site_d":2.9917},"田中鎮":{"code":136,"lat":23.8614831,"lon":120.5809585,"site":1.399,"site_s":2.9521,"site_d":2.9941},"大村鄉":{"code":137,"lat":23.9934239,"lon":120.547268,"site":1.682,"site_s":2.7661,"site_d":3.6388},"埔鹽鄉":{"code":138,"lat":24.000442,"lon":120.4636578,"site":1.998,"site_s":2.7649,"site_d":3.6374},"埔心鄉":{"code":139,"lat":23.952988,"lon":120.54354,"site":1.817,"site_s":2.9506,"site_d":2.9926},"永靖鄉":{"code":140,"lat":23.9245962,"lon":120.5477204,"site":1.919,"site_s":2.952,"site_d":2.9939},"社頭鄉":{"code":141,"lat":23.8968186,"lon":120.5858074,"site":1.488,"site_s":2.9517,"site_d":2.9936},"二水鄉":{"code":142,"lat":23.8066858,"lon":120.6190203,"site":1.501,"site_s":2.9493,"site_d":2.9912},"北斗鎮":{"code":143,"lat":23.8713826,"lon":120.5218625,"site":1.957,"site_s":2.955,"site_d":2.997},"二林鎮":{"code":144,"lat":23.8998045,"lon":120.3742654,"site":2.2,"site_s":2.9479,"site_d":2.9898},"田尾鄉":{"code":145,"lat":23.8922407,"lon":120.5259709,"site":2.175,"site_s":2.9539,"site_d":2.9959},"埤頭鄉":{"code":146,"lat":23.8914618,"lon":120.4621725,"site":2.32,"site_s":2.952,"site_d":2.994},"芳苑鄉":{"code":147,"lat":23.924354,"lon":120.320389,"site":2.117,"site_s":2.9452,"site_d":2.987},"大城鄉":{"code":148,"lat":23.852314,"lon":120.3208972,"site":2.15,"site_s":2.9455,"site_d":2.9874},"竹塘鄉":{"code":149,"lat":23.8605045,"lon":120.4277961,"site":2.029,"site_s":2.9506,"site_d":2.9925},"溪州鄉":{"code":150,"lat":23.8516188,"lon":120.498976,"site":1.834,"site_s":2.9536,"site_d":2.9955}},"南投縣":{"南投市":{"code":151,"lat":23.9116414,"lon":120.6874199,"site":1.566,"site_s":1.6047,"site_d":1.9467},"埔里鎮":{"code":152,"lat":23.9665377,"lon":120.9691809,"site":1.129,"site_s":1.145,"site_d":1.299},"草屯鎮":{"code":153,"lat":23.9736845,"lon":120.6802819,"site":1.551,"site_s":1.603,"site_d":1.9445},"竹山鎮":{"code":154,"lat":23.7578635,"lon":120.6716995,"site":1.36,"site_s":1.6009,"site_d":1.9421},"集集鎮":{"code":155,"lat":23.8283683,"lon":120.7864885,"site":1.19,"site_s":1.6018,"site_d":1.9431},"名間鄉":{"code":156,"lat":23.8382161,"lon":120.702985,"site":1.467,"site_s":1.6032,"site_d":1.9448},"鹿谷鄉":{"code":157,"lat":23.7458415,"lon":120.7534428,"site":1.183,"site_s":1.3568,"site_d":2.0077},"中寮鄉":{"code":158,"lat":23.8790067,"lon":120.7660301,"site":1.647,"site_s":1.603,"site_d":1.9445},"魚池鄉":{"code":159,"lat":23.8957849,"lon":120.9356849,"site":1.003,"site_s":1.1435,"site_d":1.2972},"國姓鄉":{"code":160,"lat":24.040019,"lon":120.8575192,"site":1.079,"site_s":1.1425,"site_d":1.2962},"水里鄉":{"code":161,"lat":23.8113991,"lon":120.8560852,"site":1.004,"site_s":1.357,"site_d":2.008},"信義鄉":{"code":162,"lat":23.696797,"lon":120.854557,"site":1.236,"site_s":1.3583,"site_d":2.01},"仁愛鄉":{"code":163,"lat":24.021544,"lon":121.1320616,"site":1.207,"site_s":1.1418,"site_d":1.2954}},"雲林縣":{"斗六市":{"code":164,"lat":23.6971143,"lon":120.5269987,"site":1.924,"site_s":2.3979,"site_d":2.9279},"斗南鎮":{"code":165,"lat":23.680105,"lon":120.47772,"site":1.783,"site_s":2.396,"site_d":2.9255},"虎尾鎮":{"code":166,"lat":23.7083539,"lon":120.4451923,"site":1.997,"site_s":2.3949,"site_d":2.9242},"西螺鎮":{"code":167,"lat":23.7977736,"lon":120.465685,"site":1.751,"site_s":2.9504,"site_d":2.9923},"土庫鎮":{"code":168,"lat":23.6820621,"lon":120.3899062,"site":1.907,"site_s":2.3927,"site_d":2.9216},"北港鎮":{"code":169,"lat":23.5759236,"lon":120.302446,"site":1.797,"site_s":2.493,"site_d":2.855},"古坑鄉":{"code":170,"lat":23.6426312,"lon":120.5619595,"site":1.824,"site_s":2.3953,"site_d":2.9247},"大埤鄉":{"code":171,"lat":23.6460343,"lon":120.4314818,"site":2.071,"site_s":2.3938,"site_d":2.9228},"莿桐鄉":{"code":172,"lat":23.7610077,"lon":120.5025072,"site":1.914,"site_s":2.3953,"site_d":2.9246},"林內鄉":{"code":173,"lat":23.7562156,"lon":120.6129427,"site":1.656,"site_s":2.3939,"site_d":2.923},"二崙鄉":{"code":174,"lat":23.7711012,"lon":120.4129596,"site":1.825,"site_s":2.3927,"site_d":2.9216},"崙背鄉":{"code":175,"lat":23.7619087,"lon":120.3591424,"site":1.818,"site_s":2.3911,"site_d":2.9196},"麥寮鄉":{"code":176,"lat":23.7539853,"lon":120.2513078,"site":2.471,"site_s":2.485,"site_d":2.8458},"東勢鄉":{"code":177,"lat":23.6753034,"lon":120.2525936,"site":2.434,"site_s":2.4883,"site_d":2.8496},"褒忠鄉":{"code":178,"lat":23.691007,"lon":120.3037335,"site":2.025,"site_s":2.488,"site_d":2.8493},"臺西鄉":{"code":179,"lat":23.700477,"lon":120.1957632,"site":2.379,"site_s":2.4861,"site_d":2.8471},"元長鄉":{"code":180,"lat":23.6497447,"lon":120.3148349,"site":1.902,"site_s":2.4898,"site_d":2.8513},"四湖鄉":{"code":181,"lat":23.6378317,"lon":120.2242949,"site":2.09,"site_s":2.4889,"site_d":2.8503},"口湖鄉":{"code":182,"lat":23.5827378,"lon":120.1858552,"site":2.016,"site_s":2.4884,"site_d":2.8497},"水林鄉":{"code":183,"lat":23.5727035,"lon":120.2459507,"site":1.816,"site_s":2.4908,"site_d":2.8524}},"嘉義市":{"東區":{"code":184,"lat":23.4786578,"lon":120.4534596,"site":1.857,"site_s":2.3869,"site_d":3.0399},"西區":{"code":185,"lat":23.4646967,"lon":120.4352822,"site":2.105,"site_s":2.386,"site_d":3.0388}},"嘉義縣":{"太保市":{"code":186,"lat":23.458967,"lon":120.3323479,"site":2.013,"site_s":2.5884,"site_d":2.3895},"朴子市":{"code":187,"lat":23.4575288,"lon":120.2459226,"site":2.029,"site_s":2.5881,"site_d":2.3892},"布袋鎮":{"code":188,"lat":23.3781734,"lon":120.1669564,"site":1.768,"site_s":2.5837,"site_d":2.3851},"大林鎮":{"code":189,"lat":23.603931,"lon":120.471178,"site":2.006,"site_s":2.3935,"site_d":2.9225},"民雄鄉":{"code":190,"lat":23.5516417,"lon":120.4283616,"site":1.989,"site_s":2.3839,"site_d":3.0361},"溪口鄉":{"code":191,"lat":23.6025304,"lon":120.392323,"site":2,"site_s":2.4892,"site_d":2.8507},"新港鄉":{"code":192,"lat":23.5519744,"lon":120.3478039,"site":1.758,"site_s":2.4909,"site_d":2.8526},"六腳鄉":{"code":193,"lat":23.4940922,"lon":120.2907962,"site":1.99,"site_s":2.5884,"site_d":2.3895},"東石鄉":{"code":194,"lat":23.4587147,"lon":120.1537883,"site":2.399,"site_s":2.5843,"site_d":2.3857},"義竹鄉":{"code":195,"lat":23.3361064,"lon":120.2430475,"site":2.322,"site_s":2.5159,"site_d":3.1512},"鹿草鄉":{"code":196,"lat":23.4113835,"lon":120.3082682,"site":1.852,"site_s":2.5878,"site_d":2.3889},"水上鄉":{"code":197,"lat":23.428531,"lon":120.398035,"site":1.995,"site_s":2.384,"site_d":3.0361},"中埔鄉":{"code":198,"lat":23.425139,"lon":120.522952,"site":1.726,"site_s":2.2181,"site_d":2.5808},"竹崎鄉":{"code":199,"lat":23.5230788,"lon":120.5513988,"site":1.666,"site_s":2.2177,"site_d":2.5803},"梅山鄉":{"code":200,"lat":23.5850678,"lon":120.5554676,"site":1.421,"site_s":2.3931,"site_d":2.922},"番路鄉":{"code":201,"lat":23.4644973,"lon":120.554286,"site":1.06,"site_s":2.22,"site_d":2.583},"大埔鄉":{"code":202,"lat":23.2986941,"lon":120.5869311,"site":1.192,"site_s":1.1427,"site_d":1.9364},"阿里山鄉":{"code":203,"lat":23.4712117,"lon":120.7135217,"site":1.031,"site_s":2.2143,"site_d":2.5764}},"臺南市":{"新營區":{"code":204,"lat":23.3101426,"lon":120.3167031,"site":2.103,"site_s":2.5189,"site_d":3.1549},"鹽水區":{"code":205,"lat":23.320027,"lon":120.266097,"site":1.829,"site_s":2.517,"site_d":3.1525},"白河區":{"code":206,"lat":23.3512886,"lon":120.415752,"site":1.057,"site_s":2.5145,"site_d":3.1494},"柳營區":{"code":207,"lat":23.278395,"lon":120.311673,"site":1.788,"site_s":2.5176,"site_d":3.1532},"後壁區":{"code":208,"lat":23.3659836,"lon":120.3619362,"site":1.736,"site_s":2.5159,"site_d":3.1511},"東山區":{"code":209,"lat":23.3261625,"lon":120.4045009,"site":1.403,"site_s":2.5153,"site_d":3.1504},"麻豆區":{"code":210,"lat":23.1849449,"lon":120.2584456,"site":2.204,"site_s":2.513,"site_d":3.1475},"下營區":{"code":211,"lat":23.2356921,"lon":120.2643838,"site":1.98,"site_s":2.5151,"site_d":3.1502},"六甲區":{"code":212,"lat":23.2318098,"lon":120.3474201,"site":1.782,"site_s":2.5153,"site_d":3.1503},"官田區":{"code":213,"lat":23.1930442,"lon":120.3154967,"site":1.704,"site_s":2.5138,"site_d":3.1485},"大內區":{"code":214,"lat":23.1192073,"lon":120.3568212,"site":1.533,"site_s":1.143,"site_d":1.9369},"佳里區":{"code":215,"lat":23.1652648,"lon":120.1770306,"site":2.17,"site_s":1.8808,"site_d":2.5266},"學甲區":{"code":216,"lat":23.2304835,"lon":120.1822926,"site":2.166,"site_s":2.5126,"site_d":3.147},"西港區":{"code":217,"lat":23.1229825,"lon":120.203413,"site":2.601,"site_s":1.8823,"site_d":2.5286},"七股區":{"code":218,"lat":23.1403809,"lon":120.1391359,"site":1.977,"site_s":1.8811,"site_d":2.5271},"將軍區":{"code":219,"lat":23.19905,"lon":120.158702,"site":1.888,"site_s":2.511,"site_d":3.145},"北門區":{"code":220,"lat":23.267723,"lon":120.125445,"site":2.124,"site_s":2.5112,"site_d":3.1452},"新化區":{"code":221,"lat":23.0385411,"lon":120.310896,"site":2.087,"site_s":1.8837,"site_d":2.5306},"善化區":{"code":222,"lat":23.1324288,"lon":120.2967849,"site":1.968,"site_s":1.8815,"site_d":2.5276},"新市區":{"code":223,"lat":23.0789967,"lon":120.2951827,"site":2.416,"site_s":1.8831,"site_d":2.5297},"安定區":{"code":224,"lat":23.121593,"lon":120.237118,"site":2.829,"site_s":1.8823,"site_d":2.5287},"山上區":{"code":225,"lat":23.1036173,"lon":120.3526487,"site":1.771,"site_s":1.1428,"site_d":1.9366},"玉井區":{"code":226,"lat":23.1237866,"lon":120.4601109,"site":1.161,"site_s":1.1448,"site_d":1.94},"楠西區":{"code":227,"lat":23.174143,"lon":120.486337,"site":1.145,"site_s":1.1452,"site_d":1.9406},"南化區":{"code":228,"lat":23.042988,"lon":120.477816,"site":0.857,"site_s":1.1438,"site_d":1.9383},"左鎮區":{"code":229,"lat":23.0567783,"lon":120.408708,"site":1.569,"site_s":1.1433,"site_d":1.9374},"仁德區":{"code":230,"lat":22.97243,"lon":120.251685,"site":1.342,"site_s":1.8861,"site_d":2.5338},"歸仁區":{"code":231,"lat":22.967286,"lon":120.2940045,"site":1.751,"site_s":1.8848,"site_d":2.5321},"關廟區":{"code":232,"lat":22.9630039,"lon":120.3278144,"site":1.747,"site_s":1.8838,"site_d":2.5307},"龍崎區":{"code":233,"lat":22.9632926,"lon":120.3649712,"site":1.57,"site_s":1.0188,"site_d":2.4227},"永康區":{"code":234,"lat":23.0260699,"lon":120.2570647,"site":1.951,"site_s":1.8852,"site_d":2.5325},"東區":{"code":235,"lat":22.9802421,"lon":120.224004,"site":1.711,"site_s":1.887,"site_d":2.535},"南區":{"code":236,"lat":22.9611326,"lon":120.1885687,"site":1.486,"site_s":1.8858,"site_d":2.5334},"北區":{"code":237,"lat":22.9997522,"lon":120.2030341,"site":2.299,"site_s":1.8861,"site_d":2.5338},"安南區":{"code":238,"lat":23.0472321,"lon":120.184714,"site":2.236,"site_s":1.8845,"site_d":2.5316},"安平區":{"code":239,"lat":22.9945789,"lon":120.1688523,"site":1.888,"site_s":1.8853,"site_d":2.5327},"中西區":{"code":240,"lat":22.9922364,"lon":120.2056571,"site":2.264,"site_s":1.8863,"site_d":2.5341}},"高雄市":{"鹽埕區":{"code":241,"lat":22.6247166,"lon":120.2868098,"site":1.496,"site_s":1.5344,"site_d":1.6413},"鼓山區":{"code":242,"lat":22.636776,"lon":120.2809626,"site":1.173,"site_s":1.5341,"site_d":1.6411},"左營區":{"code":243,"lat":22.6899834,"lon":120.2950135,"site":1.399,"site_s":1.5332,"site_d":1.64},"楠梓區":{"code":244,"lat":22.7283655,"lon":120.3263681,"site":1.394,"site_s":1.5322,"site_d":1.639},"三民區":{"code":245,"lat":22.647684,"lon":120.299851,"site":1.279,"site_s":1.5343,"site_d":1.6412},"新興區":{"code":246,"lat":22.6310347,"lon":120.3101095,"site":1.565,"site_s":1.5348,"site_d":1.6418},"前金區":{"code":247,"lat":22.6275276,"lon":120.2942181,"site":1.669,"site_s":1.5345,"site_d":1.6415},"苓雅區":{"code":248,"lat":22.621759,"lon":120.312194,"site":1.436,"site_s":1.535,"site_d":1.642},"前鎮區":{"code":249,"lat":22.5865658,"lon":120.318307,"site":1.569,"site_s":1.5341,"site_d":1.641},"旗津區":{"code":250,"lat":22.5900263,"lon":120.28471,"site":1.709,"site_s":1.5339,"site_d":1.6409},"小港區":{"code":251,"lat":22.5652134,"lon":120.3380368,"site":2.106,"site_s":1.5334,"site_d":1.6403},"鳳山區":{"code":252,"lat":22.627075,"lon":120.362525,"site":1.582,"site_s":1.5337,"site_d":1.6407},"林園區":{"code":253,"lat":22.5129453,"lon":120.3946805,"site":1.319,"site_s":1.5315,"site_d":1.6382},"大寮區":{"code":254,"lat":22.6055196,"lon":120.3956199,"site":1.901,"site_s":1.5329,"site_d":1.6397},"大樹區":{"code":255,"lat":22.6839054,"lon":120.4143416,"site":1.065,"site_s":1.0887,"site_d":1.3554},"大社區":{"code":256,"lat":22.730156,"lon":120.346671,"site":1.135,"site_s":1.532,"site_d":1.6388},"仁武區":{"code":257,"lat":22.7013806,"lon":120.3479837,"site":1.14,"site_s":1.5327,"site_d":1.6396},"鳥松區":{"code":258,"lat":22.6598339,"lon":120.364363,"site":1.181,"site_s":1.5334,"site_d":1.6403},"岡山區":{"code":259,"lat":22.7974649,"lon":120.2950724,"site":1.315,"site_s":1.5303,"site_d":1.637},"橋頭區":{"code":260,"lat":22.757591,"lon":120.305809,"site":1.29,"site_s":1.5314,"site_d":1.6381},"燕巢區":{"code":261,"lat":22.7881575,"lon":120.3619685,"site":1.202,"site_s":1.0182,"site_d":2.4214},"田寮區":{"code":262,"lat":22.8698825,"lon":120.3594334,"site":1.185,"site_s":1.0189,"site_d":2.4231},"阿蓮區":{"code":263,"lat":22.8832024,"lon":120.3274131,"site":1.114,"site_s":1.8825,"site_d":2.529},"路竹區":{"code":264,"lat":22.8547435,"lon":120.2592442,"site":1.097,"site_s":1.8827,"site_d":2.5293},"湖內區":{"code":265,"lat":22.9083136,"lon":120.211713,"site":1.162,"site_s":1.8846,"site_d":2.5318},"茄萣區":{"code":266,"lat":22.9065231,"lon":120.1824729,"site":1.204,"site_s":1.8843,"site_d":2.5314},"永安區":{"code":267,"lat":22.818298,"lon":120.224189,"site":1.3,"site_s":1.8817,"site_d":2.5279},"彌陀區":{"code":268,"lat":22.7814893,"lon":120.2507011,"site":1.511,"site_s":1.5305,"site_d":1.6372},"梓官區":{"code":269,"lat":22.7606303,"lon":120.2671523,"site":1.521,"site_s":1.5312,"site_d":1.6379},"旗山區":{"code":270,"lat":22.888642,"lon":120.48349,"site":0.836,"site_s":1.0208,"site_d":2.4276},"美濃區":{"code":271,"lat":22.8947952,"lon":120.5419493,"site":0.942,"site_s":1.02,"site_d":2.4256},"六龜區":{"code":272,"lat":22.9984391,"lon":120.6327082,"site":1.12,"site_s":1.0179,"site_d":2.4207},"甲仙區":{"code":273,"lat":23.0839058,"lon":120.587695,"site":0.807,"site_s":1.1442,"site_d":1.939},"杉林區":{"code":274,"lat":22.9717391,"lon":120.540058,"site":0.997,"site_s":1.0194,"site_d":2.4241},"內門區":{"code":275,"lat":22.9428391,"lon":120.462606,"site":1.139,"site_s":1.0201,"site_d":2.426},"茂林區":{"code":276,"lat":22.886187,"lon":120.663266,"site":1.412,"site_s":0.9985,"site_d":0.9985},"桃源區":{"code":277,"lat":23.1592827,"lon":120.7641372,"site":1.182,"site_s":1.1415,"site_d":1.9344},"那瑪夏區":{"code":278,"lat":23.277092,"lon":120.720243,"site":0.951,"site_s":1.1415,"site_d":1.9343}},"屏東縣":{"屏東市":{"code":279,"lat":22.662498,"lon":120.4914295,"site":1.138,"site_s":1.0896,"site_d":1.3565},"潮州鎮":{"code":280,"lat":22.549845,"lon":120.5429633,"site":1.085,"site_s":1.0873,"site_d":1.3536},"東港鎮":{"code":281,"lat":22.4666854,"lon":120.454361,"site":1.263,"site_s":1.5296,"site_d":1.6362},"恆春鎮":{"code":282,"lat":22.0037401,"lon":120.7472461,"site":1.392,"site_s":1.657,"site_d":2.085},"萬丹鄉":{"code":283,"lat":22.5894894,"lon":120.4850182,"site":1.18,"site_s":1.0882,"site_d":1.3548},"長治鄉":{"code":284,"lat":22.676538,"lon":120.5272963,"site":1.088,"site_s":1.0893,"site_d":1.3561},"麟洛鄉":{"code":285,"lat":22.6506473,"lon":120.5272056,"site":1.077,"site_s":1.0891,"site_d":1.3558},"九如鄉":{"code":286,"lat":22.740429,"lon":120.4903298,"site":0.97,"site_s":1.0889,"site_d":1.3556},"里港鄉":{"code":287,"lat":22.7792625,"lon":120.4944974,"site":1.197,"site_s":1.0882,"site_d":1.3547},"鹽埔鄉":{"code":288,"lat":22.7543743,"lon":120.5727019,"site":1.07,"site_s":0.9987,"site_d":0.9987},"高樹鄉":{"code":289,"lat":22.8267314,"lon":120.600241,"site":1.081,"site_s":1,"site_d":1},"萬巒鄉":{"code":290,"lat":22.5726416,"lon":120.567841,"site":1.209,"site_s":1.0875,"site_d":1.3539},"內埔鄉":{"code":291,"lat":22.6120045,"lon":120.5668293,"site":1.116,"site_s":1.0881,"site_d":1.3546},"竹田鄉":{"code":292,"lat":22.584724,"lon":120.543981,"site":1.132,"site_s":1.0879,"site_d":1.3544},"新埤鄉":{"code":293,"lat":22.4701881,"lon":120.5498736,"site":1.096,"site_s":1.0858,"site_d":1.3518},"枋寮鄉":{"code":294,"lat":22.3655097,"lon":120.5934906,"site":0.949,"site_s":1.2599,"site_d":1.4042},"新園鄉":{"code":295,"lat":22.5438351,"lon":120.4614914,"site":1.36,"site_s":1.0873,"site_d":1.3537},"崁頂鄉":{"code":296,"lat":22.5147343,"lon":120.5140493,"site":1.296,"site_s":1.0868,"site_d":1.353},"林邊鄉":{"code":297,"lat":22.431504,"lon":120.5097562,"site":1.46,"site_s":1.0852,"site_d":1.351},"南州鄉":{"code":298,"lat":22.490404,"lon":120.509879,"site":1.404,"site_s":1.0863,"site_d":1.3524},"佳冬鄉":{"code":299,"lat":22.419209,"lon":120.5524196,"site":1.274,"site_s":1.0849,"site_d":1.3506},"琉球鄉":{"code":300,"lat":22.348635,"lon":120.3827309,"site":1.632,"site_s":1.5275,"site_d":1.634},"車城鄉":{"code":301,"lat":22.0739409,"lon":120.714276,"site":1.045,"site_s":1.6548,"site_d":2.0822},"滿州鄉":{"code":302,"lat":22.020813,"lon":120.838632,"site":1.427,"site_s":1.6545,"site_d":2.0818},"枋山鄉":{"code":303,"lat":22.2639616,"lon":120.6524803,"site":1.363,"site_s":1.2609,"site_d":1.4053},"三地門鄉":{"code":304,"lat":22.7162015,"lon":120.6541301,"site":1.433,"site_s":0.9979,"site_d":0.9979},"霧臺鄉":{"code":305,"lat":22.7490518,"lon":120.7282593,"site":1.401,"site_s":0.9975,"site_d":0.9975},"瑪家鄉":{"code":306,"lat":22.7086763,"lon":120.6494041,"site":1.39,"site_s":0.9978,"site_d":0.9978},"泰武鄉":{"code":307,"lat":22.5919045,"lon":120.6319498,"site":1.084,"site_s":1.0869,"site_d":1.3532},"來義鄉":{"code":308,"lat":22.5261844,"lon":120.6315782,"site":0.774,"site_s":1.0861,"site_d":1.3521},"春日鄉":{"code":309,"lat":22.3710005,"lon":120.6290908,"site":0.837,"site_s":1.2606,"site_d":1.405},"獅子鄉":{"code":310,"lat":22.201775,"lon":120.705438,"site":1.205,"site_s":1.6512,"site_d":2.0776},"牡丹鄉":{"code":311,"lat":22.1261502,"lon":120.7743059,"site":1.17,"site_s":1.6534,"site_d":2.0804}},"臺東縣":{"臺東市":{"code":312,"lat":22.7548208,"lon":121.1465131,"site":1.532,"site_s":1.1479,"site_d":1.2229},"成功鎮":{"code":313,"lat":23.1050697,"lon":121.3808747,"site":1.6,"site_s":1.6645,"site_d":2.1652},"關山鎮":{"code":314,"lat":23.0474453,"lon":121.1630554,"site":1.417,"site_s":1.6664,"site_d":2.1676},"卑南鄉":{"code":315,"lat":22.7827393,"lon":121.0870294,"site":1.334,"site_s":1.1467,"site_d":1.2216},"鹿野鄉":{"code":316,"lat":22.9393083,"lon":121.1519859,"site":1.252,"site_s":1.1443,"site_d":1.2191},"池上鄉":{"code":317,"lat":23.1223101,"lon":121.2151887,"site":1.338,"site_s":1.669,"site_d":2.171},"東河鄉":{"code":318,"lat":22.9689404,"lon":121.3028937,"site":1.657,"site_s":1.664,"site_d":2.1644},"長濱鄉":{"code":319,"lat":23.3149961,"lon":121.4514207,"site":1.513,"site_s":1.2512,"site_d":1.4697},"太麻里鄉":{"code":320,"lat":22.615548,"lon":121.007607,"site":1.462,"site_s":1.1442,"site_d":1.2189},"大武鄉":{"code":321,"lat":22.340518,"lon":120.890073,"site":1.203,"site_s":1.266,"site_d":1.411},"綠島鄉":{"code":322,"lat":22.6658421,"lon":121.4705314,"site":1.287,"site_s":1.1418,"site_d":1.2164},"海端鄉":{"code":323,"lat":23.102057,"lon":121.176541,"site":1.228,"site_s":1.6678,"site_d":2.1695},"延平鄉":{"code":324,"lat":22.9025753,"lon":121.0860671,"site":1.198,"site_s":1.1448,"site_d":1.2196},"金峰鄉":{"code":325,"lat":22.5946397,"lon":120.9607096,"site":1.328,"site_s":1.1433,"site_d":1.218},"達仁鄉":{"code":326,"lat":22.296818,"lon":120.882973,"site":1.06,"site_s":1.265,"site_d":1.4099},"蘭嶼鄉":{"code":327,"lat":22.0244984,"lon":121.5560627,"site":2.15,"site_s":1.2508,"site_d":1.3941}},"花蓮縣":{"花蓮市":{"code":328,"lat":23.9820651,"lon":121.6067705,"site":1.433,"site_s":1.5194,"site_d":1.5864},"鳳林鎮":{"code":329,"lat":23.7447637,"lon":121.4515822,"site":1.379,"site_s":1.9153,"site_d":1.8274},"玉里鎮":{"code":330,"lat":23.335527,"lon":121.315197,"site":0.956,"site_s":1.254,"site_d":1.473},"新城鄉":{"code":331,"lat":24.0392994,"lon":121.6041173,"site":1.215,"site_s":1.519,"site_d":1.5859},"吉安鄉":{"code":332,"lat":23.9729455,"lon":121.5636438,"site":1.37,"site_s":1.5185,"site_d":1.5855},"壽豐鄉":{"code":333,"lat":23.8703424,"lon":121.5088259,"site":1.496,"site_s":1.5157,"site_d":1.5825},"光復鄉":{"code":334,"lat":23.669342,"lon":121.4233065,"site":1.396,"site_s":1.918,"site_d":1.83},"豐濱鄉":{"code":335,"lat":23.6012024,"lon":121.5211488,"site":1.223,"site_s":1.9142,"site_d":1.8264},"瑞穗鄉":{"code":336,"lat":23.4964553,"lon":121.3757788,"site":1.091,"site_s":1.2503,"site_d":1.4686},"富里鄉":{"code":337,"lat":23.1794845,"lon":121.250233,"site":1.263,"site_s":1.6671,"site_d":2.1685},"秀林鄉":{"code":338,"lat":24.1185835,"lon":121.6248326,"site":1.364,"site_s":1.5169,"site_d":1.5838},"萬榮鄉":{"code":339,"lat":23.714875,"lon":121.4109617,"site":1.794,"site_s":1.9164,"site_d":1.8285},"卓溪鄉":{"code":340,"lat":23.346478,"lon":121.303451,"site":1.004,"site_s":1.2537,"site_d":1.4726}},"宜蘭縣":{"宜蘭市":{"code":341,"lat":24.7520373,"lon":121.7531493,"site":1.609,"site_s":1.8492,"site_d":2.7708},"羅東鎮":{"code":342,"lat":24.6769245,"lon":121.7669529,"site":1.601,"site_s":1.8483,"site_d":2.7694},"蘇澳鎮":{"code":343,"lat":24.594315,"lon":121.8421903,"site":1.573,"site_s":2.421,"site_d":2.381},"頭城鎮":{"code":344,"lat":24.8548387,"lon":121.8213189,"site":0.733,"site_s":1.1095,"site_d":1.4747},"礁溪鄉":{"code":345,"lat":24.8234257,"lon":121.7711725,"site":0.949,"site_s":1.847,"site_d":2.7675},"壯圍鄉":{"code":346,"lat":24.746832,"lon":121.785759,"site":1.702,"site_s":1.8491,"site_d":2.7707},"員山鄉":{"code":347,"lat":24.7433944,"lon":121.7232538,"site":1.179,"site_s":1.8488,"site_d":2.7701},"冬山鄉":{"code":348,"lat":24.634338,"lon":121.792851,"site":1.387,"site_s":2.4185,"site_d":2.3785},"五結鄉":{"code":349,"lat":24.684772,"lon":121.7982898,"site":1.519,"site_s":1.8482,"site_d":2.7693},"三星鄉":{"code":350,"lat":24.665483,"lon":121.654047,"site":0.833,"site_s":1.3289,"site_d":2.1846},"大同鄉":{"code":351,"lat":24.677412,"lon":121.6090927,"site":1.188,"site_s":1.3296,"site_d":2.1858},"南澳鄉":{"code":352,"lat":24.465996,"lon":121.803714,"site":1.514,"site_s":2.4154,"site_d":2.3755}},"澎湖縣":{"馬公市":{"code":353,"lat":23.566159,"lon":119.578692,"site":2.42,"site_s":0.9998,"site_d":0.9998},"湖西鄉":{"code":354,"lat":23.584072,"lon":119.6528318,"site":2.42,"site_s":0.9986,"site_d":0.9986},"白沙鄉":{"code":355,"lat":23.666538,"lon":119.598639,"site":2.42,"site_s":0.9982,"site_d":0.9982},"西嶼鄉":{"code":356,"lat":23.601088,"lon":119.5069847,"site":2.42,"site_s":0.9989,"site_d":0.9989},"望安鄉":{"code":357,"lat":23.3576577,"lon":119.500894,"site":2.42,"site_s":0.9962,"site_d":0.9962},"七美鄉":{"code":358,"lat":23.2067107,"lon":119.4244825,"site":2.42,"site_s":0.9933,"site_d":0.9933}},"金門縣":{"金城鎮":{"code":359,"lat":24.432824,"lon":118.320697,"site_s":0.9999,"site_d":0.9999},"金沙鎮":{"code":360,"lat":24.488898,"lon":118.413132,"site_s":0.9983,"site_d":0.9983},"金湖鎮":{"code":361,"lat":24.4414641,"lon":118.4171018,"site_s":0.9984,"site_d":0.9984},"金寧鄉":{"code":362,"lat":24.450966,"lon":118.334887,"site_s":0.9996,"site_d":0.9996},"烈嶼鄉":{"code":363,"lat":24.4295409,"lon":118.2445892,"site_s":0.9988,"site_d":0.9988},"烏坵鄉":{"code":364,"lat":24.9887062,"lon":119.4531826,"site_s":0.98,"site_d":0.98}},"連江縣":{"南竿鄉":{"code":365,"lat":26.1529312,"lon":119.9387995,"site_s":0.9998,"site_d":0.9998},"北竿鄉":{"code":366,"lat":26.223938,"lon":119.997139,"site_s":0.9986,"site_d":0.9986},"莒光鄉":{"code":367,"lat":25.9687384,"lon":119.9369689,"site_s":0.9967,"site_d":0.9967},"東引鄉":{"code":368,"lat":26.3672636,"lon":120.4898789,"site_s":0.9909,"site_d":0.9909}}} \ No newline at end of file +{"基隆市":{"中正區":{"code":202,"lat":25.1407924,"lon":121.7592534,"site":1.077,"area":"基隆市東部"},"七堵區":{"code":206,"lat":25.097653,"lon":121.7165013,"site":1.866,"area":"基隆市西部"},"暖暖區":{"code":205,"lat":25.1001834,"lon":121.735933,"site":1.718,"area":"基隆市東部"},"仁愛區":{"code":200,"lat":25.125069,"lon":121.736754,"site":1.348,"area":"基隆市東部"},"中山區":{"code":203,"lat":25.152899,"lon":121.729552,"site":1.268,"area":"基隆市西部"},"安樂區":{"code":204,"lat":25.121176,"lon":121.7230804,"site":1.16,"area":"基隆市西部"},"信義區":{"code":201,"lat":25.1294717,"lon":121.7512671,"site":1.353,"area":"基隆市東部"}},"臺北市":{"松山區":{"code":105,"lat":25.049847,"lon":121.577241,"site":1.96,"area":"臺北市南部"},"信義區":{"code":110,"lat":25.0331574,"lon":121.5668777,"site":2.106,"area":"臺北市南部"},"大安區":{"code":106,"lat":25.02642,"lon":121.534511,"site":1.833,"area":"臺北市南部"},"中山區":{"code":104,"lat":25.0642771,"lon":121.5335776,"site":1.924,"area":"臺北市南部"},"中正區":{"code":100,"lat":25.0443212,"lon":121.5247613,"site":1.944,"area":"臺北市南部"},"大同區":{"code":103,"lat":25.0661934,"lon":121.515268,"site":2,"area":"臺北市南部"},"萬華區":{"code":108,"lat":25.034839,"lon":121.4997957,"site":1.724,"area":"臺北市南部"},"文山區":{"code":116,"lat":24.98964,"lon":121.5700826,"site":1.532,"area":"臺北市南部"},"南港區":{"code":115,"lat":25.0547059,"lon":121.6066929,"site":2.268,"area":"臺北市南部"},"內湖區":{"code":114,"lat":25.06929,"lon":121.588949,"site":2.023,"area":"臺北市北部"},"士林區":{"code":111,"lat":25.0927548,"lon":121.519565,"site":1.538,"area":"臺北市北部"},"北投區":{"code":112,"lat":25.1323666,"lon":121.5029268,"site":1.534,"area":"臺北市北部"}},"新北市":{"板橋區":{"code":220,"lat":25.0096156,"lon":121.4592358,"site":2.065,"area":"新北市北部"},"三重區":{"code":241,"lat":25.0607692,"lon":121.4884178,"site":1.926,"area":"新北市北部"},"中和區":{"code":235,"lat":24.9985208,"lon":121.5007413,"site":1.948,"area":"新北市北部"},"永和區":{"code":234,"lat":25.0091768,"lon":121.5202731,"site":1.873,"area":"新北市北部"},"新莊區":{"code":242,"lat":25.035976,"lon":121.450478,"site":2.623,"area":"新北市北部"},"新店區":{"code":231,"lat":24.9749713,"lon":121.5431673,"site":1.931,"area":"新北市南部"},"樹林區":{"code":238,"lat":24.9899673,"lon":121.4246321,"site":1.443,"area":"新北市北部"},"鶯歌區":{"code":239,"lat":24.9560294,"lon":121.3544312,"site":0.959,"area":"新北市北部"},"三峽區":{"code":237,"lat":24.9341863,"lon":121.369083,"site":1.325,"area":"新北市南部"},"淡水區":{"code":251,"lat":25.1696463,"lon":121.4409722,"site":1.999,"area":"新北市北部"},"汐止區":{"code":221,"lat":25.064261,"lon":121.65869,"site":2.09,"area":"新北市北部"},"瑞芳區":{"code":224,"lat":25.1087635,"lon":121.8098935,"site":1.286,"area":"新北市北部"},"土城區":{"code":236,"lat":24.9723361,"lon":121.4429389,"site":1.667,"area":"新北市北部"},"蘆洲區":{"code":247,"lat":25.0847112,"lon":121.4737354,"site":1.936,"area":"新北市北部"},"五股區":{"code":248,"lat":25.0830393,"lon":121.4380781,"site":1.541,"area":"新北市北部"},"泰山區":{"code":243,"lat":25.059291,"lon":121.431495,"site":2.448,"area":"新北市北部"},"林口區":{"code":244,"lat":25.0768252,"lon":121.3886134,"site":2.111,"area":"新北市北部"},"深坑區":{"code":222,"lat":25.0025007,"lon":121.615944,"site":1.542,"area":"新北市北部"},"石碇區":{"code":223,"lat":24.9914859,"lon":121.6579019,"site":1.423,"area":"新北市南部"},"坪林區":{"code":232,"lat":24.9361367,"lon":121.7117653,"site":0.93,"area":"新北市南部"},"三芝區":{"code":252,"lat":25.257748,"lon":121.5009345,"site":1.412,"area":"新北市北部"},"石門區":{"code":253,"lat":25.291248,"lon":121.567631,"site":1.406,"area":"新北市北部"},"八里區":{"code":249,"lat":25.1537592,"lon":121.4064305,"site":2.13,"area":"新北市北部"},"平溪區":{"code":226,"lat":25.026689,"lon":121.73819,"site":1.543,"area":"新北市北部"},"雙溪區":{"code":227,"lat":25.0337322,"lon":121.8657341,"site":1.622,"area":"新北市北部"},"貢寮區":{"code":228,"lat":25.021812,"lon":121.910293,"site":0.954,"area":"新北市北部"},"金山區":{"code":208,"lat":25.222241,"lon":121.636629,"site":1.586,"area":"新北市北部"},"萬里區":{"code":207,"lat":25.178066,"lon":121.689548,"site":1.581,"area":"新北市北部"},"烏來區":{"code":233,"lat":24.8717802,"lon":121.5478634,"site":1.164,"area":"新北市南部"}},"桃園市":{"桃園區":{"code":330,"lat":24.993919,"lon":121.3016657,"site":1.417,"area":"桃園市北部"},"中壢區":{"code":320,"lat":24.9656124,"lon":121.2249927,"site":1.536,"area":"桃園市北部"},"大溪區":{"code":335,"lat":24.880548,"lon":121.287142,"site":1.498,"area":"桃園市南部"},"楊梅區":{"code":326,"lat":24.9128508,"lon":121.1444587,"site":1.328,"area":"桃園市南部"},"蘆竹區":{"code":338,"lat":25.046925,"lon":121.295077,"site":1.858,"area":"桃園市北部"},"大園區":{"code":337,"lat":25.0638556,"lon":121.1954603,"site":1.752,"area":"桃園市北部"},"龜山區":{"code":333,"lat":24.9925139,"lon":121.337824,"site":2.038,"area":"桃園市北部"},"八德區":{"code":334,"lat":24.9289862,"lon":121.2846406,"site":1.568,"area":"桃園市北部"},"龍潭區":{"code":325,"lat":24.8704855,"lon":121.2224472,"site":1.427,"area":"桃園市南部"},"平鎮區":{"code":324,"lat":24.9456694,"lon":121.2181884,"site":1.549,"area":"桃園市南部"},"新屋區":{"code":327,"lat":24.9725439,"lon":121.105533,"site":1.309,"area":"桃園市北部"},"觀音區":{"code":328,"lat":25.0276516,"lon":121.0836028,"site":1.326,"area":"桃園市北部"},"復興區":{"code":336,"lat":24.8147989,"lon":121.3511305,"site":1.148,"area":"桃園市南部"}},"新竹市":{"東區":{"code":301,"lat":24.8051881,"lon":120.9732327,"site":2.41,"area":"新竹市東部"},"北區":{"code":300,"lat":24.8163726,"lon":120.9703141,"site":1.373,"area":"新竹市西部"},"香山區":{"code":300,"lat":24.7940445,"lon":120.9422678,"site":1.902,"area":"新竹市西部"}},"新竹縣":{"竹北市":{"code":302,"lat":24.8395807,"lon":121.0040235,"site":2.246,"area":"新竹縣北部"},"竹東鎮":{"code":310,"lat":24.7366942,"lon":121.0916513,"site":1.881,"area":"新竹縣北部"},"新埔鎮":{"code":305,"lat":24.8256201,"lon":121.0740799,"site":1.555,"area":"新竹縣北部"},"關西鎮":{"code":306,"lat":24.7922806,"lon":121.1759547,"site":1.558,"area":"新竹縣北部"},"湖口鄉":{"code":303,"lat":24.9010068,"lon":121.0478749,"site":1.07,"area":"新竹縣北部"},"新豐鄉":{"code":304,"lat":24.9007026,"lon":120.9852313,"site":1.395,"area":"新竹縣北部"},"芎林鄉":{"code":307,"lat":24.773309,"lon":121.081855,"site":1.773,"area":"新竹縣北部"},"橫山鄉":{"code":312,"lat":24.7167807,"lon":121.1414985,"site":1.653,"area":"新竹縣南部"},"北埔鄉":{"code":314,"lat":24.7019901,"lon":121.0563354,"site":1.797,"area":"新竹縣南部"},"寶山鄉":{"code":308,"lat":24.7654715,"lon":120.9913066,"site":1.758,"area":"新竹縣北部"},"峨眉鄉":{"code":315,"lat":24.6887921,"lon":121.0195946,"site":1.696,"area":"新竹縣南部"},"尖石鄉":{"code":313,"lat":24.705004,"lon":121.2020864,"site":1.262,"area":"新竹縣南部"},"五峰鄉":{"code":311,"lat":24.6320786,"lon":121.119596,"site":1.275,"area":"新竹縣南部"}},"苗栗縣":{"苗栗市":{"code":360,"lat":24.5616772,"lon":120.8190175,"site":1.705,"area":"苗栗縣北部"},"苑裡鎮":{"code":358,"lat":24.4396522,"lon":120.653261,"site":1.714,"area":"苗栗縣北部"},"通霄鎮":{"code":357,"lat":24.4912805,"lon":120.684249,"site":1.679,"area":"苗栗縣北部"},"竹南鎮":{"code":350,"lat":24.6838448,"lon":120.8733503,"site":2.078,"area":"苗栗縣北部"},"頭份市":{"code":351,"lat":24.6865276,"lon":120.9132454,"site":1.98,"area":"苗栗縣北部"},"後龍鎮":{"code":356,"lat":24.613682,"lon":120.792046,"site":1.839,"area":"苗栗縣北部"},"卓蘭鎮":{"code":369,"lat":24.3130501,"lon":120.8245152,"site":1.196,"area":"苗栗縣南部"},"大湖鄉":{"code":364,"lat":24.4234081,"lon":120.8661781,"site":1.116,"area":"苗栗縣南部"},"公館鄉":{"code":363,"lat":24.5058646,"lon":120.8284935,"site":1.292,"area":"苗栗縣南部"},"銅鑼鄉":{"code":366,"lat":24.4870514,"lon":120.7878718,"site":1.456,"area":"苗栗縣南部"},"南庄鄉":{"code":353,"lat":24.5970648,"lon":121.000339,"site":1.119,"area":"苗栗縣北部"},"頭屋鄉":{"code":362,"lat":24.5778158,"lon":120.8511057,"site":1.399,"area":"苗栗縣北部"},"三義鄉":{"code":367,"lat":24.4129179,"lon":120.7702392,"site":1.239,"area":"苗栗縣南部"},"西湖鄉":{"code":368,"lat":24.5567613,"lon":120.7570814,"site":1.544,"area":"苗栗縣北部"},"造橋鄉":{"code":361,"lat":24.638552,"lon":120.8651632,"site":1.807,"area":"苗栗縣北部"},"三灣鄉":{"code":352,"lat":24.6531425,"lon":120.9566265,"site":1.65,"area":"苗栗縣北部"},"獅潭鄉":{"code":354,"lat":24.539419,"lon":120.920496,"site":1.092,"area":"苗栗縣北部"},"泰安鄉":{"code":365,"lat":24.4471976,"lon":120.9081718,"site":0.985,"area":"苗栗縣南部"}},"臺中市":{"中區":{"code":400,"lat":24.1439458,"lon":120.6794414,"site":1.639,"area":"臺中市西部"},"東區":{"code":401,"lat":24.1366469,"lon":120.7037332,"site":1.24,"area":"臺中市西部"},"南區":{"code":402,"lat":24.1171412,"lon":120.6635905,"site":1.633,"area":"臺中市西部"},"西區":{"code":403,"lat":24.1413252,"lon":120.6710753,"site":1.431,"area":"臺中市西部"},"北區":{"code":404,"lat":24.1658534,"lon":120.6822936,"site":1.211,"area":"臺中市西部"},"西屯區":{"code":407,"lat":24.1658213,"lon":120.6336717,"site":1.149,"area":"臺中市西部"},"南屯區":{"code":408,"lat":24.1345298,"lon":120.6442903,"site":1.506,"area":"臺中市西部"},"北屯區":{"code":406,"lat":24.1826848,"lon":120.686403,"site":1.1,"area":"臺中市西部"},"豐原區":{"code":420,"lat":24.2419087,"lon":120.7181281,"site":1.207,"area":"臺中市西部"},"東勢區":{"code":423,"lat":24.2585728,"lon":120.8279546,"site":1.631,"area":"臺中市西部"},"大甲區":{"code":437,"lat":24.349083,"lon":120.622468,"site":1.403,"area":"臺中市西部"},"清水區":{"code":436,"lat":24.2681562,"lon":120.559717,"site":1.749,"area":"臺中市西部"},"沙鹿區":{"code":433,"lat":24.2333313,"lon":120.566317,"site":1.309,"area":"臺中市西部"},"梧棲區":{"code":435,"lat":24.2549063,"lon":120.5317002,"site":1.967,"area":"臺中市西部"},"后里區":{"code":421,"lat":24.3049377,"lon":120.7107454,"site":1.192,"area":"臺中市西部"},"神岡區":{"code":429,"lat":24.2579749,"lon":120.6614216,"site":1.119,"area":"臺中市西部"},"潭子區":{"code":427,"lat":24.2031708,"lon":120.7228978,"site":1.289,"area":"臺中市西部"},"大雅區":{"code":428,"lat":24.2291463,"lon":120.6478436,"site":1.063,"area":"臺中市西部"},"新社區":{"code":426,"lat":24.233957,"lon":120.809416,"site":1.299,"area":"臺中市西部"},"石岡區":{"code":422,"lat":24.274898,"lon":120.7803458,"site":1.227,"area":"臺中市西部"},"外埔區":{"code":438,"lat":24.3321248,"lon":120.654334,"site":1.276,"area":"臺中市西部"},"大安區":{"code":439,"lat":24.346126,"lon":120.5866075,"site":1.383,"area":"臺中市西部"},"烏日區":{"code":414,"lat":24.104605,"lon":120.6238467,"site":1.788,"area":"臺中市西部"},"大肚區":{"code":432,"lat":24.1511295,"lon":120.5457643,"site":1.81,"area":"臺中市西部"},"龍井區":{"code":434,"lat":24.1924488,"lon":120.5457999,"site":1.839,"area":"臺中市西部"},"霧峰區":{"code":413,"lat":24.0613153,"lon":120.7000868,"site":1.763,"area":"臺中市西部"},"太平區":{"code":411,"lat":24.1266572,"lon":120.7185562,"site":1.193,"area":"臺中市西部"},"大里區":{"code":412,"lat":24.0994693,"lon":120.6778413,"site":1.629,"area":"臺中市西部"},"和平區":{"code":424,"lat":24.1752225,"lon":120.8835809,"site":1.222,"area":"臺中市東部"}},"彰化縣":{"彰化市":{"code":500,"lat":24.0809056,"lon":120.5422565,"site":2.055,"area":"彰化縣北部"},"鹿港鎮":{"code":505,"lat":24.0572566,"lon":120.4350548,"site":2.217,"area":"彰化縣北部"},"和美鎮":{"code":508,"lat":24.1085584,"lon":120.4941497,"site":1.797,"area":"彰化縣北部"},"線西鄉":{"code":507,"lat":24.1306678,"lon":120.470656,"site":2.288,"area":"彰化縣北部"},"伸港鄉":{"code":509,"lat":24.1596067,"lon":120.4861141,"site":2.116,"area":"彰化縣北部"},"福興鄉":{"code":506,"lat":24.0478713,"lon":120.4439546,"site":2.046,"area":"彰化縣北部"},"秀水鄉":{"code":504,"lat":24.035321,"lon":120.5028098,"site":2.109,"area":"彰化縣北部"},"花壇鄉":{"code":503,"lat":24.0296582,"lon":120.5382578,"site":1.661,"area":"彰化縣北部"},"芬園鄉":{"code":502,"lat":24.013628,"lon":120.628964,"site":1.643,"area":"彰化縣北部"},"員林市":{"code":510,"lat":23.9589162,"lon":120.5743943,"site":1.692,"area":"彰化縣南部"},"溪湖鎮":{"code":514,"lat":23.9664245,"lon":120.4832787,"site":2.079,"area":"彰化縣南部"},"田中鎮":{"code":520,"lat":23.8614831,"lon":120.5809585,"site":1.399,"area":"彰化縣南部"},"大村鄉":{"code":515,"lat":23.9934239,"lon":120.547268,"site":1.682,"area":"彰化縣北部"},"埔鹽鄉":{"code":516,"lat":24.000442,"lon":120.4636578,"site":1.998,"area":"彰化縣北部"},"埔心鄉":{"code":513,"lat":23.952988,"lon":120.54354,"site":1.817,"area":"彰化縣南部"},"永靖鄉":{"code":512,"lat":23.9245962,"lon":120.5477204,"site":1.919,"area":"彰化縣南部"},"社頭鄉":{"code":511,"lat":23.8968186,"lon":120.5858074,"site":1.488,"area":"彰化縣南部"},"二水鄉":{"code":530,"lat":23.8066858,"lon":120.6190203,"site":1.501,"area":"彰化縣南部"},"北斗鎮":{"code":521,"lat":23.8713826,"lon":120.5218625,"site":1.957,"area":"彰化縣南部"},"二林鎮":{"code":526,"lat":23.8998045,"lon":120.3742654,"site":2.2,"area":"彰化縣南部"},"田尾鄉":{"code":522,"lat":23.8922407,"lon":120.5259709,"site":2.175,"area":"彰化縣南部"},"埤頭鄉":{"code":523,"lat":23.8914618,"lon":120.4621725,"site":2.32,"area":"彰化縣南部"},"芳苑鄉":{"code":528,"lat":23.924354,"lon":120.320389,"site":2.117,"area":"彰化縣南部"},"大城鄉":{"code":527,"lat":23.852314,"lon":120.3208972,"site":2.15,"area":"彰化縣南部"},"竹塘鄉":{"code":525,"lat":23.8605045,"lon":120.4277961,"site":2.029,"area":"彰化縣南部"},"溪州鄉":{"code":524,"lat":23.8516188,"lon":120.498976,"site":1.834,"area":"彰化縣南部"}},"南投縣":{"南投市":{"code":540,"lat":23.9116414,"lon":120.6874199,"site":1.566,"area":"南投縣西部"},"埔里鎮":{"code":545,"lat":23.9665377,"lon":120.9691809,"site":1.129,"area":"南投縣西部"},"草屯鎮":{"code":542,"lat":23.9736845,"lon":120.6802819,"site":1.551,"area":"南投縣西部"},"竹山鎮":{"code":557,"lat":23.7578635,"lon":120.6716995,"site":1.36,"area":"南投縣西部"},"集集鎮":{"code":552,"lat":23.8283683,"lon":120.7864885,"site":1.19,"area":"南投縣西部"},"名間鄉":{"code":551,"lat":23.8382161,"lon":120.702985,"site":1.467,"area":"南投縣西部"},"鹿谷鄉":{"code":558,"lat":23.7458415,"lon":120.7534428,"site":1.183,"area":"南投縣西部"},"中寮鄉":{"code":541,"lat":23.8790067,"lon":120.7660301,"site":1.647,"area":"南投縣西部"},"魚池鄉":{"code":555,"lat":23.8957849,"lon":120.9356849,"site":1.003,"area":"南投縣西部"},"國姓鄉":{"code":544,"lat":24.040019,"lon":120.8575192,"site":1.079,"area":"南投縣西部"},"水里鄉":{"code":553,"lat":23.8113991,"lon":120.8560852,"site":1.004,"area":"南投縣西部"},"信義鄉":{"code":556,"lat":23.696797,"lon":120.854557,"site":1.236,"area":"南投縣東部"},"仁愛鄉":{"code":546,"lat":24.021544,"lon":121.1320616,"site":1.207,"area":"南投縣東部"}},"雲林縣":{"斗六市":{"code":640,"lat":23.6971143,"lon":120.5269987,"site":1.924,"area":"雲林縣東部"},"斗南鎮":{"code":630,"lat":23.680105,"lon":120.47772,"site":1.783,"area":"雲林縣東部"},"虎尾鎮":{"code":632,"lat":23.7083539,"lon":120.4451923,"site":1.997,"area":"雲林縣東部"},"西螺鎮":{"code":648,"lat":23.7977736,"lon":120.465685,"site":1.751,"area":"雲林縣東部"},"土庫鎮":{"code":633,"lat":23.6820621,"lon":120.3899062,"site":1.907,"area":"雲林縣西部"},"北港鎮":{"code":651,"lat":23.5759236,"lon":120.302446,"site":1.797,"area":"雲林縣西部"},"古坑鄉":{"code":646,"lat":23.6426312,"lon":120.5619595,"site":1.824,"area":"雲林縣東部"},"大埤鄉":{"code":631,"lat":23.6460343,"lon":120.4314818,"site":2.071,"area":"雲林縣東部"},"莿桐鄉":{"code":647,"lat":23.7610077,"lon":120.5025072,"site":1.914,"area":"雲林縣東部"},"林內鄉":{"code":643,"lat":23.7562156,"lon":120.6129427,"site":1.656,"area":"雲林縣東部"},"二崙鄉":{"code":649,"lat":23.7711012,"lon":120.4129596,"site":1.825,"area":"雲林縣西部"},"崙背鄉":{"code":637,"lat":23.7619087,"lon":120.3591424,"site":1.818,"area":"雲林縣西部"},"麥寮鄉":{"code":638,"lat":23.7539853,"lon":120.2513078,"site":2.471,"area":"雲林縣西部"},"東勢鄉":{"code":635,"lat":23.6753034,"lon":120.2525936,"site":2.434,"area":"雲林縣西部"},"褒忠鄉":{"code":634,"lat":23.691007,"lon":120.3037335,"site":2.025,"area":"雲林縣西部"},"臺西鄉":{"code":636,"lat":23.700477,"lon":120.1957632,"site":2.379,"area":"雲林縣西部"},"元長鄉":{"code":655,"lat":23.6497447,"lon":120.3148349,"site":1.902,"area":"雲林縣西部"},"四湖鄉":{"code":654,"lat":23.6378317,"lon":120.2242949,"site":2.09,"area":"雲林縣西部"},"口湖鄉":{"code":653,"lat":23.5827378,"lon":120.1858552,"site":2.016,"area":"雲林縣西部"},"水林鄉":{"code":652,"lat":23.5727035,"lon":120.2459507,"site":1.816,"area":"雲林縣西部"}},"嘉義市":{"東區":{"code":600,"lat":23.4786578,"lon":120.4534596,"site":1.857,"area":"嘉義市東部"},"西區":{"code":601,"lat":23.4646967,"lon":120.4352822,"site":2.105,"area":"嘉義市西部"}},"嘉義縣":{"太保市":{"code":612,"lat":23.458967,"lon":120.3323479,"site":2.013,"area":"嘉義縣西部"},"朴子市":{"code":613,"lat":23.4575288,"lon":120.2459226,"site":2.029,"area":"嘉義縣西部"},"布袋鎮":{"code":625,"lat":23.3781734,"lon":120.1669564,"site":1.768,"area":"嘉義縣西部"},"大林鎮":{"code":622,"lat":23.603931,"lon":120.471178,"site":2.006,"area":"嘉義縣西部"},"民雄鄉":{"code":621,"lat":23.5516417,"lon":120.4283616,"site":1.989,"area":"嘉義縣西部"},"溪口鄉":{"code":623,"lat":23.6025304,"lon":120.392323,"site":2,"area":"嘉義縣西部"},"新港鄉":{"code":616,"lat":23.5519744,"lon":120.3478039,"site":1.758,"area":"嘉義縣西部"},"六腳鄉":{"code":615,"lat":23.4940922,"lon":120.2907962,"site":1.99,"area":"嘉義縣西部"},"東石鄉":{"code":614,"lat":23.4587147,"lon":120.1537883,"site":2.399,"area":"嘉義縣西部"},"義竹鄉":{"code":624,"lat":23.3361064,"lon":120.2430475,"site":2.322,"area":"嘉義縣西部"},"鹿草鄉":{"code":611,"lat":23.4113835,"lon":120.3082682,"site":1.852,"area":"嘉義縣西部"},"水上鄉":{"code":608,"lat":23.428531,"lon":120.398035,"site":1.995,"area":"嘉義縣西部"},"中埔鄉":{"code":606,"lat":23.425139,"lon":120.522952,"site":1.726,"area":"嘉義縣東部"},"竹崎鄉":{"code":604,"lat":23.5230788,"lon":120.5513988,"site":1.666,"area":"嘉義縣東部"},"梅山鄉":{"code":603,"lat":23.5850678,"lon":120.5554676,"site":1.421,"area":"嘉義縣東部"},"番路鄉":{"code":602,"lat":23.4644973,"lon":120.554286,"site":1.06,"area":"嘉義縣東部"},"大埔鄉":{"code":607,"lat":23.2986941,"lon":120.5869311,"site":1.192,"area":"嘉義縣東部"},"阿里山鄉":{"code":605,"lat":23.4712117,"lon":120.7135217,"site":1.031,"area":"嘉義縣東部"}},"臺南市":{"新營區":{"code":730,"lat":23.3101426,"lon":120.3167031,"site":2.103,"area":"臺南市北部"},"鹽水區":{"code":737,"lat":23.320027,"lon":120.266097,"site":1.829,"area":"臺南市北部"},"白河區":{"code":732,"lat":23.3512886,"lon":120.415752,"site":1.057,"area":"臺南市北部"},"柳營區":{"code":736,"lat":23.278395,"lon":120.311673,"site":1.788,"area":"臺南市北部"},"後壁區":{"code":731,"lat":23.3659836,"lon":120.3619362,"site":1.736,"area":"臺南市北部"},"東山區":{"code":733,"lat":23.3261625,"lon":120.4045009,"site":1.403,"area":"臺南市北部"},"麻豆區":{"code":721,"lat":23.1849449,"lon":120.2584456,"site":2.204,"area":"臺南市北部"},"下營區":{"code":735,"lat":23.2356921,"lon":120.2643838,"site":1.98,"area":"臺南市北部"},"六甲區":{"code":734,"lat":23.2318098,"lon":120.3474201,"site":1.782,"area":"臺南市北部"},"官田區":{"code":720,"lat":23.1930442,"lon":120.3154967,"site":1.704,"area":"臺南市北部"},"大內區":{"code":742,"lat":23.1192073,"lon":120.3568212,"site":1.533,"area":"臺南市南部"},"佳里區":{"code":722,"lat":23.1652648,"lon":120.1770306,"site":2.17,"area":"臺南市北部"},"學甲區":{"code":726,"lat":23.2304835,"lon":120.1822926,"site":2.166,"area":"臺南市北部"},"西港區":{"code":723,"lat":23.1229825,"lon":120.203413,"site":2.601,"area":"臺南市南部"},"七股區":{"code":724,"lat":23.1403809,"lon":120.1391359,"site":1.977,"area":"臺南市南部"},"將軍區":{"code":725,"lat":23.19905,"lon":120.158702,"site":1.888,"area":"臺南市北部"},"北門區":{"code":727,"lat":23.267723,"lon":120.125445,"site":2.124,"area":"臺南市北部"},"新化區":{"code":712,"lat":23.0385411,"lon":120.310896,"site":2.087,"area":"臺南市南部"},"善化區":{"code":741,"lat":23.1324288,"lon":120.2967849,"site":1.968,"area":"臺南市北部"},"新市區":{"code":744,"lat":23.0789967,"lon":120.2951827,"site":2.416,"area":"臺南市南部"},"安定區":{"code":745,"lat":23.121593,"lon":120.237118,"site":2.829,"area":"臺南市南部"},"山上區":{"code":743,"lat":23.1036173,"lon":120.3526487,"site":1.771,"area":"臺南市南部"},"玉井區":{"code":714,"lat":23.1237866,"lon":120.4601109,"site":1.161,"area":"臺南市南部"},"楠西區":{"code":715,"lat":23.174143,"lon":120.486337,"site":1.145,"area":"臺南市北部"},"南化區":{"code":716,"lat":23.042988,"lon":120.477816,"site":0.857,"area":"臺南市南部"},"左鎮區":{"code":713,"lat":23.0567783,"lon":120.408708,"site":1.569,"area":"臺南市南部"},"仁德區":{"code":717,"lat":22.97243,"lon":120.251685,"site":1.342,"area":"臺南市南部"},"歸仁區":{"code":711,"lat":22.967286,"lon":120.2940045,"site":1.751,"area":"臺南市南部"},"關廟區":{"code":718,"lat":22.9630039,"lon":120.3278144,"site":1.747,"area":"臺南市南部"},"龍崎區":{"code":719,"lat":22.9632926,"lon":120.3649712,"site":1.57,"area":"臺南市南部"},"永康區":{"code":710,"lat":23.0260699,"lon":120.2570647,"site":1.951,"area":"臺南市南部"},"東區":{"code":701,"lat":22.9802421,"lon":120.224004,"site":1.711,"area":"臺南市南部"},"南區":{"code":702,"lat":22.9611326,"lon":120.1885687,"site":1.486,"area":"臺南市南部"},"北區":{"code":704,"lat":22.9997522,"lon":120.2030341,"site":2.299,"area":"臺南市南部"},"安南區":{"code":709,"lat":23.0472321,"lon":120.184714,"site":2.236,"area":"臺南市南部"},"安平區":{"code":708,"lat":22.9945789,"lon":120.1688523,"site":1.888,"area":"臺南市南部"},"中西區":{"code":700,"lat":22.9922364,"lon":120.2056571,"site":2.264,"area":"臺南市南部"}},"高雄市":{"鹽埕區":{"code":803,"lat":22.6247166,"lon":120.2868098,"site":1.496,"area":"高雄市西部"},"鼓山區":{"code":804,"lat":22.636776,"lon":120.2809626,"site":1.173,"area":"高雄市西部"},"左營區":{"code":813,"lat":22.6899834,"lon":120.2950135,"site":1.399,"area":"高雄市西部"},"楠梓區":{"code":811,"lat":22.7283655,"lon":120.3263681,"site":1.394,"area":"高雄市西部"},"三民區":{"code":807,"lat":22.647684,"lon":120.299851,"site":1.279,"area":"高雄市西部"},"新興區":{"code":800,"lat":22.6310347,"lon":120.3101095,"site":1.565,"area":"高雄市西部"},"前金區":{"code":801,"lat":22.6275276,"lon":120.2942181,"site":1.669,"area":"高雄市西部"},"苓雅區":{"code":802,"lat":22.621759,"lon":120.312194,"site":1.436,"area":"高雄市西部"},"前鎮區":{"code":806,"lat":22.5865658,"lon":120.318307,"site":1.569,"area":"高雄市西部"},"旗津區":{"code":805,"lat":22.5900263,"lon":120.28471,"site":1.709,"area":"高雄市西部"},"小港區":{"code":812,"lat":22.5652134,"lon":120.3380368,"site":2.106,"area":"高雄市西部"},"鳳山區":{"code":830,"lat":22.627075,"lon":120.362525,"site":1.582,"area":"高雄市西部"},"林園區":{"code":832,"lat":22.5129453,"lon":120.3946805,"site":1.319,"area":"高雄市西部"},"大寮區":{"code":831,"lat":22.6055196,"lon":120.3956199,"site":1.901,"area":"高雄市西部"},"大樹區":{"code":840,"lat":22.6839054,"lon":120.4143416,"site":1.065,"area":"高雄市西部"},"大社區":{"code":815,"lat":22.730156,"lon":120.346671,"site":1.135,"area":"高雄市西部"},"仁武區":{"code":814,"lat":22.7013806,"lon":120.3479837,"site":1.14,"area":"高雄市西部"},"鳥松區":{"code":833,"lat":22.6598339,"lon":120.364363,"site":1.181,"area":"高雄市西部"},"岡山區":{"code":820,"lat":22.7974649,"lon":120.2950724,"site":1.315,"area":"高雄市西部"},"橋頭區":{"code":825,"lat":22.757591,"lon":120.305809,"site":1.29,"area":"高雄市西部"},"燕巢區":{"code":824,"lat":22.7881575,"lon":120.3619685,"site":1.202,"area":"高雄市西部"},"田寮區":{"code":823,"lat":22.8698825,"lon":120.3594334,"site":1.185,"area":"高雄市西部"},"阿蓮區":{"code":822,"lat":22.8832024,"lon":120.3274131,"site":1.114,"area":"高雄市西部"},"路竹區":{"code":821,"lat":22.8547435,"lon":120.2592442,"site":1.097,"area":"高雄市西部"},"湖內區":{"code":829,"lat":22.9083136,"lon":120.211713,"site":1.162,"area":"高雄市西部"},"茄萣區":{"code":852,"lat":22.9065231,"lon":120.1824729,"site":1.204,"area":"高雄市西部"},"永安區":{"code":828,"lat":22.818298,"lon":120.224189,"site":1.3,"area":"高雄市西部"},"彌陀區":{"code":827,"lat":22.7814893,"lon":120.2507011,"site":1.511,"area":"高雄市西部"},"梓官區":{"code":826,"lat":22.7606303,"lon":120.2671523,"site":1.521,"area":"高雄市西部"},"旗山區":{"code":842,"lat":22.888642,"lon":120.48349,"site":0.836,"area":"高雄市中部"},"美濃區":{"code":843,"lat":22.8947952,"lon":120.5419493,"site":0.942,"area":"高雄市中部"},"六龜區":{"code":844,"lat":22.9984391,"lon":120.6327082,"site":1.12,"area":"高雄市東部"},"甲仙區":{"code":847,"lat":23.0839058,"lon":120.587695,"site":0.807,"area":"高雄市東部"},"杉林區":{"code":846,"lat":22.9717391,"lon":120.540058,"site":0.997,"area":"高雄市中部"},"內門區":{"code":845,"lat":22.9428391,"lon":120.462606,"site":1.139,"area":"高雄市中部"},"茂林區":{"code":851,"lat":22.886187,"lon":120.663266,"site":1.412,"area":"高雄市東部"},"桃源區":{"code":848,"lat":23.1592827,"lon":120.7641372,"site":1.182,"area":"高雄市東部"},"那瑪夏區":{"code":849,"lat":23.277092,"lon":120.720243,"site":0.951,"area":"高雄市東部"}},"屏東縣":{"屏東市":{"code":900,"lat":22.662498,"lon":120.4914295,"site":1.138,"area":"屏東縣北部"},"潮州鎮":{"code":920,"lat":22.549845,"lon":120.5429633,"site":1.085,"area":"屏東縣北部"},"東港鎮":{"code":928,"lat":22.4666854,"lon":120.454361,"site":1.263,"area":"屏東縣中部"},"恆春鎮":{"code":946,"lat":22.0037401,"lon":120.7472461,"site":1.392,"area":"屏東縣南部"},"萬丹鄉":{"code":913,"lat":22.5894894,"lon":120.4850182,"site":1.18,"area":"屏東縣北部"},"長治鄉":{"code":908,"lat":22.676538,"lon":120.5272963,"site":1.088,"area":"屏東縣北部"},"麟洛鄉":{"code":909,"lat":22.6506473,"lon":120.5272056,"site":1.077,"area":"屏東縣北部"},"九如鄉":{"code":904,"lat":22.740429,"lon":120.4903298,"site":0.97,"area":"屏東縣北部"},"里港鄉":{"code":905,"lat":22.7792625,"lon":120.4944974,"site":1.197,"area":"屏東縣北部"},"鹽埔鄉":{"code":907,"lat":22.7543743,"lon":120.5727019,"site":1.07,"area":"屏東縣北部"},"高樹鄉":{"code":906,"lat":22.8267314,"lon":120.600241,"site":1.081,"area":"屏東縣北部"},"萬巒鄉":{"code":923,"lat":22.5726416,"lon":120.567841,"site":1.209,"area":"屏東縣北部"},"內埔鄉":{"code":912,"lat":22.6120045,"lon":120.5668293,"site":1.116,"area":"屏東縣北部"},"竹田鄉":{"code":911,"lat":22.584724,"lon":120.543981,"site":1.132,"area":"屏東縣北部"},"新埤鄉":{"code":925,"lat":22.4701881,"lon":120.5498736,"site":1.096,"area":"屏東縣中部"},"枋寮鄉":{"code":940,"lat":22.3655097,"lon":120.5934906,"site":0.949,"area":"屏東縣北部"},"新園鄉":{"code":932,"lat":22.5438351,"lon":120.4614914,"site":1.36,"area":"屏東縣中部"},"崁頂鄉":{"code":924,"lat":22.5147343,"lon":120.5140493,"site":1.296,"area":"屏東縣北部"},"林邊鄉":{"code":927,"lat":22.431504,"lon":120.5097562,"site":1.46,"area":"屏東縣中部"},"南州鄉":{"code":926,"lat":22.490404,"lon":120.509879,"site":1.404,"area":"屏東縣中部"},"佳冬鄉":{"code":931,"lat":22.419209,"lon":120.5524196,"site":1.274,"area":"屏東縣中部"},"琉球鄉":{"code":929,"lat":22.348635,"lon":120.3827309,"site":1.632,"area":"屏東縣西部"},"車城鄉":{"code":944,"lat":22.0739409,"lon":120.714276,"site":1.045,"area":"屏東縣南部"},"滿州鄉":{"code":947,"lat":22.020813,"lon":120.838632,"site":1.427,"area":"屏東縣南部"},"枋山鄉":{"code":941,"lat":22.2639616,"lon":120.6524803,"site":1.363,"area":"屏東縣南部"},"三地門鄉":{"code":901,"lat":22.7162015,"lon":120.6541301,"site":1.433,"area":"屏東縣北部"},"霧臺鄉":{"code":902,"lat":22.7490518,"lon":120.7282593,"site":1.401,"area":"屏東縣北部"},"瑪家鄉":{"code":903,"lat":22.7086763,"lon":120.6494041,"site":1.39,"area":"屏東縣北部"},"泰武鄉":{"code":921,"lat":22.5919045,"lon":120.6319498,"site":1.084,"area":"屏東縣北部"},"來義鄉":{"code":922,"lat":22.5261844,"lon":120.6315782,"site":0.774,"area":"屏東縣中部"},"春日鄉":{"code":942,"lat":22.3710005,"lon":120.6290908,"site":0.837,"area":"屏東縣中部"},"獅子鄉":{"code":943,"lat":22.201775,"lon":120.705438,"site":1.205,"area":"屏東縣南部"},"牡丹鄉":{"code":945,"lat":22.1261502,"lon":120.7743059,"site":1.17,"area":"屏東縣南部"}},"臺東縣":{"臺東市":{"code":950,"lat":22.7548208,"lon":121.1465131,"site":1.532,"area":"臺東縣中部"},"成功鎮":{"code":961,"lat":23.1050697,"lon":121.3808747,"site":1.6,"area":"臺東縣北部"},"關山鎮":{"code":956,"lat":23.0474453,"lon":121.1630554,"site":1.417,"area":"臺東縣北部"},"卑南鄉":{"code":954,"lat":22.7827393,"lon":121.0870294,"site":1.334,"area":"臺東縣北部"},"鹿野鄉":{"code":955,"lat":22.9393083,"lon":121.1519859,"site":1.252,"area":"臺東縣北部"},"池上鄉":{"code":958,"lat":23.1223101,"lon":121.2151887,"site":1.338,"area":"臺東縣北部"},"東河鄉":{"code":959,"lat":22.9689404,"lon":121.3028937,"site":1.657,"area":"臺東縣北部"},"長濱鄉":{"code":962,"lat":23.3149961,"lon":121.4514207,"site":1.513,"area":"臺東縣北部"},"太麻里鄉":{"code":963,"lat":22.615548,"lon":121.007607,"site":1.462,"area":"臺東縣南部"},"大武鄉":{"code":965,"lat":22.340518,"lon":120.890073,"site":1.203,"area":"臺東縣南部"},"綠島鄉":{"code":951,"lat":22.6658421,"lon":121.4705314,"site":1.287,"area":"臺東縣東部"},"海端鄉":{"code":957,"lat":23.102057,"lon":121.176541,"site":1.228,"area":"臺東縣北部"},"延平鄉":{"code":953,"lat":22.9025753,"lon":121.0860671,"site":1.198,"area":"臺東縣中部"},"金峰鄉":{"code":964,"lat":22.5946397,"lon":120.9607096,"site":1.328,"area":"臺東縣南部"},"達仁鄉":{"code":966,"lat":22.296818,"lon":120.882973,"site":1.06,"area":"臺東縣南部"},"蘭嶼鄉":{"code":952,"lat":22.0244984,"lon":121.5560627,"site":2.15,"area":"臺東縣東部"}},"花蓮縣":{"花蓮市":{"code":970,"lat":23.9820651,"lon":121.6067705,"site":1.433,"area":"花蓮縣北部"},"鳳林鎮":{"code":975,"lat":23.7447637,"lon":121.4515822,"site":1.379,"area":"花蓮縣中部"},"玉里鎮":{"code":981,"lat":23.335527,"lon":121.315197,"site":0.956,"area":"花蓮縣南部"},"新城鄉":{"code":971,"lat":24.0392994,"lon":121.6041173,"site":1.215,"area":"花蓮縣北部"},"吉安鄉":{"code":973,"lat":23.9729455,"lon":121.5636438,"site":1.37,"area":"花蓮縣北部"},"壽豐鄉":{"code":974,"lat":23.8703424,"lon":121.5088259,"site":1.496,"area":"花蓮縣中部"},"光復鄉":{"code":976,"lat":23.669342,"lon":121.4233065,"site":1.396,"area":"花蓮縣中部"},"豐濱鄉":{"code":977,"lat":23.6012024,"lon":121.5211488,"site":1.223,"area":"花蓮縣中部"},"瑞穗鄉":{"code":978,"lat":23.4964553,"lon":121.3757788,"site":1.091,"area":"花蓮縣中部"},"富里鄉":{"code":983,"lat":23.1794845,"lon":121.250233,"site":1.263,"area":"花蓮縣南部"},"秀林鄉":{"code":972,"lat":24.1185835,"lon":121.6248326,"site":1.364,"area":"花蓮縣北部"},"萬榮鄉":{"code":979,"lat":23.714875,"lon":121.4109617,"site":1.794,"area":"花蓮縣中部"},"卓溪鄉":{"code":982,"lat":23.346478,"lon":121.303451,"site":1.004,"area":"花蓮縣南部"}},"宜蘭縣":{"宜蘭市":{"code":260,"lat":24.7520373,"lon":121.7531493,"site":1.609,"area":"宜蘭縣北部"},"羅東鎮":{"code":265,"lat":24.6769245,"lon":121.7669529,"site":1.601,"area":"宜蘭縣北部"},"蘇澳鎮":{"code":270,"lat":24.594315,"lon":121.8421903,"site":1.573,"area":"宜蘭縣北部"},"頭城鎮":{"code":261,"lat":24.8548387,"lon":121.8213189,"site":0.733,"area":"宜蘭縣北部"},"礁溪鄉":{"code":262,"lat":24.8234257,"lon":121.7711725,"site":0.949,"area":"宜蘭縣北部"},"壯圍鄉":{"code":263,"lat":24.746832,"lon":121.785759,"site":1.702,"area":"宜蘭縣北部"},"員山鄉":{"code":264,"lat":24.7433944,"lon":121.7232538,"site":1.179,"area":"宜蘭縣北部"},"冬山鄉":{"code":269,"lat":24.634338,"lon":121.792851,"site":1.387,"area":"宜蘭縣北部"},"五結鄉":{"code":268,"lat":24.684772,"lon":121.7982898,"site":1.519,"area":"宜蘭縣北部"},"三星鄉":{"code":266,"lat":24.665483,"lon":121.654047,"site":0.833,"area":"宜蘭縣北部"},"大同鄉":{"code":267,"lat":24.677412,"lon":121.6090927,"site":1.188,"area":"宜蘭縣南部"},"南澳鄉":{"code":272,"lat":24.465996,"lon":121.803714,"site":1.514,"area":"宜蘭縣南部"}},"澎湖縣":{"馬公市":{"code":880,"lat":23.566159,"lon":119.578692,"site":2.42,"area":"澎湖縣中部"},"湖西鄉":{"code":885,"lat":23.584072,"lon":119.6528318,"site":2.42,"area":"澎湖縣中部"},"白沙鄉":{"code":884,"lat":23.666538,"lon":119.598639,"site":2.42,"area":"澎湖縣中部"},"西嶼鄉":{"code":881,"lat":23.601088,"lon":119.5069847,"site":2.42,"area":"澎湖縣中部"},"望安鄉":{"code":882,"lat":23.3576577,"lon":119.500894,"site":2.42,"area":"澎湖縣中部"},"七美鄉":{"code":883,"lat":23.2067107,"lon":119.4244825,"site":2.42,"area":"澎湖縣中部"}},"金門縣":{"金城鎮":{"code":893,"lat":24.432824,"lon":118.320697,"area":"金門縣中部"},"金沙鎮":{"code":890,"lat":24.488898,"lon":118.413132,"area":"金門縣中部"},"金湖鎮":{"code":891,"lat":24.4414641,"lon":118.4171018,"area":"金門縣中部"},"金寧鄉":{"code":892,"lat":24.450966,"lon":118.334887,"area":"金門縣中部"},"烈嶼鄉":{"code":894,"lat":24.4295409,"lon":118.2445892,"area":"金門縣中部"},"烏坵鄉":{"code":896,"lat":24.9887062,"lon":119.4531826,"area":"金門縣中部"}},"連江縣":{"南竿鄉":{"code":209,"lat":26.1529312,"lon":119.9387995,"area":"連江縣中部"},"北竿鄉":{"code":210,"lat":26.223938,"lon":119.997139,"area":"連江縣中部"},"莒光鄉":{"code":211,"lat":25.9687384,"lon":119.9369689,"area":"連江縣中部"},"東引鄉":{"code":212,"lat":26.3672636,"lon":120.4898789,"area":"連江縣中部"}}} \ No newline at end of file diff --git a/src/view/index.html b/src/view/index.html index 80184322..eb23ee87 100644 --- a/src/view/index.html +++ b/src/view/index.html @@ -114,7 +114,7 @@
- - - - - -
-
+ -
-
-
-
預警條件
-
即時測站 (任一站) 為觸發時任一站震度門檻,預估震度 (所在地) - 為地震預警時所在地震度門檻,達到下方任一條件後軟體將會發出音效及彈出視窗。 -
-
-
- - -
-
- - -
-
-
-
@@ -135,7 +116,7 @@
-
+ +
+
+
+
+
+
+
預警條件
+
即時測站 (任一站) 為觸發時任一站震度門檻,預估震度 (所在地) + 為地震預警時所在地震度門檻,達到下方任一條件後軟體將會發出音效及彈出視窗。 +
+
+
+ + +
+
+ +
@@ -196,14 +196,27 @@
-
金鑰
-
使用個人金鑰可以讓你獲取最新即時資料、更多測站、進階功能等。
+
ExpTech
+
擁有 trem.vip 可以使用 WebSocket 取得最新即時資料、更多測站、進階功能等。
- -
+
+ + +
+
+ + +
@@ -235,10 +248,10 @@
- -
@@ -421,10 +434,10 @@
  • 交通部中央氣象署 (CWA)
  • -
  • 日本気象庁 (JMA)
  • +