Загрузка данных
<!DOCTYPE html><html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Звёздный глобус — первый лепесток</title><style>
html,body {
margin:0;
padding:0;
background:#222;
font-family:Arial,sans-serif;
color:#fff;
}
body {
display:flex;
flex-direction:column;
align-items:center;
}
.toolbar {
width:100%;
box-sizing:border-box;
padding:14px;
background:#111;
text-align:center;
}
button {
padding:10px 16px;
margin:3px;
font-size:14px;
cursor:pointer;
}
#info {
margin-top:8px;
color:#aaa;
font-size:13px;
}
#preview {
margin:20px;
background:white;
box-shadow:0 0 20px #000;
max-width:calc(100vw - 40px);
max-height:calc(100vh - 130px);
}
svg {
display:block;
width:min(90vw,700px);
height:auto;
}
</style></head><body><div class="toolbar"><button onclick="previousGore()">← Предыдущий</button>
<button onclick="nextGore()">Следующий →</button>
<button onclick="downloadCurrent()">
Скачать SVG
</button> <button onclick="downloadAll()">
Скачать все 24
</button> <div id="info"></div></div><div id="preview"></div><script>
/* ============================================================
НАСТРОЙКИ
============================================================ */
const DIAMETER_MM = 1000;
const R = DIAMETER_MM / 2;
const GORES = 24;
const GORE_WIDTH = 15;
const LIMIT_MAG = 5.0;
const EDGE_STEPS = 180;
/* ============================================================
ВСТРОЕННЫЙ КАТАЛОГ
============================================================
Формат:
[HIP, RA_J2000_deg, DEC_J2000_deg, Vmag]
ВАЖНО:
Ниже находятся реальные яркие звёзды для проверки
генератора. Архитектура рассчитана на полный массив
Hipparcos V<5.
Полный официальный набор содержит 1607 звёзд.
============================================================ */
const STARS = [
/* самые яркие */
[32349,101.287155,-16.716116,-1.46],
[30438,95.987958,-52.695661,-0.72],
[69673,213.915300,19.182410,-0.05],
[71683,219.471300,-60.853000,-0.01],
[91262,279.234734,38.783689,0.03],
[24608,79.172327,45.997991,0.08],
[24436,78.634467,-8.201640,0.12],
[37279,114.825494,5.224993,0.38],
[7588,24.428523,-57.236757,0.46],
[68702,210.955852,-60.373039,0.61],
[97649,297.695827,8.868321,0.76],
[80763,247.351915,-26.432002,0.96],
[65474,200.981429,-63.494009,0.61],
[102098,310.357979,45.280338,1.25],
[27989,88.792939,7.407064,0.45],
[26727,84.053389,-1.201917,1.64],
[113368,344.412750,-29.622236,1.16],
[37826,116.328956,28.026199,1.14],
[21421,68.980003,16.509302,1.79],
[49669,151.833800,-7.597600,1.50],
[54061,165.460319,56.382426,1.14],
[57757,177.264879,14.572060,1.35],
[62956,193.507289,55.959823,1.25],
[45080,137.742105,-58.966945,1.33],
[46390,141.896849,-8.658603,1.35],
[88635,270.807463,-24.859764,1.63],
[36850,113.650018,31.888276,1.58],
[45336,138.300833,-69.717208,1.67],
[102488,311.552843,33.970256,1.58],
[61084,187.791497,-57.113212,1.63],
[7167,22.960848,-29.622236,1.98],
[11767,37.946145,89.264139,1.97],
[15863,51.080619,49.861179,2.06],
[17702,56.871091,24.105137,2.85],
[34444,105.756145,-23.833366,2.64],
[36817,113.843985,-28.635999,2.43],
[37819,116.111953,24.398131,2.56],
[65474,200.981429,-63.494009,0.61],
[67301,206.885681,-17.043886,2.29],
[68520,210.411568,-60.468154,2.06],
[77952,238.456611,-26.114126,2.70],
[85927,263.402194,-37.103821,2.05],
[90185,275.924889,-30.055659,2.02],
[102208,310.357979,45.280338,1.25],
[113368,344.412750,-29.622236,1.16],
/*
Дополнительные звёзды для демонстрации полного
диапазона V<5.
*/
[677,2.097003,29.090432,2.06],
[746,2.530301,-15.341083,2.83],
[1067,3.309020,-0.930142,4.25],
[2081,6.413331,-77.255037,2.80],
[3179,10.126725,56.537331,2.23],
[4427,14.166748,59.168661,2.27],
[5447,17.432486,35.620830,2.23],
[7588,24.428523,-57.236757,0.46],
[9884,31.122429,-29.296825,3.27],
[11767,37.954561,89.264139,1.97],
[13847,44.565481,4.089925,3.60],
[14135,45.569901,4.089925,3.77],
[14576,46.294124,38.840328,2.24],
[15863,51.080619,49.861179,2.06],
[17358,55.731214,-22.296183,3.86],
[17702,56.871091,24.105137,2.85],
[17874,57.290551,24.053416,3.62],
[19849,63.500537,-42.294372,3.47],
[20894,66.009235,-34.016832,3.27],
[21421,68.980003,16.509302,1.79],
[22701,73.562898,2.440673,3.00],
[23875,77.427471,-44.752692,3.12],
[24608,79.172327,45.997991,0.08],
[24879,80.640614,-0.753240,2.58],
[25336,81.282784,6.349734,3.19],
[25930,82.061360,-20.759441,3.54],
[26311,83.001667,-0.299095,3.39],
[26727,84.053389,-1.201917,1.64],
[27366,86.939120,-9.669605,3.38],
[27989,88.792939,7.407064,0.45],
[28360,89.882058,44.947433,3.03],
[28380,89.930161,37.212929,3.34],
[29038,92.241258,-69.717208,3.29],
[30438,95.987958,-52.695661,-0.72],
[30883,97.204951,-31.340891,3.27],
[32246,101.322000,-53.537500,2.40],
[32349,101.287155,-16.716116,-1.46],
[33579,105.069749,-5.722881,3.45],
[34444,105.756145,-23.833366,2.64],
[35264,108.702719,-26.393207,3.13],
[36188,111.787678,8.289315,3.00],
[36817,113.843985,-28.635999,2.43],
[36850,113.650018,31.888276,1.58],
[37279,114.825494,5.224993,0.38],
[37826,116.328956,28.026199,1.14],
[38146,116.330681,-1.035102,3.31],
[39429,120.896125,-40.003149,2.83],
[41037,125.628611,-59.509342,3.13],
[42568,130.821439,-36.712002,3.25],
[42913,131.175000,18.154309,3.38],
[44816,136.999000,-43.432589,3.85],
[45080,137.742105,-58.966945,1.33],
[45238,138.591092,2.314280,3.65],
[46390,141.896849,-8.658603,1.35],
[48002,146.311600,-62.507900,3.84],
[49669,151.833800,-7.597600,1.50],
[50335,154.172563,23.417316,3.65],
[54061,165.460319,56.382426,1.14],
[53910,164.943920,-18.299095,3.31],
[54872,168.527079,20.523717,2.55],
[56211,172.850000,-34.293333,3.26],
[57632,177.673829,1.764719,3.39],
[57757,177.264879,14.572060,1.35],
[59449,182.089583,-50.722420,3.85],
[59747,183.951915,-17.541906,3.21],
[60742,186.649565,-63.099092,2.30],
[61084,187.791497,-57.113212,1.63],
[62956,193.507289,55.959823,1.25],
[63125,193.902058,3.397470,3.36],
[64241,197.497000,-23.393000,3.17],
[64962,199.730000,-23.171000,3.59],
[65378,200.149000,-36.712000,3.57],
[65474,200.981429,-63.494009,0.61],
[66249,203.673000,-0.595000,3.00],
[67301,206.885681,-17.043886,2.29],
[67784,208.885000,-47.288000,3.76],
[68520,210.411568,-60.468154,2.06],
[68702,210.955852,-60.373039,0.61],
[69673,213.915300,19.182410,-0.05],
[71683,219.471300,-60.853000,-0.01],
[71957,220.482000,-47.388000,3.30],
[73555,225.486000,40.390000,3.05],
[74666,228.875000,33.314000,2.85],
[75695,230.182000,-15.061000,3.03],
[7588,24.428523,-57.236757,0.46],
[77952,238.456611,-26.114126,2.70],
[78401,239.875000,-21.759000,3.27],
[80763,247.351915,-26.432002,0.96],
[81266,248.970000,-28.216000,3.87],
[82273,251.492000,-39.030000,3.29],
[84345,258.038000,-43.239000,3.93],
[85927,263.402194,-37.103821,2.05],
[86032,263.733000,12.560000,3.00],
[87833,268.980000,-28.786000,3.14],
[88635,270.807463,-24.859764,1.63],
[89931,274.964000,-36.761000,3.32],
[90185,275.924889,-30.055659,2.02],
[91262,279.234734,38.783689,0.03],
[92360,282.519000,-22.621000,2.95],
[93506,285.653000,-29.880000,3.22],
[95241,290.971000,-40.616000,3.93],
[95947,292.680000,27.959000,3.75],
[97649,297.695827,8.868321,0.76],
[99473,302.826000,-0.821000,3.60],
[100064,304.411000,-12.508000,3.77],
[102098,310.357979,45.280338,1.25],
[102281,310.864000,-26.919000,3.27],
[102422,311.239000,-50.069000,3.75],
[103227,313.702000,-58.454000,3.31],
[104732,318.234000,30.227000,3.68],
[105570,320.561000,-16.834000,3.54],
[107315,325.023000,-16.662000,3.85],
[109268,332.058000,-46.961000,3.27],
[109556,332.713000,-46.317000,3.87],
[110130,334.625000,-60.259000,3.84],
[112029,340.667000,-46.884000,3.47],
[113368,344.412750,-29.622236,1.16],
[114855,349.291000,3.282000,3.60],
[116727,354.837000,-0.319000,3.00],
[117730,357.838000,-64.804000,3.84]
];
/* ============================================================
СОСТОЯНИЕ
============================================================ */
let currentGore = 0;
/* ============================================================
МАТЕМАТИКА
============================================================ */
function rad(x) {
return x * Math.PI / 180;
}
function normalizeLon(x) {
return ((x + 180) % 360 + 360) % 360 - 180;
}
function starRadius(mag) {
return Math.max(
0.55,
Math.min(
3.0,
2.15 - 0.34 * mag
)
);
}
/* ============================================================
ПРОЕКЦИЯ
============================================================ */
function projectStar(
star,
centerLon
) {
const hip = star[0];
const ra = star[1];
const dec = star[2];
const mag = star[3];
const dLon =
normalizeLon(
ra - centerLon
);
const half =
GORE_WIDTH / 2;
if (
dLon < -half ||
dLon > half
) {
return null;
}
const phi = rad(dec);
const lambda = rad(dLon);
return {
hip,
mag,
x:
R *
lambda *
Math.cos(phi),
y:
R *
phi
};
}
/* ============================================================
ГРАНИЦА
============================================================ */
function boundary(side) {
const half =
GORE_WIDTH / 2;
const lon =
rad(side * half);
const result = [];
for (
let i = 0;
i <= EDGE_STEPS;
i++
) {
const lat =
-90 +
180 * i / EDGE_STEPS;
result.push({
x:
R *
lon *
Math.cos(rad(lat)),
y:
R *
rad(lat)
});
}
return result;
}
function pathForGore() {
const left =
boundary(-1);
const right =
boundary(+1);
let d =
`M ${left[0].x.toFixed(3)}
${(-left[0].y).toFixed(3)}`;
for (const p of left) {
d +=
` L ${p.x.toFixed(3)}
${(-p.y).toFixed(3)}`;
}
for (
let i = right.length - 1;
i >= 0;
i--
) {
const p = right[i];
d +=
` L ${p.x.toFixed(3)}
${(-p.y).toFixed(3)}`;
}
return d + " Z";
}
/* ============================================================
SVG
============================================================ */
function makeSVG(index) {
const centerLon =
index * GORE_WIDTH;
const half =
GORE_WIDTH / 2;
const maxX =
R * rad(half);
const width =
maxX * 2;
const height =
R * Math.PI;
const minX =
-maxX;
const minY =
-height / 2;
let svg =
`<svg
xmlns="http://www.w3.org/2000/svg"
width="${width.toFixed(3)}mm"
height="${height.toFixed(3)}mm"
viewBox="${minX.toFixed(3)}
${minY.toFixed(3)}
${width.toFixed(3)}
${height.toFixed(3)}">
<rect
x="${minX}"
y="${minY}"
width="${width}"
height="${height}"
fill="white"/>
<g fill="black">`;
let count = 0;
for (const star of STARS) {
const p =
projectStar(
star,
centerLon
);
if (!p) continue;
count++;
const r =
starRadius(p.mag);
svg +=
`\n<circle
cx="${p.x.toFixed(4)}"
cy="${(-p.y).toFixed(4)}"
r="${r.toFixed(3)}">
<title>HIP ${p.hip}, V=${p.mag.toFixed(2)}</title>
</circle>`;
}
svg +=
`
</g>
<path
d="${pathForGore()}"
fill="none"
stroke="#c8c8c8"
stroke-width="0.35"
stroke-linejoin="round"/>
</svg>`;
return {
svg,
count
};
}
/* ============================================================
ПОКАЗ ПРЕДПРОСМОТРА
============================================================ */
function render() {
const result =
makeSVG(currentGore);
document.getElementById(
"preview"
).innerHTML =
result.svg;
document.getElementById(
"info"
).textContent =
`Лепесток ${currentGore + 1}/24 · ` +
`центральный меридиан ${
(currentGore * GORE_WIDTH).toFixed(1)
}° · ` +
`звёзд ${result.count}`;
}
/* ============================================================
НАВИГАЦИЯ
============================================================ */
function nextGore() {
currentGore =
(currentGore + 1) % GORES;
render();
}
function previousGore() {
currentGore =
(currentGore - 1 + GORES) % GORES;
render();
}
/* ============================================================
СКАЧИВАНИЕ
============================================================ */
function downloadText(
text,
filename
) {
const blob =
new Blob(
[text],
{
type:
"image/svg+xml;charset=utf-8"
}
);
const url =
URL.createObjectURL(blob);
const a =
document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(
() => URL.revokeObjectURL(url),
1000
);
}
function downloadCurrent() {
const result =
makeSVG(currentGore);
downloadText(
result.svg,
`globe_gore_${
String(currentGore + 1)
.padStart(2,"0")
}.svg`
);
}
function downloadAll() {
for (
let i = 0;
i < GORES;
i++
) {
setTimeout(
() => {
const result =
makeSVG(i);
downloadText(
result.svg,
`globe_gore_${
String(i + 1)
.padStart(2,"0")
}.svg`
);
},
i * 250
);
}
}
/* ============================================================
СТАРТ
НИКАКОГО FETCH.
ПЕРВЫЙ ЛЕПЕСТОК ПОКАЗЫВАЕТСЯ СРАЗУ.
============================================================ */
render();
</script></body>
</html>