/*
########################################################################
# gui.js 2.11
# show weather stations and display weather for them
#
# copyright (c) 2011-2023 metaf2xml
#
# This file is part of metaf2xml.
#
# metaf2xml is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# metaf2xml is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with metaf2xml. If not, see .
########################################################################
*/
// constants
var zoom2prefix = [ 50, 100, 300, 600, 1200, 1800, 1800 ];
var MAX_ZOOM = zoom2prefix.length - 1;
var viewportsizes = [ 1, 2, 6 ];
var MAX_VIEWPORTSIZE = viewportsizes.length - 1;
var tileSizes = [ [ 600, 300 ],
[ 1200, 600 ],
[ 300, 300 ],
[ 600, 600 ],
[ 1200, 1200 ],
[ 1200, 1200 ],
[ 2400, 2400 ]];
var tile2Lat = [ [ "NX" ],
[ "NX" ],
[ "N60", "N30", "N0", "S0", "S30", "S60" ],
[ "N60", "N30", "N0", "S0", "S30", "S60" ],
[ "N60", "N30", "N0", "S0", "S30", "S60" ],
[ "N75", "N60", "N45", "N30", "N15", "N0",
"S0", "S15", "S30", "S45", "S60", "S75" ],
[ "N75", "N60", "N45", "N30", "N15", "N0",
"S0", "S15", "S30", "S45", "S60", "S75" ]];
var tile2Lon = [ [ "WX" ],
[ "WX" ],
[ "W150", "W120", "W90", "W60", "W30", "W0",
"E0", "E30", "E60", "E90", "E120", "E150" ],
[ "W150", "W120", "W90", "W60", "W30", "W0",
"E0", "E30", "E60", "E90", "E120", "E150" ],
[ "W150", "W120", "W90", "W60", "W30", "W0",
"E0", "E30", "E60", "E90", "E120", "E150" ],
[ "W165", "W150", "W135", "W120", "W105", "W90",
"W75", "W60", "W45", "W30", "W15", "W0",
"E0", "E15", "E30", "E45", "E60", "E75",
"E90", "E105", "E120", "E135", "E150", "E165" ],
[ "W165", "W150", "W135", "W120", "W105", "W90",
"W75", "W60", "W45", "W30", "W15", "W0",
"E0", "E15", "E30", "E45", "E60", "E75",
"E90", "E105", "E120", "E135", "E150", "E165" ]];
var squareDotWidth = 30; // dot30 image is 30x30
var squareDotHeight = 30;
var MAX_DOTS_PER_SQUARE = 10;
var MAX_DOTS_OVERLAP = 4;
var version = '?v=2.11';
// global variables
var view_no;
var hist_no;
var zoom;
var viewportWidth;
var viewportHeight;
var lang;
var unit_temp;
var src_metaf;
var src_synop;
var src_buoy;
var src_amdar;
var synop_type;
var isMouseDownCanvas;
var mouseDownTarget;
var wasDragging;
var dragStartCanvasTop;
var dragStartCanvasLeft;
var dragStartMouseTop;
var dragStartMouseLeft;
var stations;
var stations_from_db;
var trans;
var icao_coords;
var init_done;
var init_stations_done;
var xsl_detailed;
var xsl_summary;
var canvas;
var startX;
var endX;
var startY;
var endY;
var scrollCanvasRepeat;
var scrollCanvasTimer;
var latestDots;
var end_date_valid;
function log (text) {
var views;
views = document.getElementById("views");
views.appendChild(document.createTextNode(text));
views.appendChild(document.createElement("br"));
}
function pixel2number (value) {
if (value == "") return 0;
return parseFloat(value.substring(0, value.length - 2));
}
function number2pixel (value) {
return value + "px";
}
function getCanvasWidth (z) {
return tileSizes[z][0] * tile2Lon[z].length;
}
function getCanvasHeight (z) {
return tileSizes[z][1] * tile2Lat[z].length;
}
function resizeCanvas () {
canvas.style.width = number2pixel(getCanvasWidth(zoom));
canvas.style.height = number2pixel(getCanvasHeight(zoom));
}
function start () {
// some browsers ignore
document.getElementById("noscript").style.display = "none";
view_no = 0;
hist_no = 0;
zoom = 0;
// lang is set from the URL parameter or the response to init_src_url
unit_temp = "C";
src_metaf = "local";
src_synop = "local";
src_buoy = "local";
src_amdar = "local";
synop_type = 1;
isMouseDownCanvas = false;
wasDragging = false;
document.onmouseup = onMouseUp;
end_date_valid = 0;
if (document.location.search.length > 0)
document.location.search.substring(1, 501).split("&").forEach(
function (p) {
var delimit = p.indexOf("=");
if (delimit < 1) // missing or empty parameter name?
return;
var param_name = decodeURIComponent(p.substring(0, delimit));
var param_value = decodeURIComponent(p.substring(delimit + 1));
if (param_name == "lang") {
if (/^(?:de|en|es)$/.test(param_value))
lang = param_value;
} else if (param_name == "unit_temp") {
if (/^(?:F)$/.test(param_value))
unit_temp = param_value;
} else if (param_name == "src_metaf") {
if (/^(?:noaa|nws|addsds|ogimet)$/.test(param_value))
src_metaf = param_value;
} else if (param_name == "src_synop") {
if (/^(?:nws|ogimet)$/.test(param_value))
src_synop = param_value;
} else if (param_name == "src_buoy") {
if (/^(?:nws|ogimet)$/.test(param_value))
src_buoy = param_value;
} else if (param_name == "src_amdar") {
if (/^(?:nws)$/.test(param_value))
src_amdar = param_value;
} else if (param_name == "synop_type") {
if (/^[0-7]$/.test(param_value))
synop_type = param_value;
}
});
// size of canvas
canvas = document.getElementById("canvas");
resizeCanvas();
canvas.ondragstart = function() { return false; } // IE
// size of viewport
resizeViewport(1);
addOnClick("decr_viewport", function() { resizeViewport(0, 0) } );
addOnClick("incr_viewport", function() { resizeViewport(0, 1) } );
addOnClick("update", function() { loadStations(0) } );
addOnClick("decr_end_date", function() { endDateChanged(-1, 1) } );
addOnClick("incr_end_date", function() { endDateChanged(1, 1) } );
document.getElementById("end_date").onchange
= function() { endDateChanged(0, 1) };
document.getElementById("hours").onchange
= function() { stationListNeedsUpdate(1) };
document.getElementById("zoom_" + zoom).checked = true;
if (synop_type & 1)
document.getElementById("synop_any").checked = true;
else
document.getElementById("synop_any").checked = false;
if (synop_type & 2)
document.getElementById("synop_nonstandard").checked = true;
else
document.getElementById("synop_nonstandard").checked = false;
if (synop_type & 4)
document.getElementById("synop_inter").checked = true;
else
document.getElementById("synop_inter").checked = false;
if (synop_type & 8)
document.getElementById("synop_main").checked = true;
else
document.getElementById("synop_main").checked = false;
loadStaticData();
loadStations(1);
scrollCanvasRepeat = 0;
scrollCanvasTimer = "undefined";
}
function fmt2 (i) {
return i >= 10 ? i : "0" + i;
}
function setDisabled (elements, disable, checked) {
elements.forEach(function (id) {
var el;
el = document.getElementById(id);
el.disabled = disable;
el.readonly = disable;
if (checked != undefined)
el.checked = checked;
});
}
function stationListNeedsUpdate (is_true) {
document.getElementById("update").style.fontWeight = is_true ? "bold" : "normal";
}
function endDateChanged (factor, stationsUpdated) {
var element, date, pat, date_arr;
// check validity
element = document.getElementById("end_date");
date = element.value;
pat = /^(1999|20\d\d)-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01]) ([01]\d|2[0-3]):([0-5]\d)$/;
date_arr = pat.exec(date);
end_date_valid = date_arr != undefined;
element.style.backgroundColor = end_date_valid ? "" : "#FF8080";
stationListNeedsUpdate(stationsUpdated);
if (!end_date_valid || factor == 0) // period end set?
return;
// set new value
date = new Date(date_arr[1], date_arr[2] - 1, date_arr[3],
date_arr[4], date_arr[5], 0);
date.setTime(date.getTime()
+ document.getElementById("change_end_date_by").value
* factor * 60000);
element.value = (date.getFullYear()) + "-"
+ fmt2(date.getMonth() + 1) + "-"
+ fmt2(date.getDate()) + " "
+ fmt2(date.getHours()) + ":"
+ fmt2(date.getMinutes());
stationListNeedsUpdate(1);
}
function loadStations (first_time) {
var req, element;
init_stations_done = 0;
setDisabled(["update"], 1);
req = new Object();
req.stations_url = "stations.xml" + version;
element = document.getElementById("hours");
if (first_time)
element.value = 1;
req.stations_db_url = "cgi-bin/db_stations.pl" + version
+ "&hours=" + element.value;
if (end_date_valid)
req.stations_db_url +=
"&end_date=" + document.getElementById("end_date").value;
req.info = "station data";
if (window.ActiveXObject !== undefined) {
if (first_time || !stations_from_db)
req.stations = getXML_ActiveX(req.stations_url);
if (first_time || stations_from_db)
req.stations_db = getXML_ActiveX(req.stations_db_url);
processStations(req, first_time);
} else if (window.XMLHttpRequest) {
if (first_time || !stations_from_db) {
req.stations = getXMLXSL(req.stations_url);
req.stations.onreadystatechange = function () { processStations(req, first_time) };
}
if (first_time || stations_from_db) {
req.stations_db = getXMLXSL(req.stations_db_url);
req.stations_db.onreadystatechange = function () { processStations(req, first_time) };
}
// start send only after all objects have been created
if (first_time || !stations_from_db)
req.stations.send(null);
if (first_time || stations_from_db)
req.stations_db.send(null);
} else
throw new Error("This browser cannot create XML HTTP requests");
}
function loadStaticData () {
var req;
init_done = 0;
req = new Object();
// can't use xsl:include: browsers using WebKit cannot handle it :-(
req.xsl_detailed_url = "metaf.xsl" + version;
req.xsl_summary_url = "metaf-sum.xsl" + version;
req.init_src_url = "cgi-bin/metaf.pl" + version + "&format=xml";
if (lang != undefined)
req.init_src_url += "&lang=" + lang;
req.lang_de_url = "metaf-lang-de.xml" + version;
req.lang_en_url = "metaf-lang-en.xml" + version;
req.lang_es_url = "metaf-lang-es.xml" + version;
req.transsum_url = "metaf-lang.xml" + version;
req.info = "basic data";
if (window.ActiveXObject !== undefined) {
req.xsl_detailed = getXSL_ActiveX(req);
req.xsl_summary = getXSL_ActiveX(req);
req.init_src = getXML_ActiveX(req.init_src_url);
req.lang_de = getXML_ActiveX(req.lang_de_url);
req.lang_en = getXML_ActiveX(req.lang_en_url);
req.lang_es = getXML_ActiveX(req.lang_es_url);
req.transsum = getXML_ActiveX(req.transsum_url);
// start load only after all objects have been created
req.xsl_detailed.load(req.xsl_detailed_url);
req.xsl_summary.load(req.xsl_summary_url);
} else if (window.XMLHttpRequest) {
req.xsl_detailed = getXMLXSL(req.xsl_detailed_url);
req.xsl_detailed.onreadystatechange = function () { initStaticData(req) };
req.xsl_summary = getXMLXSL(req.xsl_summary_url);
req.xsl_summary.onreadystatechange = function () { initStaticData(req) };
req.init_src = getXMLXSL(req.init_src_url);
req.init_src.onreadystatechange = function () {initStaticData(req)};
req.lang_de = getXMLXSL(req.lang_de_url);
req.lang_de.onreadystatechange = function () {initStaticData(req)};
req.lang_en = getXMLXSL(req.lang_en_url);
req.lang_en.onreadystatechange = function () {initStaticData(req)};
req.lang_es = getXMLXSL(req.lang_es_url);
req.lang_es.onreadystatechange = function () {initStaticData(req)};
req.transsum = getXMLXSL(req.transsum_url);
req.transsum.onreadystatechange = function () {initStaticData(req)};
// start send only after all objects have been created
req.xsl_detailed.send(null);
req.xsl_summary.send(null);
req.init_src.send(null);
req.lang_de.send(null);
req.lang_en.send(null);
req.lang_es.send(null);
req.transsum.send(null);
} else
throw new Error("This browser cannot create XML HTTP requests");
}
function str2coord (str) {
var coord, letter, length;
length = str.length;
if (length <= 6)
coord = parseFloat(str.substring(0, length - 3))
+ parseFloat(str.substring(length - 3, length - 1)) / 60;
else
coord = parseFloat(str.substring(0, length - 5))
+ parseFloat(str.substring(length - 5, length - 3)) / 60
+ parseFloat(str.substring(length - 3, length - 1)) / 3600;
letter = str.substring(length - 1, length);
if (letter == "W" || letter == "S")
coord *= -1;
return coord;
}
function checkError (node, req_data, info, text, url, quiet) {
if ( req_data.status == 200 // IE/XMLHTTP, FF
|| window.ActiveXObject !== undefined && req_data.parseError == 0) // other IE
return false;
if (quiet)
return true;
text = " " + info + " ERROR: could not " + text;
if ((window.ActiveXObject !== undefined) && req_data.parseError)
text += ": " + req_data.parseError.reason;
else {
text += " (HTTP error code: " + req_data.status;
try { text += ": "+ '"' + req_data.statusText + '"' + ")" } catch(e) {};
text += ")";
}
text += " URL: " + '"' + url + '"';
node.appendChild(document.createTextNode(" " + text));
return true;
}
function setSrc (options, is_init) {
var s;
s = options.getAttribute("src_metaf");
if (is_init || s != src_metaf) {
if (s != src_metaf && src_metaf == "local")
s = "addsds";
setSrcMetaf(s);
if (s == "local")
setDisabled(["src_metaf_noaa", "src_metaf_nws",
"src_metaf_addsds",
"src_metaf_ogimet"], 1, false);
else {
setDisabled(["src_metaf_noaa"], 0, s == "noaa");
setDisabled(["src_metaf_nws"], 0, s == "nws");
setDisabled(["src_metaf_addsds"], 0, s == "addsds");
setDisabled(["src_metaf_ogimet"], 0, s == "ogimet");
}
}
s = options.getAttribute("src_synop");
if (is_init || s != src_synop) {
if (s != src_synop && src_synop == "local")
s = "ogimet";
setSrcSynop(s);
if (s == "local")
setDisabled(["src_synop_nws", "src_synop_ogimet"], 1, false);
else {
setDisabled(["src_synop_nws"], 0, s == "nws");
setDisabled(["src_synop_ogimet"], 0, s == "ogimet");
}
}
s = options.getAttribute("src_buoy");
if (is_init || s != src_buoy) {
if (s != src_buoy && src_buoy == "local")
s = "ogimet";
setSrcBuoy(s);
if (s == "local")
setDisabled(["src_buoy_nws", "src_buoy_ogimet"], 1, false);
else {
setDisabled(["src_buoy_nws"], 0, s == "nws");
setDisabled(["src_buoy_ogimet"], 0, s == "ogimet");
}
}
s = options.getAttribute("src_amdar");
if (is_init || s != src_amdar) {
if (s != src_amdar && src_amdar == "local")
s = "nws";
setSrcAmdar(s);
if (s == "local")
setDisabled(["src_amdar_nws"], 1, false);
else {
setDisabled(["src_amdar_nws"], 0, s == "nws");
}
}
}
function addEvent (element, event, func){
if (element.attachEvent) // IE
return element.attachEvent("on" + event, func);
return element.addEventListener(event, func, false);
}
function addOnClick (id, func) {
addEvent(document.getElementById(id), "click", func);
}
function addScroll (id, x, y) {
var element = document.getElementById(id);
addEvent(element, "mousedown", function() { startScrollCanvas(x, y) });
addEvent(element, "mouseup", function() { stopScrollCanvas() });
addEvent(element, "mouseout", function() { stopScrollCanvas() });
}
function mkTrans (req, lang) {
var data;
if (!(window.ActiveXObject !== undefined))
req = req.responseXML;
trans[lang] = [];
trans[lang].country = [];
trans[lang].trans = req.getElementsByTagName("trans")[0];
data = req.getElementsByTagName("country");
for (var i = 0; i < data.length; i++) {
trans[lang].country[data[i].getAttribute("o")] =
data[i].firstChild.nodeValue;
}
}
// can't use xsl:include: browsers using WebKit cannot handle it :-(
function modifyXSL (req) {
var prefix, xsl, variables;
prefix = "xsl:"; // FF, IE
xsl = req.getElementsByTagName("xsl:stylesheet")[0];
if (xsl == null) {
prefix = ""; // WebKit
xsl = req.getElementsByTagName("stylesheet")[0];
}
// can't use createElement(): we need correct namespace, prefix, ...
variables = req.getElementsByTagName(prefix + "variable");
for (var i = 0; i < variables.length; i++) {
var meth;
if (variables[i].getAttribute("name") == "transsumroot") {
variables[i].setAttribute("select", "/data/transsum");
continue;
}
if (variables[i].getAttribute("name") != "transroot")
continue;
variables[i].setAttribute("select", "/data/trans");
meth = variables[i].cloneNode(false);
meth.setAttribute("name", "method");
meth.setAttribute("select", "'html'");
xsl.insertBefore(meth, xsl.firstChild);
(xsl.getElementsByTagName(prefix + "output")[0]).setAttribute("method", "html"); // not needed
break;
}
}
function appendAddStation (i) {
var info, span;
info = new makeStationInfo(i);
span = document.createElement("span");
span.onclick = function () { fetchData(i) };
span.onmouseover = function () {
document.getElementById("stationInfo").appendChild(document.createTextNode(info.info_obs))
}
span.onmouseout = function() { showStationInfo(-1) };
span.appendChild(document.createTextNode(info.info));
document.getElementById("morestations").appendChild(span);
document.getElementById("morestations").appendChild(document.createElement("p"));
}
function processStations (req, first_time) {
var response, maxWidth, maxHeight, divWidth, divHeight;
var max_dots, element, br;
// check if all requests are complete
if ( (req.stations == undefined ? 0 : req.stations.readyState != 4)
|| (req.stations_db == undefined ? 0 : req.stations_db.readyState != 4))
return;
// may get here once for each completed request, avoid multiple inits
if (init_stations_done)
return;
if (first_time) {
stations_from_db = 1;
if (checkError("", req.stations_db, "", "", "", 1)) {
stations_from_db = 0;
document.getElementById("chart").style.display = "none";
if (checkError(document.getElementById("errors"), req.stations,
req.info, "load station data",
req.stations_url + '"' + " and " + '"'
+ req.stations_db_url))
{
setDisabled(["update"], 0);
return;
}
}
} else if (stations_from_db) {
if (checkError(document.getElementById("errors"), req.stations_db,
req.info, "load station data", req.stations_db_url))
{
setDisabled(["update"], 0);
return;
}
} else {
if (checkError(document.getElementById("errors"), req.stations,
req.info, "load station data", req.stations_url))
{
setDisabled(["update"], 0);
return;
}
}
init_stations_done = 1;
if (first_time)
if (stations_from_db) {
document.getElementById("src_metaf").parentNode.style.display = "none";
document.getElementById("src_synop").parentNode.style.display = "none";
document.getElementById("src_buoy").parentNode.style.display = "none";
document.getElementById("src_amdar").parentNode.style.display = "none";
} else {
document.getElementById("update").style.display = "none";
document.getElementById("morestations_header").style.display = "none";
document.getElementById("morestations").parentNode.style.display = "none";
}
if (window.ActiveXObject !== undefined)
response = stations_from_db ? req.stations_db : req.stations;
else
response = stations_from_db ? req.stations_db.responseXML
: req.stations.responseXML;
stations = response.getElementsByTagName("stations")[0].getElementsByTagName("station");
// delete list of add. stations
element = document.getElementById("morestations");
while (element.hasChildNodes())
element.removeChild(element.firstChild);
/*
** divide icao_coords into an array so that stations for smallest
** squareDot (for 2nd biggest zoom) are in one array element
*/
divWidth = tileSizes[MAX_ZOOM - 1][0] * tile2Lon[MAX_ZOOM - 1].length / squareDotWidth;
divHeight = tileSizes[MAX_ZOOM - 1][1] * tile2Lat[MAX_ZOOM - 1].length / squareDotHeight;
icao_coords = new Array(divWidth);
for (var i = 0; i < divWidth; i++)
icao_coords[i] = new Array(divHeight);
max_dots = 1;
maxWidth = tileSizes[MAX_ZOOM][0] * tile2Lon[MAX_ZOOM].length;
maxHeight = tileSizes[MAX_ZOOM][1] * tile2Lat[MAX_ZOOM].length;
for (var i = 0; i < stations.length; i++) {
var posXY, lon, lat, x, y, sameDot;
posXY = getStationPos(stations[i].getAttribute("loc"));
if (!posXY) {
if (stations_from_db)
appendAddStation(i);
continue;
}
lon = posXY[0];
lat = posXY[1];
// determine indices for square for biggest zoom
x = Math.floor(lon * divWidth);
if (x == divWidth)
x = 0; // lon: wrap around
y = Math.floor(lat * divHeight);
if (y == divHeight)
y--; // lat: no wrap
// check for dot with identical coordinates (for biggest zoom)
sameDot = -1;
if (icao_coords[x] != undefined && icao_coords[x][y] != undefined)
for (var j = 0; j < icao_coords[x][y].length; j++)
if ( Math.round(Math.round(icao_coords[x][y][j][0] * maxWidth) / MAX_DOTS_OVERLAP)
== Math.round(Math.round(lon * maxWidth) / MAX_DOTS_OVERLAP)
&& Math.round(Math.round(icao_coords[x][y][j][1] * maxHeight) / MAX_DOTS_OVERLAP)
== Math.round(Math.round(lat * maxHeight) / MAX_DOTS_OVERLAP))
{
sameDot = j;
break;
}
if (sameDot == -1) {
// store coordinates
if (icao_coords[x] == undefined)
icao_coords[x] = [];
if (icao_coords[x][y] == undefined)
icao_coords[x][y] = [];
icao_coords[x][y].push([lon, lat, i]);
} else {
icao_coords[x][y][sameDot].push(i);
if (max_dots < icao_coords[x][y][sameDot].length - 2)
max_dots = icao_coords[x][y][sameDot].length - 2;
//log("samedot(" + icao_coords[x][y][sameDot]);
}
}
// try to join ICAO + WMO
for (var i = 0; i < icao_coords.length; i++) {
if (icao_coords[i] != undefined)
for (var j = 0; j < icao_coords[i].length; j++)
if (icao_coords[i][j] != undefined)
for (var k = 0; k < icao_coords[i][j].length; k++)
if (icao_coords[i][j][k].length == 4)
{
var i1, i2, s1, s2, attr, names_match, is_joined;
i1 = icao_coords[i][j][k][2];
i2 = icao_coords[i][j][k][3];
s1 = new getStationId(i1);
s2 = new getStationId(i2);
names_match = s1.name.substring(0, s2.name.length) == s2.name
||
s2.name.substring(0, s1.name.length) == s1.name;
is_joined = 0;
if ( s1.wmo == "" && s1.icao != ""
&& s2.wmo != "" && s2.icao == ""
&& names_match)
{
//log(" join('" + s1.name + "'/'" + s2.name + "'/" + s1.icao + "/" + s2.wmo + ")");
is_joined = 1;
stations[i1].setAttribute("wmo", s2.wmo);
attr = stations[i2].getAttribute("obsS");
if (attr)
stations[i1].setAttribute("obsS", attr);
attr = stations[i2].getAttribute("dataS");
if (attr)
stations[i1].setAttribute("dataS", attr);
}
else
if ( s1.wmo != "" && s1.icao == ""
&& s2.wmo == "" && s2.icao != ""
&& names_match)
{
//log(" join('" + s1.name + "'/'" + s2.name + "'/" + s1.wmo + "/" + s2.icao + ")");
is_joined = 1;
stations[i1].setAttribute("icao", s2.icao);
attr = stations[i2].getAttribute("obsM");
if (attr)
stations[i1].setAttribute("obsM", attr);
attr = stations[i2].getAttribute("obsT");
if (attr)
stations[i1].setAttribute("obsT", attr);
}
if (is_joined) {
icao_coords[i][j][k].pop();
if (s2.name.length > s1.name.length) {
if (stations[i1].childNodes.length == 1)
stations[i1].replaceChild(response.createTextNode(s2.name), stations[i1].firstChild);
else
stations[i1].appendChild(response.createTextNode(s2.name));
}
}
}
}
endX = -1; // indicator that all dots must be created
updateDots(zoom, 1);
element = document.getElementById("stationInfoHdr");
br = element.getElementsByTagName("br");
for (i = br.length; i < max_dots; i++)
element.appendChild(document.createElement("br"));
for (i = br.length; i > max_dots; i--)
element.removeChild(br[i - 1]);
if (stations_from_db) {
if (first_time || !end_date_valid) {
document.getElementById("end_date").value = response.getElementsByTagName("stations")[0].getAttribute("latest");
endDateChanged(0, 0);
} else
stationListNeedsUpdate(0);
setDisabled(["update"], 0);
}
}
function initStaticData (req) {
var response;
// check if all requests are complete
if ( req.xsl_detailed.readyState != 4
|| req.xsl_summary.readyState != 4
|| req.init_src.readyState != 4
|| req.lang_de.readyState != 4
|| req.lang_en.readyState != 4
|| req.lang_es.readyState != 4
|| req.transsum.readyState != 4)
return;
// may get here once for each completed request, avoid multiple inits
if (init_done)
return;
if (checkError(document.getElementById("errors"), req.xsl_detailed,
req.info, "load XSL file for detailed view",
req.xsl_detailed_url))
return;
if (checkError(document.getElementById("errors"), req.xsl_summary,
req.info, "load XSL file for summary view",
req.xsl_summary_url))
return;
if (checkError(document.getElementById("errors"), req.init_src,
req.info, "start CGI script", req.init_src_url))
return;
if (checkError(document.getElementById("errors"), req.lang_de, req.info,
"load language file for 'de'", req.lang_de_url))
return;
if (checkError(document.getElementById("errors"), req.lang_en, req.info,
"load language file for 'en'", req.lang_en_url))
return;
if (checkError(document.getElementById("errors"), req.lang_es, req.info,
"load language file for 'es'", req.lang_es_url))
return;
if (checkError(document.getElementById("errors"), req.transsum,
req.info, "load weather summary file", req.transsum_url))
return;
init_done = 1;
/*
** stylesheets: create XSLT processors
*/
if (window.ActiveXObject !== undefined) {
var xslt_detailed, xslt_summary;
modifyXSL(req.xsl_detailed);
xslt_detailed = new ActiveXObject("MSXML2.XSLTemplate");
xslt_detailed.stylesheet = req.xsl_detailed;
xsl_detailed = xslt_detailed.createProcessor();
modifyXSL(req.xsl_summary);
xslt_summary = new ActiveXObject("MSXML2.XSLTemplate");
xslt_summary.stylesheet = req.xsl_summary;
xsl_summary = xslt_summary.createProcessor();
xsl_summary.addParameter("no_msg", "1", "");
} else {
modifyXSL(req.xsl_detailed.responseXML);
xsl_detailed = new XSLTProcessor();
xsl_detailed.importStylesheet(req.xsl_detailed.responseXML);
modifyXSL(req.xsl_summary.responseXML);
xsl_summary = new XSLTProcessor();
xsl_summary.importStylesheet(req.xsl_summary.responseXML);
xsl_summary.setParameter("", "no_msg", "1");
}
/*
** get translations for countries
*/
trans = [];
mkTrans(req.lang_de, "de");
mkTrans(req.lang_en, "en");
mkTrans(req.lang_es, "es");
/*
** get weatherSum
*/
trans["sum"] = [];
if (window.ActiveXObject !== undefined)
trans["sum"].transsum = req.transsum.getElementsByTagName("transsum")[0];
else
trans["sum"].transsum = (req.transsum.responseXML).getElementsByTagName("transsum")[0];
updateTiles(zoom);
/*
** setup UI from options
*/
if (window.ActiveXObject !== undefined)
response = req.init_src;
else
response = req.init_src.responseXML;
// setup sources
setSrc(response.getElementsByTagName("options")[0], true);
// setup language
lang = response.getElementsByTagName("options")[0].getAttribute("lang");
if (!lang || trans[lang] == undefined)
lang = "de";
setLanguage(lang);
document.getElementById("language_" + lang).checked = true;
// setup unit_temp
unit_temp = response.getElementsByTagName("options")[0].getAttribute("unit_temp");
if (!unit_temp)
unit_temp = "C";
setUnitTemp(unit_temp);
document.getElementById("unit_temp_" + unit_temp).checked = true;
setChartDot("init");
setChartInfo("init");
addOnClick("language_de", function() { setLanguage("de") } );
addOnClick("language_en", function() { setLanguage("en") } );
addOnClick("language_es", function() { setLanguage("es") } );
addOnClick("unit_temp_C", function() { setUnitTemp("C") } );
addOnClick("unit_temp_F", function() { setUnitTemp("F") } );
addOnClick("zoom_0", function() { setZoom(0) } );
addOnClick("zoom_1", function() { setZoom(1) } );
addOnClick("zoom_2", function() { setZoom(2) } );
addOnClick("zoom_3", function() { setZoom(3) } );
addOnClick("zoom_4", function() { setZoom(4) } );
addOnClick("zoom_5", function() { setZoom(5) } );
addOnClick("zoom_6", function() { setZoom(6) } );
addOnClick("src_metaf_noaa", function() { setSrcMetaf("noaa") } );
addOnClick("src_metaf_nws", function() { setSrcMetaf("nws") } );
addOnClick("src_metaf_addsds", function() { setSrcMetaf("addsds") } );
addOnClick("src_metaf_ogimet", function() { setSrcMetaf("ogimet") } );
addOnClick("src_synop_nws", function() { setSrcSynop("nws") } );
addOnClick("src_synop_ogimet", function() { setSrcSynop("ogimet") } );
addOnClick("src_buoy_nws", function() { setSrcBuoy("nws") } );
addOnClick("src_buoy_ogimet", function() { setSrcBuoy("ogimet") } );
addOnClick("src_amdar_nws", function() { setSrcAmdar("nws") } );
addOnClick("synop_any", function() { setSynopType() } );
addOnClick("synop_nonstandard", function() { setSynopType() } );
addOnClick("synop_inter", function() { setSynopType() } );
addOnClick("synop_main", function() { setSynopType() } );
addOnClick("chartdot", function() { setChartDot() } );
addOnClick("chartnone", function() { setChartInfo("none") } );
addOnClick("chartcloud", function() { setChartInfo("cloud") } );
addOnClick("chartwind", function() { setChartInfo("wind") } );
addOnClick("chartall", function() { setChartInfo("all") } );
addScroll("scrollup", 0, viewportHeight/4);
addScroll("scrollleft", viewportWidth/4, 0);
addScroll("scrollright", -viewportWidth/4, 0);
addScroll("scrolldown", 0, -viewportHeight/4);
// event handlers of canvas
canvas.onmousedown = onMouseDown;
canvas.onmousemove = onMouseMove;
if (navigator.userAgent.indexOf('Trident') != -1) {
// TODO: IE: 2px offset required?!?
document.styleSheets[0].insertRule(".chartW { transform-origin: 0 -2px 0; }", document.styleSheets[0]['cssRules'].length);
}
}
function moveCanvas (top, left) {
var maxtop = viewportHeight - getCanvasHeight(zoom);
if (top > 0)
top = 0;
if (top < maxtop)
top = maxtop;
canvas.style.top = number2pixel(top);
var maxleft = viewportWidth - getCanvasWidth(zoom);
if (left > 0)
left = 0;
if (left < maxleft)
left = maxleft;
canvas.style.left = number2pixel(left);
}
function onMouseDown (event) {
var el;
event = event || window.event; // IE
el = event.target || event.srcElement; // IE
canvas.style.cursor = "move";
// clicked on a dot? store to set cursor on drag
if (el.className.indexOf("dot_") == 0) {
mouseDownTarget = event.target;
} else {
mouseDownTarget = null;
}
dragStartCanvasTop = pixel2number(canvas.style.top);
dragStartCanvasLeft = pixel2number(canvas.style.left);
dragStartMouseTop = event.clientY;
dragStartMouseLeft = event.clientX;
isMouseDownCanvas = true;
wasDragging = false; // not yet
return false;
}
function onMouseUp () {
if (isMouseDownCanvas) {
canvas.style.cursor = "";
if (mouseDownTarget)
mouseDownTarget.style.cursor = "pointer";
isMouseDownCanvas = false;
}
return false;
}
function onMouseMove (event) {
if (isMouseDownCanvas) {
event = event || window.event; // IE
moveCanvas(
parseFloat(dragStartCanvasTop) + event.clientY - dragStartMouseTop,
parseFloat(dragStartCanvasLeft) + event.clientX - dragStartMouseLeft);
updateTiles(zoom);
updateDots(zoom);
if (!wasDragging && (event.clientY != dragStartMouseTop || event.clientX != dragStartMouseLeft))
{
wasDragging = true;
if (mouseDownTarget)
mouseDownTarget.style.cursor = "move";
}
}
return false;
}
function getStationId (i) {
this.wmo = stations[i].getAttribute("wmo");
if (!this.wmo)
this.wmo = "";
this.ship = stations[i].getAttribute("ship");
if (!this.ship)
this.ship = "";
this.mobil = stations[i].getAttribute("mobil");
if (!this.mobil)
this.mobil = "";
this.icao = stations[i].getAttribute("icao");
if (!this.icao)
this.icao = "";
this.buoy = stations[i].getAttribute("buoy");
if (!this.buoy)
this.buoy = "";
this.ac = stations[i].getAttribute("ac");
if (!this.ac)
this.ac = "";
this.nat = stations[i].getAttribute("nat");
if (!this.nat)
this.nat = "";
if (stations[i].childNodes.length > 0)
this.name = stations[i].firstChild.nodeValue;
else
this.name = "";
}
function addObsTime (obs_src, i, attr_suff, obs_str) {
var attr, obs_time;
attr = stations[i].getAttribute("obs" + attr_suff);
if (attr) {
obs_time = new Date(attr * 1000);
if (obs_str != "")
obs_str += ", ";
obs_str += obs_src + ": "
+ fmt2(obs_time.getUTCHours()) + ":"
+ fmt2(obs_time.getUTCMinutes());
}
return obs_str;
}
function makeStationInfo (i) {
var station_id, attr, str, obs_str;
station_id = new getStationId(i);
this.wmo = station_id.wmo;
this.ship = station_id.ship;
this.mobil = station_id.mobil;
this.icao = station_id.icao;
this.buoy = station_id.buoy;
this.ac = station_id.ac;
this.nat = station_id.nat;
this.name = station_id.name;
// id
str = station_id.wmo;
if (str != "" && station_id.icao != "")
str += "/";
str += station_id.icao;
if (str != "" && station_id.nat != "")
str += "/";
str += station_id.nat;
str += station_id.ship;
str += station_id.mobil;
str += station_id.buoy;
str += station_id.ac;
this.info = str;
this.info_obs = str;
// ctry
str = this.name;
attr = stations[i].getAttribute("ctry");
if (lang && attr) {
if (str != "")
str += ", ";
if (trans[lang].country != undefined) {
var ctry2;
if (attr.indexOf("-") > 0)
ctry2 = attr.substring(0, attr.indexOf("-"));
else
ctry2 = "";
if (trans[lang].country[attr] != undefined)
str += trans[lang].country[attr];
else if (ctry2 != "" && trans[lang].country[ctry2] != undefined)
str += trans[lang].country[ctry2];
else
str += attr;
} else
str += attr;
}
this.name = str;
attr = stations[i].getAttribute("loc");
if (attr) {
if (str != "")
str += ", ";
if ("NS".indexOf(attr.substring(4, 5)) >= 0) {
str += parseFloat(attr.substring(0, 2)) + "° "
+ parseFloat(attr.substring(2, 4)) + "′ "
+ attr.substring(4, 5) + " "
+ parseFloat(attr.substring(5, 8)) + "° "
+ parseFloat(attr.substring(8, 10)) + "′ "
+ attr.substring(10, 11);
if (attr.length == 15)
str += " " + parseFloat(attr.substring(11, 15)) +" m";
} else {
str += parseFloat(attr.substring(0, 2)) + "° "
+ parseFloat(attr.substring(2, 4)) + "′ "
+ parseFloat(attr.substring(4, 6)) + '″ '
+ attr.substring(6, 7) + " "
+ parseFloat(attr.substring(7, 10)) + "° "
+ parseFloat(attr.substring(10, 12)) + "′ "
+ parseFloat(attr.substring(12, 14)) + '″ '
+ attr.substring(14, 15);
if (attr.length == 19)
str += " " + parseFloat(attr.substring(15, 19)) +" m";
}
}
if (str != "")
this.info += " (" + str + ")";
if (stations[i].getAttribute("buoy"))
obs_str = addObsTime("BUOY", i, "", "");
else if (stations[i].getAttribute("ac"))
obs_str = addObsTime("AMDAR", i, "", "");
else {
obs_str = "";
[ "METAR", "TAF", "SYNOP" ].forEach(function (o_s) {
obs_str = addObsTime(o_s, i, o_s.substring(0, 1), obs_str);
});
}
if (str != "") {
if (obs_str == "")
obs_str = str;
else
obs_str = str + ". " + obs_str;
}
if (obs_str != "")
this.info_obs += " (" + obs_str + ")";
}
/* WMO IPET-DRMM-III_Doc11-5_GDPFS_Manual_Appendix_II-4.pdf */
function makeWMOChartSymbol (dataS, is_southern, dot) {
var span, ii, jj, chars;
/* N */
chars = [];
ii = dataS.indexOf("N") + 1;
if (ii > 0)
chars.push(0xE000 + dataS.substr(ii, 1) * 1);
else
chars.push(0xE00A);
/* automatic station? */
ii = dataS.indexOf("A") + 1;
if (ii > 0)
chars.push(0xE00B);
chars.forEach(function (ch) {
span = document.createElement("span");
span.appendChild(document.createTextNode(String.fromCharCode(ch)));
span.className = "chartcenter";
dot.appendChild(span);
});
/* wind: w, ss: "xx" or (speed[kt] rounded to nearest 5) / 5 */
ii = dataS.indexOf("W") + 1;
if (ii > 0) {
var wind_speed;
chars = [];
wind_speed = dataS.substring(ii + 3, ii + 5);
if (wind_speed == "xx") /* Wx */
chars.push(0xE00E);
else if (wind_speed == "cm") /* Wcalm */
chars.push(0xE00F);
else if (wind_speed <= 11) /* W000..W055 */
chars.push(0xE010 + wind_speed * 1);
else if (wind_speed <= 19) /* W050, W010..W045 */
chars.push(0xE01A, 0xE010 + wind_speed * 1 - 10);
else if (wind_speed <= 21) /* W100, W050..W055 */
chars.push(0xE01C, 0xE01A + wind_speed * 1 - 20);
else if (wind_speed <= 29) /* W100, W050, W010..W045 */
chars.push(0xE01C, 0xE01A, 0xE010 + wind_speed * 1 - 20);
else if (wind_speed <= 31) /* W150, W100, W050..W055 */
chars.push(0xE01D, 0xE01C, 0xE01A + wind_speed * 1 - 30);
else { /* W150, W100, W050, W010..W045 */
if (wind_speed > 39)
wind_speed = 39;
chars.push(0xE01D, 0xE01C, 0xE01A, 0xE010 + wind_speed * 1 - 30);
}
chars.forEach(function (ch) {
span = document.createElement("span");
if (wind_speed != "cm") {
span.className = "chartW";
span.style.transform = "rotate(" + (dataS.substr(ii, 3) * 1 + 180) + "deg)";
if (is_southern)
span.style.transform += " rotateY(180deg)";
} else {
span.className = "chartcenter";
}
span.appendChild(document.createTextNode(String.fromCharCode(ch)));
dot.appendChild(span);
});
/*
[0, 90, 180, 270].forEach(function (d) {
span = document.createElement("span");
span.className = "chartW";
span.style.transform = "rotate(" + d + "deg)";
span.appendChild(document.createTextNode(String.fromCharCode(0xE012)));
dot.appendChild(span);
});
*/
}
/* PPPP */
ii = dataS.indexOf("P") + 1;
if (ii > 0) {
span = document.createElement("span");
span.appendChild(document.createTextNode(dataS.substr(ii, 4)));
span.className = "chartP chartText";
dot.appendChild(span);
}
/* ppp */
ii = dataS.indexOf("p") + 1;
if (ii > 0) {
var p, t;
p = dataS.substr(ii, 3).trim();
t = dataS.substr(ii + 3, 1);
span = document.createElement("span");
if (t == "x")
span.appendChild(document.createTextNode(p));
else
span.appendChild(document.createTextNode(p + String.fromCharCode(0xE020 + t * 1)));
span.className = "chartp chartText";
dot.appendChild(span);
}
/* TgTg */
ii = dataS.indexOf("Tg") + 2;
if (ii > 1) {
var t;
t = dataS.substr(ii, 3);
span = document.createElement("span");
span.appendChild(document.createTextNode(t.trim()));
span.className = "chartTg chartText";
dot.appendChild(span);
}
/* TxTxTx or TnTnTn */
ii = dataS.indexOf("Tm") + 2;
if (ii > 1) {
var t;
t = dataS.substr(ii, 5);
span = document.createElement("span");
span.appendChild(document.createTextNode(t.trim()));
span.className = "chartTm chartText";
dot.appendChild(span);
}
/* TTT */
ii = dataS.indexOf("Ta") + 2;
if (ii > 1) {
var t;
t = dataS.substr(ii, 5);
span = document.createElement("span");
span.appendChild(document.createTextNode(t.trim()));
span.className = "chartTa chartText";
dot.appendChild(span);
}
/* TdTdTd */
ii = dataS.indexOf("Td") + 2;
if (ii > 1) {
var t;
t = dataS.substr(ii, 5);
span = document.createElement("span");
span.appendChild(document.createTextNode(t.trim()));
span.className = "chartTd chartText";
dot.appendChild(span);
}
/* RRR/tR */
ii = dataS.indexOf("R") + 1;
if (ii > 0) {
var t;
t = dataS.substr(ii, 5);
span = document.createElement("span");
span.appendChild(document.createTextNode(t.trim()));
span.className = "chartR chartText";
dot.appendChild(span);
}
/* Nh, CL, CM, CH */
ii = dataS.indexOf("Cx") + 2;
if (ii > 1) {
var ch;
/* Nh */
ch = dataS.substr(ii, 1);
if (ch != "x") {
span = document.createElement("span");
span.appendChild(document.createTextNode(ch));
span.className = "chartNh chartText";
dot.appendChild(span);
}
ii++;
/* CL */
ch = dataS.substr(ii, 1);
if (ch != "x" && ch != "0") {
ch = 0xE028 + ch * 1;
span = document.createElement("span");
span.appendChild(document.createTextNode(String.fromCharCode(ch)));
span.className = "chartCL";
dot.appendChild(span);
}
ii++;
/* CM */
ch = dataS.substr(ii, 1);
if (ch != "x" && ch != "0") {
ch = 0xE031 + ch * 1;
span = document.createElement("span");
span.appendChild(document.createTextNode(String.fromCharCode(ch)));
span.className = "chartCM";
dot.appendChild(span);
}
ii++;
/* CH */
ch = dataS.substr(ii, 1);
if (ch != "x" && ch != "0") {
ch = 0xE03A + ch * 1;
span = document.createElement("span");
span.appendChild(document.createTextNode(String.fromCharCode(ch)));
span.className = "chartCH";
dot.appendChild(span);
}
}
}
function updateTiles (old_zoom) {
/*
** The DOM structure relevant for the map is as follows:
** BODY
** ...
** DIV viewport
** DIV canvas
** DIV divCOORDINATE[1..n] (exists if visible in viewport)
** with topographic image as background
** DIV dot_X_Y_IDX[0..m] (marker (dot) for a station)
** DIV dot_X_Y_[0..l] (marker (square) for stations)
** ...
*/
var displayTiles = [];
var displayTilesHash = {};
var displayTilesCnt = 0;
var tileWidth = tileSizes[zoom][0];
var tileHeight = tileSizes[zoom][1];
var col1 = -(Math.floor(pixel2number(canvas.style.left) / tileWidth));
var row1 = -(Math.floor(pixel2number(canvas.style.top) / tileHeight));
var tilesX = Math.ceil(viewportWidth / tileWidth);
var tilesY = Math.ceil(viewportHeight / tileHeight);
// make list of tiles that will be displayed
for (var col = Math.max(col1 - 1, 0);
col < Math.min(col1 + tilesX, tile2Lon[zoom].length);
col++)
{
for (var row = Math.max(row1 - 1, 0);
row < Math.min(row1 + tilesY, tile2Lat[zoom].length);
row++)
{
displayTiles[displayTilesCnt++] = [ col, row ];
displayTilesHash[tile2Lat[zoom][row] + tile2Lon[zoom][col]] = true;
}
}
// remove unused existing tiles
var oldTiles = canvas.getElementsByTagName("div");
var no_old = oldTiles.length;
for (var i = oldTiles.length - 1; i >= 0; i--) {
if ( (
oldTiles[i].name != undefined
&& oldTiles[i].name.substring(0, 3) == "div"
&& !displayTilesHash[oldTiles[i].name.substring(3)]))
{
canvas.removeChild(oldTiles[i]);
}
}
// check for tiles to be created
for (var i = 0; i < displayTilesCnt; i++) {
var tile, need_tile_update;
var col = displayTiles[i][0];
var row = displayTiles[i][1];
var coords = tile2Lat[zoom][row] + tile2Lon[zoom][col];
need_tile_update = false;
tile = document.getElementById("div" + coords);
if (tile) {
// tile already exists, check if update is required
if (old_zoom != zoom)
need_tile_update = true;
} else {
need_tile_update = true;
// prepend tile for image to canvas
tile = document.createElement("div");
tile.id = "div" + coords;
tile.name = tile.id;
tile.style.position = "absolute";
canvas.insertBefore(tile, canvas.firstChild);
}
if (need_tile_update) {
tile.style.left = number2pixel(col * tileWidth);
tile.style.top = number2pixel(row * tileHeight);
tile.style.width = number2pixel(tileWidth);
tile.style.height = number2pixel(tileHeight);
if (window.ActiveXObject !== undefined) {
var img;
img = document.createElement("img");
img.id = "img" + coords;
img.name = img.id;
img.style.position = "absolute";
img.style.left = "0";
img.style.top = "0";
img.style.backgroundSize = "cover";
img.style.width = number2pixel(tileWidth);
img.style.height = number2pixel(tileHeight);
img.src = "images/"
+ zoom2prefix[zoom]
+ "px-Topographic30deg_"
+ coords
+ ".png";
if (tile.hasChildNodes())
tile.removeChild(tile.firstChild);
tile.appendChild(img);
} else
tile.style.backgroundSize = "cover";
tile.style.backgroundImage = "url(images/"
+ zoom2prefix[zoom]
+ "px-Topographic30deg_"
+ coords
+ ".png)";
}
}
}
function sortByCoords (a, b) {
if (a.offsetX != b.offsetX)
return a.offsetX - b.offsetX
else
return a.offsetY - b.offsetY;
}
function idxItem (x, y, z, offsetX, offsetY) {
this.x = x;
this.y = y;
this.z = z;
this.offsetX = offsetX;
this.offsetY = offsetY;
}
function mkZoomIn (centerX, centerY) {
return function() {
if (!wasDragging)
zoomIn(centerX, centerY);
wasDragging = false;
};
}
function mkShowStationInfo (x, y, z) {
return function() { showStationInfo(x, y, z) };
}
function mkFetchData (arr) {
return function() {
if (!wasDragging)
for (var i = arr.length - 1; i >= 0; i--)
fetchData(arr[i]);
wasDragging = false;
};
}
// str contains space-delimited substrings
// remove all sub_str from str, then append sub_str if add_sub_str
function setSubStr (str_old, sub_str, add_sub_str) {
var str_new;
if (str_old.indexOf(sub_str) == -1) // quick & dirty check
str_new = str_old;
else {
str_new = "";
str_old.split(" ").forEach( // proper check
function (s) {
if (sub_str != s)
str_new += " " + s;
}
);
}
if (add_sub_str)
str_new += " " + sub_str;
// skip leading blank if there is one
return str_new.substring(0, 1) == " " ? str_new.substring(1) : str_new;
}
function chartMouseHover (event) {
event = event || window.event; // IE
this.className = setSubStr(this.className, "chartHover",
event.type == "mouseover");
for (var i = 0; i < this.children.length; i++)
this.children[i].className = setSubStr(this.children[i].className,
"chartHover",
event.type == "mouseover");
}
function updateDots (old_zoom, force_delete) {
var incr, startXnew, endXnew, startYnew, endYnew, latestDot, startDot;
var canvasWidth, canvasHeight, tileWidth, tileHeight, showchart;
canvasWidth = getCanvasWidth(zoom);
canvasHeight = getCanvasHeight(zoom);
if (zoom == MAX_ZOOM)
incr = 1;
else
incr = getCanvasWidth(MAX_ZOOM - 1) / canvasWidth;
//log("zoom: " + zoom + " getCanvasWidth(" + (MAX_ZOOM-1) + "): " + getCanvasWidth(MAX_ZOOM - 1) + " canvasWidth: " + canvasWidth + " incr: " + incr);
// determine indices to show
startXnew = -pixel2number(canvas.style.left) / canvasWidth * icao_coords.length - 1;
if (startXnew < 0)
startXnew = 0;
else
startXnew -= startXnew % incr;
endXnew = (-pixel2number(canvas.style.left) + viewportWidth) / canvasWidth * icao_coords.length + 1;
if (endXnew > icao_coords.length - 1)
endXnew = icao_coords.length - incr;
else
endXnew -= endXnew % incr;
startYnew = -pixel2number(canvas.style.top) / canvasHeight * icao_coords[0].length - 1;
if (startYnew < 0)
startYnew = 0;
else
startYnew -= startYnew % incr;
endYnew = (-pixel2number(canvas.style.top) + viewportHeight) / canvasHeight * icao_coords[0].length + 1;
if (endYnew > icao_coords[0].length - 1)
endYnew = icao_coords[0].length - incr;
else
endYnew -= endYnew % incr;
if (force_delete || old_zoom != zoom) {
// delete all dots
var dots = canvas.getElementsByTagName("div");
for (var i = dots.length - 1; i >= 0; i--)
if (dots[i].id.indexOf("dot_") == 0)
canvas.removeChild(dots[i]);
endX = -1; // indicator that all dots must be created
}
if (endX == -1) {
startX = endXnew + 1;
startY = endYnew + 1;
endY = -1;
latestDots = [];
}
if ( startX == startXnew && endX == endXnew
&& startY == startYnew && endY == endYnew)
return;
tileWidth = canvasWidth / icao_coords.length;
tileHeight = canvasHeight / icao_coords[0].length;
var no_sq_num = 0; //log
var no_sq_pos = 0; //log
startDot = document.getElementById("start_of_dots");
latestDot = startDot;
showchart = zoom == MAX_ZOOM
&& document.getElementById("chart").style.display != "none";
for (var x = Math.min(startX, startXnew);
x <= Math.max(endX, endXnew);
x += incr)
{
var squareDotLeft = number2pixel(x * tileWidth);
for (var y = Math.min(startY, startYnew);
y <= Math.max(endY, endYnew);
y += incr)
{
var squareDotTop = number2pixel(y * tileHeight);
if ( x >= startXnew && x <= endXnew
&& y >= startYnew && y <= endYnew
&& x >= startX && x <= endX
&& y >= startY && y <= endY)
{
if (latestDots[x][y] != undefined) {
latestDot = latestDots[x][y];
//log("+ok["+x+","+y+"]("+latestDot.id+")");
}
continue;
}
if ( x >= startXnew && x <= endXnew
&& y >= startYnew && y <= endYnew)
{
// create dots
var idxList, need_square_dot, dots;
idxList = [];
need_square_dot = false;
for (var i = 0; i < incr; i++) {
for (var j = 0; j < incr; j++) {
if (icao_coords[x + i][y + j] == undefined)
continue;
// check if appending the new list exceed max. dots
//if ( idxList.length + icao_coords[x + i][y + j].length > MAX_DOTS_PER_SQUARE
// && zoom < MAX_ZOOM)
//{
// need_square_dot = true;
// no_sq_num++; //log
// break;
//}
for (var z = 0;
z < icao_coords[x + i][y + j].length;
z++)
{
var station_id;
station_id = new getStationId(icao_coords[x + i][y + j][z][2]);
// TODO: should we use this feature?
if (zoom < MAX_ZOOM - 2 && (!station_id.wmo || !station_id.icao) && icao_coords[x + i][y + j][z].length == 3)
continue;
var offsetX = Math.round(Math.round(icao_coords[x + i][y + j][z][0] * canvasWidth) / MAX_DOTS_OVERLAP) * MAX_DOTS_OVERLAP;
var offsetY = Math.round(Math.round(icao_coords[x + i][y + j][z][1] * canvasHeight) / MAX_DOTS_OVERLAP) * MAX_DOTS_OVERLAP;
if (zoom < MAX_ZOOM) {
// check distance to other points in square
for (var l = 0; l < idxList.length; l++) {
if ( Math.abs(idxList[l].offsetX - offsetX) < 5
&& Math.abs(idxList[l].offsetY - offsetY) < 5)
{
need_square_dot = true;
no_sq_pos++; //log
break;
}
}
}
if (!need_square_dot) {
idxList.push(new idxItem(x + i, y + j, z, offsetX, offsetY));
//log(icao_coords[x + i][y + j][z][2]+"->("+(x+i)+","+(y+j)+")");
}
}
if (need_square_dot)
break;
}
if (need_square_dot)
break;
}
// draw squareDot or dots
if (latestDots[x] == undefined)
latestDots[x] = [];
if (need_square_dot) {
var dot;
dot = document.createElement("div");
dot.id = "dot_" + x + "_" + y + "_";
dot.className = "dot_square";
dot.style.left = squareDotLeft;
dot.style.top = squareDotTop;
dot.onclick = mkZoomIn(
(x + incr / 2) * tileWidth,
(y + incr / 2) * tileHeight);
dot.onmouseover = function() { showStationInfo(-2) };
dot.onmouseout = function() { showStationInfo(-1) };
//log("+sq["+x+","+y+"]("+latestDot.id+")");
canvas.insertBefore(dot, startDot);
//log("+sq["+x+","+y+"]");
} else {
//log(" +dots["+x+","+y+"]");
idxList.sort(sortByCoords);
idxList.forEach(function (item) {
var idx, dot, station_id, fetch, attr;
idx = icao_coords[item.x][item.y][item.z][2];
dot = document.createElement("div");
dot.style.top = number2pixel(item.offsetY - 4);
dot.style.left = number2pixel(item.offsetX - 4);
station_id = new getStationId(idx);
if (icao_coords[item.x][item.y][item.z].length > 3)
dot.className = "dot_multi";
else if (station_id.icao && station_id.wmo)
dot.className = "dot_icao_synop";
else if (station_id.icao)
dot.className = "dot_icao";
else if (station_id.ship)
if (/^\d\d\d\d\d$/.test(station_id.ship))
dot.className = "dot_buoy_ship";
else
dot.className = "dot_ship";
else if (station_id.mobil)
dot.className = "dot_mobil";
else if (station_id.buoy)
dot.className = "dot_buoy";
else if (station_id.ac)
dot.className = "dot_amdar";
else
dot.className = "dot_synop";
dot.id = "dot_" + x + "_" + y + "_" + idx;
fetch = [];
for (var j = 2; j < icao_coords[item.x][item.y][item.z].length; j++)
{
fetch.push(icao_coords[item.x][item.y][item.z][j]);
}
dot.onclick = mkFetchData(fetch);
dot.onmouseover = mkShowStationInfo(item.x, item.y, item.z);
dot.onmouseout = function() { showStationInfo(-1) };
if (showchart)
attr = stations[idx].getAttribute("dataS");
if (attr) {
var chart;
chart = document.createElement("div");
chart.id = dot.id + "c";
// TODO: IE: 2px offset required?!?
chart.style.top = number2pixel(pixel2number(dot.style.top) + (navigator.userAgent.indexOf('Trident') != -1 ? 6 : 4));
chart.style.left = number2pixel(pixel2number(dot.style.left) + 4);
chart.className = "chart";
addEvent(chart, "mouseover", chartMouseHover);
addEvent(chart, "mouseout", chartMouseHover);
makeWMOChartSymbol(attr, icao_coords[item.x][item.y][item.z][1] > 0.5, chart);
canvas.insertBefore(chart, latestDot.nextSibling);
latestDot = chart;
dot.className += " dot_chart";
}
//log("+dt["+x+","+y+"]("+latestDot.id+")");
canvas.insertBefore(dot, latestDot.nextSibling);
latestDot = dot;
latestDots[x][y] = dot;
});
}
} else {
// delete all dots of square
var dots = canvas.getElementsByTagName("div");
var id = "dot_" + x + "_" + y + "_";
for (var i = dots.length - 1; i >= 0; i--)
if (dots[i].id.indexOf(id) == 0)
canvas.removeChild(dots[i]);
if (latestDots[x] != undefined)
latestDots[x][y] = undefined;
//log("-["+x+","+y+"]");
}
}
}
//log("num: "+no_sq_num+",pos: "+no_sq_pos);
startX = startXnew;
endX = endXnew;
startY = startYnew;
endY = endYnew;
}
function showStationInfo (x, y, z) {
var stationInfo, info;
stationInfo = document.getElementById("stationInfo");
while (stationInfo.hasChildNodes())
stationInfo.removeChild(stationInfo.firstChild);
switch (x) {
case -2: info = { "de": "Anklicken zum Vergrößern",
"en": "click to enlarge",
"es": "clic para ampliar",
}[lang];
stationInfo.appendChild(document.createTextNode(info));
break;
case -1: stationInfo.appendChild(document.createTextNode(""));
break;
default:
for (var i = 2; i < icao_coords[x][y][z].length; i++) {
if (i > 2)
stationInfo.appendChild(document.createElement("br"));
info = new makeStationInfo(icao_coords[x][y][z][i]).info_obs;
stationInfo.appendChild(document.createTextNode(info));
}
}
return false;
}
function setHref (lang_changed) {
var element;
element = document.getElementById("cgi_link");
element.href = "cgi-bin/metaf.pl" + version + "&src_metaf=" + src_metaf + "&src_synop=" + src_synop + "&src_buoy=" + src_buoy + "&src_amdar=" + src_amdar + "&lang=" + lang;
if (lang_changed) {
element.replaceChild(document.createTextNode(
{ "de": "text-basierte Version",
"en": "text-based version",
"es": "versión a base de texto",
}[lang]),
element.firstChild);
element = document.getElementById("help_link");
element.href = "gui-help" + { "de": ".de",
"en": "",
"es": "",
}[lang] + ".html" + version;
element.replaceChild(document.createTextNode(
{ "de": "Hilfeseite",
"en": "help page",
"es": "página de ayuda",
}[lang]),
element.firstChild);
}
}
function setLanguage (new_lang) {
var element;
lang = new_lang;
setHref(1);
element = document.getElementById("feedback");
if (element != null) {
element.replaceChild(document.createTextNode(
{ "de": "Übersetzung verbessern",
"en": "improve decoding",
"es": "mejorar traducción",
}[lang]),
element.firstChild);
element.href = "cgi-bin/feedback.pl?gui=&lang=" + lang;
}
element = document.getElementById("lang").firstChild;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Sprache:",
"en": "language:",
"es": "lengua:",
}[lang]),
element);
element = document.getElementById("unit_temp").firstChild;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Temperatur in:",
"en": "temperature in:",
"es": "temperatura en:",
}[lang]),
element);
element = document.getElementById("viewportsize");
element.replaceChild(document.createTextNode(
{ "de": "Kartenfenstergröße:",
"en": "map window size:",
"es": "tamaño de la ventana del mapa:",
}[lang]),
element.firstChild);
element = document.getElementById("zoom");
element.replaceChild(document.createTextNode(
{ "de": "Kartenvergrößerung:",
"en": "map zoom:",
"es": "zoom del mapa:",
}[lang]),
element.firstChild);
document.title = { "de": "metaf2xml: analysiere und dekodiere METAR, TAF, SYNOP, BUOY und AMDAR",
"en": "metaf2xml: parse and decode METAR, TAF, SYNOP, BUOY and AMDAR",
"es": "metaf2xml: analiza y decodifica METAR, TAF, SYNOP, BUOY y AMDAR",
}[lang];
if (window.ActiveXObject !== undefined)
{ }
else {
element = document.getElementsByTagName("title")[0];
element.replaceChild(document.createTextNode(document.title),
element.firstChild);
}
element = document.getElementsByTagName("h1")[0];
element.replaceChild(document.createTextNode(document.title),
element.firstChild);
element = document.getElementById("stationInfoHdr");
element.replaceChild(document.createTextNode(
{ "de": "Station: ",
"en": "station: ",
"es": "estación: ",
}[lang]),
element.firstChild);
element = document.getElementById("src_metaf");
element.replaceChild(document.createTextNode(
{ "de": "hole METAR/TAF-Meldungen von:",
"en": "fetch METAR/TAF messages from:",
"es": "trae METAR/TAF mensajes de:",
}[lang]),
element.firstChild);
element = document.getElementById("src_synop");
element.replaceChild(document.createTextNode(
{ "de": "hole SYNOP-Meldungen von:",
"en": "fetch SYNOP messages from:",
"es": "trae SYNOP mensajes de:",
}[lang]),
element.firstChild);
element = document.getElementById("src_buoy");
element.replaceChild(document.createTextNode(
{ "de": "hole BUOY-Meldungen von:",
"en": "fetch BUOY messages from:",
"es": "trae BOYA mensajes de:",
}[lang]),
element.firstChild);
element = document.getElementById("src_amdar");
element.replaceChild(document.createTextNode(
{ "de": "hole AMDAR-Meldungen von:",
"en": "fetch AMDAR messages from:",
"es": "trae AMDAR mensajes de:",
}[lang]),
element.firstChild);
element = document.getElementById("synop_type");
element.replaceChild(document.createTextNode(
{ "de": "Zeit der SYNOP-Meldung:",
"en": "hour of SYNOP message:",
"es": "hora de SYNOP mensaje:",
}[lang]),
element.firstChild);
element = document.getElementById("synop_any").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "alle",
"en": "any",
"es": "cualquiera",
}[lang]),
element);
element = document.getElementById("synop_nonstandard").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Nicht-Standard-Zeit",
"en": "non-standard",
"es": "no estándar",
}[lang]),
element);
element = document.getElementById("synop_inter").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Zwischenzeit",
"en": "intermediate",
"es": "intermedia",
}[lang]),
element);
element = document.getElementById("synop_main").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Hauptzeit",
"en": "main",
"es": "principal",
}[lang]),
element);
element = document.getElementById("chartinfo");
element.replaceChild(document.createTextNode(
{ "de": "WMO-Chart:",
"en": "WMO chart:",
"es": "grafica WMO:",
}[lang]),
element.firstChild);
element = document.getElementById("chartdot").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Stationskreis",
"en": "station circle",
"es": "círculo de la estacion",
}[lang]),
element);
element = document.getElementById("chartnone").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "aus",
"en": "off",
"es": "no",
}[lang]),
element);
element = document.getElementById("chartcloud").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "Bewölkung",
"en": "cloud",
"es": "nubes",
}[lang]),
element);
element = document.getElementById("chartwind").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "+Wind",
"en": "+wind",
"es": "+viento",
}[lang]),
element);
element = document.getElementById("chartall").nextSibling;
element.parentNode.replaceChild(document.createTextNode(
{ "de": "alle",
"en": "all",
"es": "todos",
}[lang]),
element);
element = document.getElementById("date_range1");
element.replaceChild(document.createTextNode(
{ "de": "Zeitraum:",
"en": "time period:",
"es": "espacio de tiempo:",
}[lang]),
element.firstChild);
element = document.getElementById("date_range2");
element.replaceChild(document.createTextNode(
{ "de": "Stunde(n) vor:",
"en": "hour(s) before:",
"es": "hora(s) antes de:",
}[lang]),
element.firstChild);
element = document.getElementById("update");
element.value = { "de": "aktualisiere Stationen",
"en": "update stations",
"es": "actualizar estaciones",
}[lang];
element = document.getElementById("morestations_header");
element.replaceChild(document.createTextNode(
{ "de": "weitere Stationen",
"en": "add. stations",
"es": "otras estaciones",
}[lang]),
element.firstChild);
}
function setUnitTemp (new_unit_temp) {
unit_temp = new_unit_temp;
if (window.ActiveXObject !== undefined) {
xsl_summary.addParameter("unit_temp", unit_temp, "");
} else {
xsl_summary.setParameter("", "unit_temp", unit_temp);
}
}
function setZoom (new_zoom, centerX, centerY, force) {
var old_zoom = zoom;
zoom = Math.floor(new_zoom);
if (zoom < 0)
zoom = 0;
if (zoom > MAX_ZOOM)
zoom = MAX_ZOOM;
if (old_zoom == zoom && !force)
return;
// get current center if necessary
if (centerX == undefined)
centerX = (-pixel2number(canvas.style.left) + viewportWidth / 2) / getCanvasWidth(old_zoom);
if (centerY == undefined)
centerY = (-pixel2number(canvas.style.top) + viewportHeight / 2) / getCanvasHeight(old_zoom);
resizeCanvas();
// set new center
centerX *= getCanvasWidth(zoom);
centerY *= getCanvasHeight(zoom);
moveCanvas(viewportHeight / 2 - centerY, viewportWidth / 2 - centerX);
updateTiles(old_zoom);
updateDots(old_zoom);
}
function resizeViewport (is_init, is_incr) {
var el, centerX, centerY, new_zoom;
el = document.getElementById("viewport");
if (is_init) {
viewportWidth = el.clientWidth;
viewportHeight = el.clientHeight;
} else {
var change;
centerX = (-pixel2number(canvas.style.left) + viewportWidth / 2) / getCanvasWidth(zoom);
centerY = (-pixel2number(canvas.style.top) + viewportHeight / 2) / getCanvasHeight(zoom);
change = document.getElementById("change_viewport_by").value;
if (is_incr) {
viewportWidth = Math.round(viewportWidth * change);
viewportHeight = Math.round(viewportHeight * change);
} else {
viewportWidth = Math.round(viewportWidth / change);
viewportHeight = Math.round(viewportHeight / change);
if (viewportWidth < tileSizes[0][0] && viewportHeight < tileSizes[0][1])
{
viewportWidth = tileSizes[0][0];
viewportHeight = tileSizes[0][1];
}
}
el.style.width = number2pixel(viewportWidth);
el.style.height = number2pixel(viewportHeight);
// adapt width of header
var viewport_table = document.getElementById("viewport_table");
var vp_style = window.getComputedStyle(viewport_table);
var vp_width = viewport_table.clientWidth + 1 * vp_style.borderLeftWidth.slice(0, -2) + 1 * vp_style.borderRightWidth.slice(0, -2);
var body_width = document.getElementsByTagName("body")[0].clientWidth;
document.getElementsByTagName("header")[0].style.width = (body_width > vp_width ? body_width : vp_width) + 'px';
}
// size for list of add. stations
el = document.getElementById("morestations");
el.style.height = number2pixel(viewportHeight
+ document.getElementById("scrollup").clientHeight
+ 5); // borders etc.
if (is_init)
return;
// increase zoom if necessary for new viewport size
new_zoom = zoom;
while ( new_zoom < MAX_ZOOM
&& ( viewportWidth > getCanvasWidth(new_zoom)
|| viewportHeight > getCanvasHeight(new_zoom)))
new_zoom++;
if (new_zoom == zoom) {
centerX *= getCanvasWidth(zoom);
centerY *= getCanvasHeight(zoom);
moveCanvas(viewportHeight / 2 - centerY, viewportWidth / 2 - centerX);
updateTiles(zoom);
updateDots(zoom);
while ( new_zoom > 0
&& viewportWidth <= getCanvasWidth(new_zoom - 1)
&& viewportHeight <= getCanvasHeight(new_zoom - 1))
{
new_zoom--;
setDisabled(["zoom_" + new_zoom], 0);
}
while (new_zoom > 0) {
new_zoom--;
setDisabled(["zoom_" + new_zoom], 1);
}
} else if (new_zoom > zoom) {
for (var ii = zoom; ii < new_zoom; ii++)
setDisabled(["zoom_" + ii], 1);
setDisabled(["zoom_" + new_zoom], 0, 1);
setZoom(new_zoom, centerX, centerY);
}
}
function getStationPos (loc) {
var posX, posY;
if (!loc)
return undefined;
if ("NS".indexOf(loc.substring(4, 5)) >= 0) {
posX = str2coord(loc.substring(5, 11));
posY = str2coord(loc.substring(0, 5));
} else {
posX = str2coord(loc.substring(7, 15));
posY = str2coord(loc.substring(0, 7));
}
// convert to 0..1
posX = posX / 360 + 0.5;
posY = -posY / 180 + 0.5;
return [posX, posY];
}
function centerDot (lat, lon) {
zoom = -1; // force centering
setZoom(MAX_ZOOM, lat, lon);
document.getElementById("zoom_" + MAX_ZOOM).checked = true;
}
function scrollCanvas (scrollX, scrollY) {
if (scrollCanvasRepeat == 0)
return;
moveCanvas(parseFloat(pixel2number(canvas.style.top) + scrollY),
parseFloat(pixel2number(canvas.style.left) + scrollX));
updateTiles(zoom);
updateDots(zoom);
if (scrollCanvasRepeat < 3) {
var repeats = [ 500, 100 ];
if (scrollCanvasTimer != "undefined")
clearTimeout(scrollCanvasTimer);
scrollCanvasTimer =
setInterval(function () { scrollCanvas(scrollX, scrollY) },
repeats[scrollCanvasRepeat - 1]);
scrollCanvasRepeat++;
}
}
function startScrollCanvas (scrollX, scrollY) {
scrollCanvasRepeat = 1;
scrollCanvas(scrollX, scrollY);
}
function stopScrollCanvas () {
scrollCanvasRepeat = 0;
if (scrollCanvasTimer != "undefined")
clearTimeout(scrollCanvasTimer);
scrollCanvasTimer = "undefined";
}
function zoomIn (centerX, centerY) {
showStationInfo(-1);
setZoom(zoom + 3, centerX / getCanvasWidth(zoom),
centerY / getCanvasHeight(zoom));
document.getElementById("zoom_" + zoom).checked = true;
}
function setSrcMetaf (new_source) {
src_metaf = new_source;
setHref(0);
}
function setSrcSynop (new_source) {
src_synop = new_source;
setHref(0);
}
function setSrcBuoy (new_source) {
src_buoy = new_source;
setHref(0);
}
function setSrcAmdar (new_source) {
src_amdar = new_source;
setHref(0);
}
function setSynopType () {
synop_type = 0;
if (document.getElementById("synop_any").checked)
synop_type = 1;
if (document.getElementById("synop_nonstandard").checked)
synop_type |= 2;
if (document.getElementById("synop_inter").checked)
synop_type |= 4;
if (document.getElementById("synop_main").checked)
synop_type |= 8;
}
function setChartDot (which) {
var is_checked, bg_css;
bg_css = ".dot_chart { background-image: none; }";
if (which == "init") {
is_checked = 1;
document.getElementById("chartdot").checked = 1;
} else {
is_checked = document.getElementById("chartdot").checked;
for (var i = document.styleSheets[0]['cssRules'].length - 1; i >= 0; i--)
{
var s;
s = document.styleSheets[0]['cssRules'][i].cssText;
if (s != undefined && bg_css == s) {
document.styleSheets[0].deleteRule(i);
break;
}
}
}
if (!is_checked)
document.styleSheets[0].insertRule(bg_css, document.styleSheets[0]['cssRules'].length);
}
function setChartInfo (which) {
var css;
css = [];
css["none"] = ".js, .chart *";
css["wind"] = ".js, .chartP, .chartp, .chartR, .chartTg, .chartTm, .chartTa, .chartTd, .chartCL";
css["cloud"] = ".chartW, " + css["wind"];
if (which == "init") {
document.getElementById("chartnone").checked = true;
which = "none";
} else {
for (var i = document.styleSheets[0]['cssRules'].length - 1; i >= 0; i--)
{
var s;
s = document.styleSheets[0]['cssRules'][i].selectorText;
if ( s != undefined
&& ( s == css["none"]
|| s == css["cloud"]
|| s == css["wind"]))
{
document.styleSheets[0].deleteRule(i);
break;
}
}
}
if (which != "all")
document.styleSheets[0].insertRule(css[which] + " { display: none; }", document.styleSheets[0]['cssRules'].length);
if (which == "none") {
document.getElementById("chartdot").checked = 1;
setChartDot();
}
}
function getButtonTitle (which) {
return {
"close de": "Ansicht schließen",
"close en": "close view",
"close es": "cerrar la vista",
"hide data de": "Ansicht verstecken",
"hide data en": "hide view",
"hide data es": "tapa la vista",
"show data de": "Ansicht zeigen",
"show data en": "show view",
"show data es": "mostra la vista",
"hide detail de": "Detailansicht verstecken",
"hide detail en": "hide detailed view",
"hide detail es": "tapa la vista detallada",
"show detail de": "Detailansicht zeigen",
"show detail en": "show detailed view",
"show detail es": "mostra la vista detallada",
}[which + " " + lang];
}
function mkButton (state, type, id, func) {
var button;
button = document.createElement("button");
if (type != "")
button.id = "button_toggle_" + type + "_" + id;
button.className = "button_" + state;
button.onclick = func;
button.title = getButtonTitle(state + " " + type);
return button;
}
function appButtonToggleView (element, state, type, id, text) {
element.appendChild(mkButton(state, type, id,
function() { toggleView(type, id)}));
if (text != "")
element.appendChild(document.createTextNode(text));
}
// add station info to /data/stations
function addInfo (response, id) {
var info, station, stations;
// use "response" to avoid conversion of tag name to lower case
station = response.createElement("station");
info = new makeStationInfo(id);
if (info.wmo != "")
station.setAttribute("wmo", info.wmo);
if (info.ship != "")
station.setAttribute("ship", info.ship);
if (info.mobil != "")
station.setAttribute("mobil", info.mobil);
if (info.icao != "")
station.setAttribute("icao", info.icao);
if (info.buoy != "")
station.setAttribute("buoy", info.buoy);
if (info.ac != "")
station.setAttribute("ac", info.ac);
if (info.nat != "")
station.setAttribute("nat", info.nat);
station.appendChild(response.createTextNode(info.name));
stations = response.createElement("stations");
stations.appendChild(station);
return stations;
}
function get_cols (tr) {
var cols;
cols = 0;
for (var i = 0; i < tr.children.length; i++)
if (tr.children[i].nodeName == "TH")
cols += tr.children[i].colSpan;
return cols;
}
function displayData (req) {
/*
** The DOM structure relevant for displaying data is as follows
** BODY
** ...
** DIV views
** DIV #view_+view_no[0..n] (for each request)
** BR
** BUTTON .button_close
** (onclick: closeView('view_'+view_no))
** BUTTON #button_toggle_data_view_+view_no (hide(-) or show(+) button)
** (onclick: toggleView('data',view_no))
** DIV #data_view_+view_no
** DIV .output (from metaf-sum.xsl)
** ...
** TABLE[0..o] (contain summary data)
** ...
** TR #detail_+view_no+row_no
** TD
** TABLE (contains detailed data)
** ...
*/
var data, view, id, response, data_xml, det_html, sum_html, div, posXY;
var noData = {
"de": "(keine Daten)",
"en": "(no data)",
"es": "(no hay datos)",
};
id = "view_" + req.view_no;
data = document.getElementById(id);
if (!data) { // was the request already closed by the user?
req.data.abort();
return;
}
// check if request is complete
if (req.data.readyState != 4) {
data.replaceChild(document.createTextNode(req.info_full + " loading ... " + req.data.readyState), data.childNodes[3]);
return;
}
div = document.createElement("div");
div.style.display = "inline-block";
posXY = getStationPos(stations[req.station].getAttribute("loc"));
if (posXY) {
div.style.cursor = "pointer";
div.onclick = function() { centerDot(posXY[0], posXY[1]); };
}
div.appendChild(document.createTextNode(req.info_full));
data.replaceChild(div, data.childNodes[3]);
if (checkError(data, req.data, req.info_full, "load weather data",
req.data_url))
{
data.removeChild(data.childNodes[2]); // toggle_view button
return;
}
if (window.ActiveXObject !== undefined)
response = req.data;
else
response = req.data.responseXML;
setSrc(response.getElementsByTagName("options")[0], false);
// container for summary view
view = document.createElement("div");
view.id = "data_" + id;
view.style.verticalAlign = "bottom";
// add translation and station data
data_xml = response.getElementsByTagName("data")[0];
data_xml.appendChild(trans[lang].trans);
data_xml.appendChild(trans["sum"].transsum);
data_xml.appendChild(addInfo(response, req.station));
// ActiveX returns the HTML as string. use via DOM
det_html = document.createElement("div");
if (window.ActiveXObject !== undefined)
det_html.innerHTML = processXSL_ActiveX(response, xsl_detailed, noData[lang]);
else
det_html.appendChild(processXSL(response, xsl_detailed, noData[lang]));
if (window.ActiveXObject !== undefined)
view.innerHTML = processXSL_ActiveX(response, xsl_summary, noData[lang]);
else
view.appendChild(processXSL(response, xsl_summary, noData[lang]));
data.appendChild(view);
// find rows from summary tables
var sum_trs = [];
var sum_cols = [];
var sum_tr_use = [];
sum_html = view.getElementsByTagName("table");
for (var i = 0; i < sum_html.length; i++) {
var cols = 0;
var trs = sum_html[i].getElementsByTagName("tr");
for (var j = 0; j < trs.length; j++) {
if (j == 0)
cols = get_cols(trs[j]);
sum_trs.push(trs[j]);
sum_cols.push(cols);
sum_tr_use.push(-1);
}
}
// prepend button to rows from summary tables, mark rows used for append
var next_row;
var seq = 0;
for (var i = 0; i < sum_trs.length; i++) {
if (sum_trs[i].children[0].nodeName == "TH") {
sum_trs[i].insertBefore(document.createElement("th"),
sum_trs[i].children[0]);
next_row = i + 1;
} else if (sum_trs[i].children[0].nodeName == "TD") {
if (next_row == i) {
var td;
td = document.createElement("td");
td.rowSpan = sum_trs[i].children[0].rowSpan;
appButtonToggleView(td, "show", "detail",
req.view_no + "_" + seq, "");
sum_trs[i].insertBefore(td, sum_trs[i].children[0]);
next_row += td.rowSpan;
sum_tr_use[i + td.rowSpan - 1] = seq;
seq++;
}
}
}
// append tables from details to table rows from summary
var det_tables = det_html.getElementsByTagName("table");
for (var i = sum_trs.length - 1; i >= 0; i--) {
var td, tr;
if (sum_tr_use[i] == -1)
continue;
tr = document.createElement("tr");
tr.id = "detail_" + req.view_no + "_" + sum_tr_use[i];
tr.style.display = "none";
td = document.createElement("td");
td.setAttribute("colspan", sum_cols[i] + 1);
td.appendChild(det_tables[sum_tr_use[i]]);
tr.appendChild(td);
if (sum_trs[i].nextSibling)
sum_trs[i].parentNode.insertBefore(tr, sum_trs[i].nextSibling);
else
sum_trs[i].parentNode.appendChild(tr);
}
}
function fetchData (i) {
/*
** prepare display of data, start asynchronous download of data.
** the DOM structure relevant for displaying data is described in
** displayData()
*/
var info, url, req, data, views, delimit, station, id;
url = "cgi-bin/metaf.pl" + version + "&format=xml&mode=summary&gui="
+ "&end_date=" + document.getElementById("end_date").value
+ "&hours=" + document.getElementById("hours").value;
info = new makeStationInfo(i);
/*
** assemble URL to fetch XML data
*/
url += "&src_metaf=" + src_metaf;
if (info.icao != "")
url += "&type_metaf=icao&msg_metaf=" + info.icao;
delimit = "";
url += "&src_synop=" + src_synop;
if ( info.wmo + info.ship + info.mobil + info.nat != ""
&& synop_type != 0)
{
url += "&type_synop=";
if (info.wmo != "") {
station = info.wmo;
url += "wmo";
} else if (info.ship != "") {
station = info.ship;
url += "ship";
} else if (info.mobil != "") {
station = info.mobil;
url += "mobil";
} else {
station = info.nat;
url += "nat";
}
url += "&msg_synop=";
if (synop_type & 1) {
url += station;
delimit = " ";
}
if (synop_type & 2) {
url += delimit + "SN-" + station + " ISN-" + station;
delimit = " ";
}
if (synop_type & 4) {
url += delimit + "SI-" + station + " ISI-" + station;
delimit = " ";
}
if (synop_type & 8)
url += delimit + "SM-" + station + " ISM-" + station;
}
url += "&src_buoy=" + src_buoy;
if (info.buoy != "")
url += "&type_buoy=wmo&msg_buoy=" + info.buoy;
url += "&src_amdar=" + src_amdar;
if (info.ac != "")
url += "&type_amdar=ac&msg_amdar=" + info.ac;
/*
** create request + init
*/
req = new Object();
req.info_full = info.info;
req.station = i;
req.view_no = view_no++;
req.data_url = url;
/*
** create container for data
*/
id = "view_" + req.view_no;
data = document.createElement("div");
data.id = id;
data.appendChild(document.createElement("br"));
data.appendChild(mkButton("close", "", "", function() {closeView(id)}));
appButtonToggleView(data, "hide", "data", id, req.info_full);
views = document.getElementById("views");
if (views.firstChild)
views.insertBefore(data, views.firstChild);
else
views.appendChild(data);
/*
** start request
*/
if (window.ActiveXObject !== undefined) {
req.data = getXML_ActiveX(req.data_url);
displayData(req);
} else if (window.XMLHttpRequest) {
req.data = getXMLXSL(req.data_url);
req.data.onreadystatechange = function () { displayData(req) };
req.data.send(null);
} else
throw new Error("This browser cannot create XML HTTP requests");
}
function getXMLXSL (url) {
var req;
req = new XMLHttpRequest();
req.open("GET", url, true);
req.overrideMimeType("application/xml");
return req;
}
function processXSL (xml, xsl, noData) {
var frag;
if ( xml.getElementsByTagName("metar").length == 0
&& xml.getElementsByTagName("taf").length == 0
&& xml.getElementsByTagName("synop").length == 0
&& xml.getElementsByTagName("buoy").length == 0
&& xml.getElementsByTagName("amdar").length == 0)
return document.createTextNode(noData);
try {
frag = xsl.transformToFragment(xml, document);
} catch (e) {
if (e != "") return document.createTextNode("ERROR: " + e);
}
return frag == null ? document.createTextNode("ERROR: transformToFragment failed!") : frag;
}
// synchronous to avoid parallel transform()
// avoid MSXML2.XMLHTTP: IE does not send requests but uses cached data!?!
function getXML_ActiveX (url) {
var xml;
xml = new ActiveXObject("MSXML2.DOMDocument");
xml.async = false;
xml.validateOnParse = false;
xml.load(url);
return xml;
}
function getXSL_ActiveX (req) {
var xsl;
xsl = new ActiveXObject("MSXML2.FreeThreadedDOMDocument");
xsl.async = true;
xsl.validateOnParse = false;
xsl.onreadystatechange = function () { initStaticData(req) };
return xsl;
}
function processXSL_ActiveX (xml, xsl, noData) {
if ( xml.getElementsByTagName("metar").length == 0
&& xml.getElementsByTagName("taf").length == 0
&& xml.getElementsByTagName("synop").length == 0
&& xml.getElementsByTagName("buoy").length == 0
&& xml.getElementsByTagName("amdar").length == 0)
return noData;
xsl.input = xml;
xsl.transform();
return xsl.output;
}
function toggleView (type, id) {
var element, button;
id = type + "_" + id;
element = document.getElementById(id);
button = document.getElementById("button_toggle_" + id);
if (element && button)
if (element.style.display == "none") {
element.style.display = "";
button.className = "button_hide";
button.title = getButtonTitle("hide " + type);
} else {
element.style.display = "none";
button.className = "button_show";
button.title = getButtonTitle("show " + type);
}
}
function closeView (id) {
var div = document.getElementById(id);
div.parentNode.removeChild(div);
}
window.onload = start;