Initial import: WebAisMap
Closes TG-4
This commit is contained in:
+6077
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
{"273":"RU","275":"LV","277":"LT","276":"EE","272":"UA","261":"PL","211":"DE","218":"DE","226":"FR","227":"FR","228":"FR","247":"IT","257":"NO","258":"NO","259":"NO","265":"SE","266":"SE","230":"FI","219":"DK","220":"DK","244":"NL","245":"NL","246":"NL","205":"BE","224":"ES","225":"ES","237":"GR","239":"GR","240":"GR","241":"GR","271":"TR","264":"RO","207":"BG","238":"HR","232":"GB","233":"GB","234":"GB","235":"GB","250":"IE","251":"IS","215":"MT","229":"MT","248":"MT","249":"MT","256":"MT","209":"CY","210":"CY","212":"CY","338":"US","366":"US","367":"US","368":"US","369":"US","316":"CA","412":"CN","413":"CN","414":"CN","431":"JP","432":"JP","440":"KR","441":"KR","563":"SG","564":"SG","565":"SG","566":"SG","419":"IN","503":"AU","710":"BR","701":"AR","351":"PA","352":"PA","353":"PA","354":"PA","355":"PA","356":"PA","357":"PA","370":"PA","371":"PA","372":"PA","373":"PA","374":"PA","636":"LR","637":"LR","538":"MH","308":"BS","309":"BS","311":"BS","477":"HK","416":"TW","574":"VN","525":"ID","533":"MY","548":"PH","567":"TH","403":"SA","470":"AE","471":"AE","428":"IL","622":"EG","601":"ZA","512":"NZ","345":"MX","725":"CL","263":"PT","269":"CH","203":"AT","270":"CZ","243":"HU","279":"RS","278":"SI","267":"SK","262":"ME","201":"AL","213":"GE","436":"KZ","422":"IR"}
|
||||
@@ -0,0 +1,473 @@
|
||||
/**
|
||||
* Редактор габаритов (ITU Fig. 38).
|
||||
* Корма — L, правый борт — W (доли A/L и C/W фиксируются на время жеста); точка GPS — перетаскивание.
|
||||
* Для роста L/W координаты могут выходить за контур корпуса (опорный масштаб wPxRef/hPxRef с pointerdown).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var NS = 'http://www.w3.org/2000/svg';
|
||||
|
||||
var MIN_LEN = 20;
|
||||
var MIN_BEAM = 6;
|
||||
var MAX_AB = 511;
|
||||
var MAX_CD = 63;
|
||||
var MAX_L = MAX_AB + MAX_AB;
|
||||
var MAX_W = MAX_CD + MAX_CD;
|
||||
|
||||
/** Макс. размер корпуса в пикселях (пропорции сохраняются) */
|
||||
var MAX_DRAW_W = 175;
|
||||
var MAX_DRAW_H = 210;
|
||||
/** Минимум по меньшей стороне корпуса в px — иначе ручки и клампы «схлопываются» */
|
||||
var MIN_HULL_PX = 48;
|
||||
|
||||
var PAD_L = 12;
|
||||
var PAD_T = 48;
|
||||
var PAD_R = 78;
|
||||
var PAD_B = 42;
|
||||
|
||||
var svg, inner, hull, marker, handles;
|
||||
var gridH, gridV, lblBow, lblStern, dimBeam, dimLength;
|
||||
var drag = null;
|
||||
|
||||
/** Текущая геометрия (обновляется в refresh) */
|
||||
var layout = {
|
||||
wPx: 100,
|
||||
hPx: 160,
|
||||
dispL: MIN_LEN,
|
||||
dispW: MIN_BEAM,
|
||||
};
|
||||
|
||||
function clamp(n, lo, hi) {
|
||||
return Math.max(lo, Math.min(hi, n));
|
||||
}
|
||||
|
||||
function el(name, attrs) {
|
||||
var e = document.createElementNS(NS, name);
|
||||
if (attrs) {
|
||||
Object.keys(attrs).forEach(function (k) {
|
||||
e.setAttribute(k, attrs[k]);
|
||||
});
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
function readDims() {
|
||||
var A = parseInt(document.getElementById('tp-to-bow').value, 10) || 0;
|
||||
var B = parseInt(document.getElementById('tp-to-stern').value, 10) || 0;
|
||||
var C = parseInt(document.getElementById('tp-to-port').value, 10) || 0;
|
||||
var D = parseInt(document.getElementById('tp-to-starboard').value, 10) || 0;
|
||||
A = clamp(A, 0, MAX_AB);
|
||||
B = clamp(B, 0, MAX_AB);
|
||||
C = clamp(C, 0, MAX_CD);
|
||||
D = clamp(D, 0, MAX_CD);
|
||||
return { A: A, B: B, C: C, D: D, L: A + B, W: C + D };
|
||||
}
|
||||
|
||||
function writeDims(A, B, C, D) {
|
||||
A = clamp(Math.round(A), 0, MAX_AB);
|
||||
B = clamp(Math.round(B), 0, MAX_AB);
|
||||
C = clamp(Math.round(C), 0, MAX_CD);
|
||||
D = clamp(Math.round(D), 0, MAX_CD);
|
||||
document.getElementById('tp-to-bow').value = A;
|
||||
document.getElementById('tp-to-stern').value = B;
|
||||
document.getElementById('tp-to-port').value = C;
|
||||
document.getElementById('tp-to-starboard').value = D;
|
||||
}
|
||||
|
||||
function displayLW(d) {
|
||||
var L = d.L > 0 ? d.L : MIN_LEN;
|
||||
var W = d.W > 0 ? d.W : MIN_BEAM;
|
||||
return { L: L, W: W, template: d.L === 0 && d.W === 0 };
|
||||
}
|
||||
|
||||
function hullPath(w, h) {
|
||||
var bow = Math.min(20, h * 0.11);
|
||||
var tipX = w / 2;
|
||||
return (
|
||||
'M ' + tipX + ',0 L ' + w + ',' + bow + ' L ' + w + ',' + h + ' L 0,' + h + ' L 0,' + bow + ' Z'
|
||||
);
|
||||
}
|
||||
|
||||
function computeLayout(d, disp) {
|
||||
var scale = Math.min(MAX_DRAW_W / disp.W, MAX_DRAW_H / disp.L);
|
||||
if (!isFinite(scale) || scale <= 0) scale = 1;
|
||||
var wPx0 = disp.W * scale;
|
||||
var hPx0 = disp.L * scale;
|
||||
var bump = 1;
|
||||
if (wPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(wPx0, 1e-6));
|
||||
if (hPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(hPx0, 1e-6));
|
||||
scale *= bump;
|
||||
var wPx = disp.W * scale;
|
||||
var hPx = disp.L * scale;
|
||||
layout.wPx = wPx;
|
||||
layout.hPx = hPx;
|
||||
layout.dispL = disp.L;
|
||||
layout.dispW = disp.W;
|
||||
layout.scale = scale;
|
||||
return { sx: scale, sy: scale, wPx: wPx, hPx: hPx };
|
||||
}
|
||||
|
||||
function scales(d, disp, geo) {
|
||||
var wPx = geo.wPx;
|
||||
var hPx = geo.hPx;
|
||||
var padX = Math.max(1, Math.min(8, wPx * 0.1));
|
||||
var padY = Math.max(1, Math.min(8, hPx * 0.1));
|
||||
var aVis = d.L > 0 ? d.A : disp.L / 2;
|
||||
var cVis = d.W > 0 ? d.C : disp.W / 2;
|
||||
var mx = clamp(cVis * geo.sx, padX, wPx - padX);
|
||||
var my = clamp(aVis * geo.sy, padY, hPx - padY);
|
||||
return { mx: mx, my: my };
|
||||
}
|
||||
|
||||
function ensureNonZeroDims() {
|
||||
var d = readDims();
|
||||
if (d.L === 0 && d.W === 0) {
|
||||
writeDims(MIN_LEN / 2, MIN_LEN / 2, MIN_BEAM / 2, MIN_BEAM / 2);
|
||||
}
|
||||
}
|
||||
|
||||
function clearG(g) {
|
||||
while (g.firstChild) g.removeChild(g.firstChild);
|
||||
}
|
||||
|
||||
function rebuildBeamDimension(g, wPx, hPx, Wm) {
|
||||
clearG(g);
|
||||
var bow = Math.min(20, hPx * 0.11);
|
||||
var off = 24;
|
||||
var y = -off;
|
||||
var yPast = y - 1.5;
|
||||
g.appendChild(
|
||||
el('line', { class: 'ship-dim-ext', x1: 0, y1: bow, x2: 0, y2: yPast })
|
||||
);
|
||||
g.appendChild(
|
||||
el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: wPx, y2: yPast })
|
||||
);
|
||||
g.appendChild(
|
||||
el('line', {
|
||||
class: 'ship-dim-main',
|
||||
x1: 0,
|
||||
y1: y,
|
||||
x2: wPx,
|
||||
y2: y,
|
||||
'marker-start': 'url(#ship-dim-arrow)',
|
||||
'marker-end': 'url(#ship-dim-arrow)',
|
||||
})
|
||||
);
|
||||
var t = el('text', {
|
||||
class: 'ship-dim-txt',
|
||||
x: wPx / 2,
|
||||
y: y - 8,
|
||||
'text-anchor': 'middle',
|
||||
});
|
||||
t.textContent = 'W = ' + Wm + ' м';
|
||||
g.appendChild(t);
|
||||
}
|
||||
|
||||
function rebuildLengthDimension(g, wPx, hPx, Lm) {
|
||||
clearG(g);
|
||||
var bow = Math.min(20, hPx * 0.11);
|
||||
var off = 22;
|
||||
var x = wPx + off;
|
||||
var xPast = x + 1.5;
|
||||
g.appendChild(
|
||||
el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: x, y2: bow })
|
||||
);
|
||||
g.appendChild(
|
||||
el('line', { class: 'ship-dim-ext', x1: x, y1: bow, x2: x, y2: 0 })
|
||||
);
|
||||
g.appendChild(
|
||||
el('line', { class: 'ship-dim-ext', x1: wPx, y1: hPx, x2: xPast, y2: hPx })
|
||||
);
|
||||
g.appendChild(
|
||||
el('line', {
|
||||
class: 'ship-dim-main',
|
||||
x1: x,
|
||||
y1: 0,
|
||||
x2: x,
|
||||
y2: hPx,
|
||||
'marker-start': 'url(#ship-dim-arrow)',
|
||||
'marker-end': 'url(#ship-dim-arrow)',
|
||||
})
|
||||
);
|
||||
var t = el('text', {
|
||||
class: 'ship-dim-txt',
|
||||
x: x + 14,
|
||||
y: hPx / 2,
|
||||
'text-anchor': 'middle',
|
||||
transform: 'rotate(-90 ' + (x + 14) + ' ' + hPx / 2 + ')',
|
||||
});
|
||||
t.textContent = 'L = ' + Lm + ' м';
|
||||
g.appendChild(t);
|
||||
}
|
||||
|
||||
function positionHandles(wPx, hPx) {
|
||||
if (!handles) return;
|
||||
var stern = handles.querySelector('[data-ship-edge="stern"]');
|
||||
var sb = handles.querySelector('[data-ship-edge="starboard"]');
|
||||
if (stern) stern.setAttribute('transform', 'translate(' + wPx / 2 + ',' + hPx + ')');
|
||||
if (sb) sb.setAttribute('transform', 'translate(' + wPx + ',' + hPx / 2 + ')');
|
||||
}
|
||||
|
||||
function refreshFromInputs() {
|
||||
if (!svg || !inner || !hull || !marker) return;
|
||||
var d = readDims();
|
||||
var disp = displayLW(d);
|
||||
var geo = computeLayout(d, disp);
|
||||
var sc = scales(d, disp, geo);
|
||||
var wPx = geo.wPx;
|
||||
var hPx = geo.hPx;
|
||||
|
||||
inner.setAttribute('transform', 'translate(' + PAD_L + ',' + PAD_T + ')');
|
||||
|
||||
var vbW = PAD_L + wPx + PAD_R;
|
||||
var vbH = PAD_T + hPx + PAD_B;
|
||||
svg.setAttribute('viewBox', '0 0 ' + vbW + ' ' + vbH);
|
||||
|
||||
rebuildBeamDimension(dimBeam, wPx, hPx, disp.W);
|
||||
rebuildLengthDimension(dimLength, wPx, hPx, disp.L);
|
||||
|
||||
hull.setAttribute('d', hullPath(wPx, hPx));
|
||||
|
||||
if (gridH && gridV) {
|
||||
gridH.setAttribute('x1', 0);
|
||||
gridH.setAttribute('y1', sc.my);
|
||||
gridH.setAttribute('x2', wPx);
|
||||
gridH.setAttribute('y2', sc.my);
|
||||
gridV.setAttribute('x1', sc.mx);
|
||||
gridV.setAttribute('y1', 0);
|
||||
gridV.setAttribute('x2', sc.mx);
|
||||
gridV.setAttribute('y2', hPx);
|
||||
}
|
||||
|
||||
if (lblBow) {
|
||||
lblBow.setAttribute('x', wPx / 2);
|
||||
lblBow.setAttribute('y', -38);
|
||||
}
|
||||
if (lblStern) {
|
||||
lblStern.setAttribute('x', wPx / 2);
|
||||
lblStern.setAttribute('y', hPx + 22);
|
||||
}
|
||||
|
||||
marker.setAttribute('transform', 'translate(' + sc.mx + ',' + sc.my + ')');
|
||||
marker.setAttribute('class', 'ship-gps-group' + (disp.template ? ' ship-gps-group--template' : ''));
|
||||
|
||||
positionHandles(wPx, hPx);
|
||||
}
|
||||
|
||||
function svgPointFromClient(clientX, clientY) {
|
||||
var pt = svg.createSVGPoint();
|
||||
pt.x = clientX;
|
||||
pt.y = clientY;
|
||||
var ctm = inner.getScreenCTM();
|
||||
if (!ctm) return null;
|
||||
var p = pt.matrixTransform(ctm.inverse());
|
||||
return { x: p.x, y: p.y };
|
||||
}
|
||||
|
||||
function splitLength(u, Ls) {
|
||||
u = clamp(u, 0, 1);
|
||||
var A = Math.round(u * Ls);
|
||||
A = clamp(A, 0, MAX_AB);
|
||||
var B = Ls - A;
|
||||
if (B > MAX_AB) {
|
||||
B = MAX_AB;
|
||||
A = clamp(Ls - B, 0, MAX_AB);
|
||||
}
|
||||
if (B < 0) {
|
||||
B = 0;
|
||||
A = clamp(Ls, 0, MAX_AB);
|
||||
}
|
||||
return { A: A, B: B };
|
||||
}
|
||||
|
||||
function splitBeam(v, Ws) {
|
||||
v = clamp(v, 0, 1);
|
||||
var C = Math.round(v * Ws);
|
||||
C = clamp(C, 0, MAX_CD);
|
||||
var D = Ws - C;
|
||||
if (D > MAX_CD) {
|
||||
D = MAX_CD;
|
||||
C = clamp(Ws - D, 0, MAX_CD);
|
||||
}
|
||||
if (D < 0) {
|
||||
D = 0;
|
||||
C = clamp(Ws, 0, MAX_CD);
|
||||
}
|
||||
return { C: C, D: D };
|
||||
}
|
||||
|
||||
/** Новая длина L; сохраняем долю носа A/L ≈ rA. */
|
||||
function abFromLength(Ln, rA) {
|
||||
Ln = clamp(Math.round(Ln), 1, MAX_L);
|
||||
var r = clamp(isFinite(rA) ? rA : 0.5, 0, 1);
|
||||
var A = Math.round(r * Ln);
|
||||
A = clamp(A, 0, MAX_AB);
|
||||
var B = Ln - A;
|
||||
if (B > MAX_AB) {
|
||||
B = MAX_AB;
|
||||
A = clamp(Ln - B, 0, MAX_AB);
|
||||
}
|
||||
if (B < 0) {
|
||||
B = 0;
|
||||
A = clamp(Ln, 0, MAX_AB);
|
||||
}
|
||||
return { A: A, B: B };
|
||||
}
|
||||
|
||||
/** Новая ширина W; сохраняем долю порта C/W ≈ rC. */
|
||||
function cdFromWidth(Wn, rC) {
|
||||
Wn = clamp(Math.round(Wn), 1, MAX_W);
|
||||
var r = clamp(isFinite(rC) ? rC : 0.5, 0, 1);
|
||||
var C = Math.round(r * Wn);
|
||||
C = clamp(C, 0, MAX_CD);
|
||||
var D = Wn - C;
|
||||
if (D > MAX_CD) {
|
||||
D = MAX_CD;
|
||||
C = clamp(Wn - D, 0, MAX_CD);
|
||||
}
|
||||
if (D < 0) {
|
||||
D = 0;
|
||||
C = clamp(Wn, 0, MAX_CD);
|
||||
}
|
||||
return { C: C, D: D };
|
||||
}
|
||||
|
||||
function startDrag(ev, kind, captureEl) {
|
||||
ev.preventDefault();
|
||||
captureEl.setPointerCapture(ev.pointerId);
|
||||
document.body.classList.add('ship-editor-dragging');
|
||||
document.addEventListener('pointermove', onDocumentPointerMove);
|
||||
document.addEventListener('pointerup', onDocumentPointerEnd);
|
||||
document.addEventListener('pointercancel', onDocumentPointerEnd);
|
||||
return { kind: kind, pid: ev.pointerId, el: captureEl };
|
||||
}
|
||||
|
||||
function stopDragListeners() {
|
||||
document.removeEventListener('pointermove', onDocumentPointerMove);
|
||||
document.removeEventListener('pointerup', onDocumentPointerEnd);
|
||||
document.removeEventListener('pointercancel', onDocumentPointerEnd);
|
||||
}
|
||||
|
||||
function onInnerPointerDown(ev) {
|
||||
if (!inner) return;
|
||||
var edgeG = ev.target.closest ? ev.target.closest('[data-ship-edge]') : null;
|
||||
if (edgeG) {
|
||||
ensureNonZeroDims();
|
||||
var d0 = readDims();
|
||||
var disp0 = displayLW(d0);
|
||||
var geo0 = computeLayout(d0, disp0);
|
||||
var kind = edgeG.getAttribute('data-ship-edge');
|
||||
drag = startDrag(ev, kind, edgeG);
|
||||
drag.L0 = d0.L;
|
||||
drag.W0 = d0.W;
|
||||
drag.rA = d0.L > 0 ? d0.A / d0.L : 0.5;
|
||||
drag.rC = d0.W > 0 ? d0.C / d0.W : 0.5;
|
||||
drag.wPxRef = geo0.wPx;
|
||||
drag.hPxRef = geo0.hPx;
|
||||
return;
|
||||
}
|
||||
if (marker && marker.contains(ev.target)) {
|
||||
ensureNonZeroDims();
|
||||
var dg = readDims();
|
||||
var Ls = dg.L > 0 ? Math.min(dg.L, MAX_L) : MIN_LEN;
|
||||
var Ws = dg.W > 0 ? Math.min(dg.W, MAX_W) : MIN_BEAM;
|
||||
Ls = clamp(Ls, 1, MAX_L);
|
||||
Ws = clamp(Ws, 1, MAX_W);
|
||||
drag = startDrag(ev, 'gps', marker);
|
||||
drag.Ls = Ls;
|
||||
drag.Ws = Ws;
|
||||
}
|
||||
}
|
||||
|
||||
function onDocumentPointerMove(ev) {
|
||||
if (!drag || ev.pointerId !== drag.pid) return;
|
||||
var p = svgPointFromClient(ev.clientX, ev.clientY);
|
||||
if (!p) return;
|
||||
|
||||
var d = readDims();
|
||||
var disp = displayLW(d);
|
||||
var geo = computeLayout(d, disp);
|
||||
var wPx = geo.wPx;
|
||||
var hPx = geo.hPx;
|
||||
|
||||
if (drag.kind === 'gps') {
|
||||
var u = p.y / hPx;
|
||||
var v = p.x / wPx;
|
||||
var ab = splitLength(u, drag.Ls);
|
||||
var cd = splitBeam(v, drag.Ws);
|
||||
writeDims(ab.A, ab.B, cd.C, cd.D);
|
||||
refreshFromInputs();
|
||||
return;
|
||||
}
|
||||
|
||||
var wRef = drag.wPxRef;
|
||||
var hRef = drag.hPxRef;
|
||||
if (drag.kind === 'stern' && wRef > 0 && hRef > 0) {
|
||||
var yMin = (hRef * 1) / Math.max(drag.L0, 1);
|
||||
var yMax = (hRef * MAX_L) / Math.max(drag.L0, 1);
|
||||
var yS = clamp(p.y, yMin, yMax);
|
||||
var L1 = Math.round((drag.L0 * yS) / hRef);
|
||||
L1 = clamp(L1, 1, MAX_L);
|
||||
var abS = abFromLength(L1, drag.rA);
|
||||
writeDims(abS.A, abS.B, d.C, d.D);
|
||||
} else if (drag.kind === 'starboard' && wRef > 0 && hRef > 0) {
|
||||
var xMin = (wRef * 1) / Math.max(drag.W0, 1);
|
||||
var xMax = (wRef * MAX_W) / Math.max(drag.W0, 1);
|
||||
var xSb = clamp(p.x, xMin, xMax);
|
||||
var W1s = Math.round((drag.W0 * xSb) / wRef);
|
||||
W1s = clamp(W1s, 1, MAX_W);
|
||||
var cd2 = cdFromWidth(W1s, drag.rC);
|
||||
writeDims(d.A, d.B, cd2.C, cd2.D);
|
||||
}
|
||||
|
||||
refreshFromInputs();
|
||||
}
|
||||
|
||||
function onDocumentPointerEnd(ev) {
|
||||
if (!drag || ev.pointerId !== drag.pid) return;
|
||||
stopDragListeners();
|
||||
try {
|
||||
drag.el.releasePointerCapture(ev.pointerId);
|
||||
} catch (e) { /* ignore */ }
|
||||
drag = null;
|
||||
document.body.classList.remove('ship-editor-dragging');
|
||||
}
|
||||
|
||||
function bindInputs() {
|
||||
['tp-to-bow', 'tp-to-stern', 'tp-to-port', 'tp-to-starboard'].forEach(function (id) {
|
||||
var eln = document.getElementById(id);
|
||||
if (eln) {
|
||||
eln.addEventListener('input', refreshFromInputs);
|
||||
eln.addEventListener('change', refreshFromInputs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function boot() {
|
||||
svg = document.getElementById('ship-editor-svg');
|
||||
inner = document.getElementById('ship-editor-inner');
|
||||
hull = document.getElementById('ship-hull');
|
||||
marker = document.getElementById('ship-gps-marker');
|
||||
handles = document.getElementById('ship-edge-handles');
|
||||
gridH = document.getElementById('ship-grid-h');
|
||||
gridV = document.getElementById('ship-grid-v');
|
||||
lblBow = document.getElementById('ship-lbl-bow');
|
||||
lblStern = document.getElementById('ship-lbl-stern');
|
||||
dimBeam = document.getElementById('ship-dim-beam');
|
||||
dimLength = document.getElementById('ship-dim-length');
|
||||
if (!svg || !inner || !hull || !marker) return;
|
||||
|
||||
inner.addEventListener('pointerdown', onInnerPointerDown);
|
||||
bindInputs();
|
||||
refreshFromInputs();
|
||||
}
|
||||
|
||||
window.shipDimsEditorRefresh = refreshFromInputs;
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* ITU-R M.1371-6, табл. 51 — тип судна (идентификатор 0–99).
|
||||
* Подписи на русском по официальным формулировкам (сокращ.: ОПГ — опасные грузы;
|
||||
* ОН — опасные только насыпью; ВВ — вредные вещества; МЗ — морские загрязнители).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var LABELS = [
|
||||
'Не указано',
|
||||
'Научно-исследовательское судно',
|
||||
'Учебное судно',
|
||||
'Судно, принадлежащее или эксплуатируемое государственным органом',
|
||||
'Ледокол',
|
||||
'Судно обслуживания буёв (навигационных знаков)',
|
||||
'Кабелеукладчик',
|
||||
'Трубоукладчик',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Судно специального назначения, дополнительные сведения не указаны',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Судно FPSO (добыча, хранение и отгрузка нефти на месторождении)',
|
||||
'Рыбозавод (плавучий рыбоперерабатывающий завод)',
|
||||
'Судно обеспечения рыбоводческого хозяйства',
|
||||
'Судно оффшорного обеспечения и т. п.',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Судно для строительных работ',
|
||||
'Катер доставки экипажа (crew boat)',
|
||||
'Судно обеспечения, дополнительные сведения не указаны',
|
||||
'Судно на воздушной подушке (WIG), все суда этого типа',
|
||||
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности X (ИМО)',
|
||||
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности Y (ИМО)',
|
||||
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности Z (ИМО)',
|
||||
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'WIG, дополнительные сведения не указаны',
|
||||
'Рыболовное судно',
|
||||
'Буксир',
|
||||
'Буксир; длина буксира >200 м или ширина >25 м',
|
||||
'Земснаряд',
|
||||
'Водолазное судно',
|
||||
'Военный корабль или вспомогательное судно ВМС',
|
||||
'Парусное судно',
|
||||
'Прогулочное моторное судно',
|
||||
'Тральщик',
|
||||
'Патрульное судно',
|
||||
'Высокоскоростное судно (ВСС), все суда этого типа',
|
||||
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
|
||||
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
|
||||
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
|
||||
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'ВСС, перевозка пассажиров',
|
||||
'ВСС Ro-Ro (автомобили / ж/д)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'ВСС, дополнительные сведения не указаны',
|
||||
'Лоцманское судно',
|
||||
'Поисково-спасательное судно',
|
||||
'Буксиры',
|
||||
'Портовое или рыболовное вспомогательное судно',
|
||||
'Противозагрязнение или пожарный резерв',
|
||||
'Судно правоохранительных органов',
|
||||
'Резерв 1 — для назначений местным судам',
|
||||
'Резерв 2 — для назначений местным судам',
|
||||
'Медицинский транспорт (Женевские конвенции 1949 г. и Доп. протоколы)',
|
||||
'Судна государств, не участвующих в вооружённом конфликте',
|
||||
'Пассажирское судно, все суда этого типа',
|
||||
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
|
||||
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
|
||||
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
|
||||
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'Пассажирский лайнер (круизное судно)',
|
||||
'Пассажирский паром',
|
||||
'Пассажирское прогулочное (напр. по гавани, наблюдение за китами)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Пассажирское судно, дополнительные сведения не указаны',
|
||||
'Грузовое судно, все суда этого типа',
|
||||
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
|
||||
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
|
||||
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
|
||||
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'Грузовое судно, балкер',
|
||||
'Грузовое судно, контейнеровоз',
|
||||
'Грузовое судно, Ro-Ro',
|
||||
'Грузовое судно, десантная баржа',
|
||||
'Грузовое судно, дополнительные сведения не указаны',
|
||||
'Танкер, все суда этого типа',
|
||||
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
|
||||
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
|
||||
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
|
||||
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'Танкер, неопасный груз / не загрязняющий',
|
||||
'Составной буксир и танкерная баржа (A–D — буксир и баржа)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Танкер, дополнительные сведения не указаны',
|
||||
'Прочий тип судна',
|
||||
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
|
||||
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
|
||||
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
|
||||
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Зарезервировано (на будущее)',
|
||||
'Прочий тип судна, дополнительные сведения не указаны',
|
||||
];
|
||||
|
||||
var GROUPS = [
|
||||
{ from: 1, to: 9, title: '01–09 Судно специального назначения' },
|
||||
{ from: 10, to: 19, title: '10–19 Судно обеспечения' },
|
||||
{ from: 20, to: 29, title: '20–29 Судно на воздушной подушке (WIG)' },
|
||||
{ from: 30, to: 39, title: '30–39 Особое судно' },
|
||||
{ from: 40, to: 49, title: '40–49 Высокоскоростное судно (ВСС)' },
|
||||
{ from: 50, to: 59, title: '50–59 Особое судно' },
|
||||
{ from: 60, to: 69, title: '60–69 Пассажирское судно' },
|
||||
{ from: 70, to: 79, title: '70–79 Грузовое судно' },
|
||||
{ from: 80, to: 89, title: '80–89 Танкер' },
|
||||
{ from: 90, to: 99, title: '90–99 Прочие типы' },
|
||||
];
|
||||
|
||||
function addOption(sel, value, text) {
|
||||
var o = document.createElement('option');
|
||||
o.value = String(value);
|
||||
o.textContent = String(value) + ' — ' + text;
|
||||
sel.appendChild(o);
|
||||
}
|
||||
|
||||
function fillShipTypeSelect() {
|
||||
var sel = document.getElementById('tp-ship-type');
|
||||
if (!sel || sel.getAttribute('data-table51') === '1') return;
|
||||
sel.setAttribute('data-table51', '1');
|
||||
sel.innerHTML = '';
|
||||
addOption(sel, 0, LABELS[0]);
|
||||
GROUPS.forEach(function (g) {
|
||||
var og = document.createElement('optgroup');
|
||||
og.label = g.title;
|
||||
for (var c = g.from; c <= g.to; c++) {
|
||||
var o = document.createElement('option');
|
||||
o.value = String(c);
|
||||
var pad = c < 10 ? '0' + c : String(c);
|
||||
o.textContent = pad + ' — ' + LABELS[c];
|
||||
og.appendChild(o);
|
||||
}
|
||||
sel.appendChild(og);
|
||||
});
|
||||
}
|
||||
|
||||
function ensureShipTypeOption(value) {
|
||||
var sel = document.getElementById('tp-ship-type');
|
||||
if (!sel) return;
|
||||
var v = Math.max(0, Math.min(255, parseInt(value, 10) || 0));
|
||||
var s = String(v);
|
||||
for (var i = 0; i < sel.options.length; i++) {
|
||||
if (sel.options[i].value === s) return;
|
||||
}
|
||||
var o = document.createElement('option');
|
||||
o.value = s;
|
||||
o.textContent = s + ' — (из конфигурации, вне табл. 51 / 0–99)';
|
||||
sel.appendChild(o);
|
||||
}
|
||||
|
||||
window.fillShipTypeSelect = fillShipTypeSelect;
|
||||
window.ensureShipTypeOption = ensureShipTypeOption;
|
||||
window.AIS_TABLE51_SHIP_TYPE_LABEL = function (code) {
|
||||
var c = parseInt(code, 10);
|
||||
if (isNaN(c) || c < 0 || c > 99) return null;
|
||||
return LABELS[c] || null;
|
||||
};
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', fillShipTypeSelect);
|
||||
} else {
|
||||
fillShipTypeSelect();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user