Загрузка данных
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Лепесток звёздного глобуса — 1000 мм</title>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
min-height: 100%;
background: #e5e5e5;
}
body {
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
box-sizing: border-box;
}
#download {
position: fixed;
top: 10px;
left: 10px;
z-index: 100;
padding: 10px 16px;
font-size: 16px;
cursor: pointer;
}
svg {
display: block;
/* Вертикальный лепесток */
width: min(90vw, 1000px);
height: auto;
/* Белый сам лепесток */
background: transparent;
}
.grid {
fill: none;
stroke: #f0f0f0;
stroke-width: 0.3;
vector-effect: non-scaling-stroke;
}
.edge {
fill: none;
stroke: #808080;
stroke-width: 0.5;
vector-effect: non-scaling-stroke;
}
</style>
</head>
<body>
<button id="download">Скачать SVG</button>
<svg
id="petal"
xmlns="http://www.w3.org/2000/svg"
width="1000mm"
height="1000mm"
viewBox="-550 -550 1100 1100">
<!--
Белая форма самого лепестка.
Она повторяет границы между -7.5° и +7.5°.
-->
<path
id="petalShape"
fill="white"
stroke="none">
</path>
<g id="grid"></g>
<g id="edges"></g>
</svg>
<script>
const svg = document.getElementById("petal");
const grid = document.getElementById("grid");
const edges = document.getElementById("edges");
const petalShape = document.getElementById("petalShape");
const NS = "http://www.w3.org/2000/svg";
const R = 500;
// Один лепесток = 1 час = 15°
const HALF_LON = 7.5;
// --------------------------------------------------
// Координаты
// --------------------------------------------------
function Y(latDeg) {
return -R * latDeg * Math.PI / 180;
}
function X(latDeg, lonDeg) {
const lat = latDeg * Math.PI / 180;
const lon = lonDeg * Math.PI / 180;
return R * Math.sin(lon) * Math.cos(lat);
}
// --------------------------------------------------
// Создание path
// --------------------------------------------------
function makePath(d, cls, parent) {
const p = document.createElementNS(NS, "path");
p.setAttribute("d", d);
p.setAttribute("class", cls);
parent.appendChild(p);
return p;
}
// --------------------------------------------------
// БЕЛЫЙ ЛЕПЕСТОК
// --------------------------------------------------
let petalPath = "";
// Левая граница: Северный → Южный полюс
for (let lat = 90; lat >= -90; lat -= 0.5) {
const x = X(lat, -HALF_LON);
const y = Y(lat);
if (lat === 90) {
petalPath += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
} else {
petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
}
// Нижняя точка
{
const x = X(-90, HALF_LON);
const y = Y(-90);
petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
// Правая граница: Южный → Северный полюс
for (let lat = -89.5; lat <= 90; lat += 0.5) {
const x = X(lat, HALF_LON);
const y = Y(lat);
petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
// Замыкаем
petalPath += "Z";
petalShape.setAttribute("d", petalPath);
// --------------------------------------------------
// ПАРАЛЛЕЛИ КАЖДЫЕ 5°
// --------------------------------------------------
for (let lat = -85; lat <= 85; lat += 5) {
const y = Y(lat);
const x1 = X(lat, -HALF_LON);
const x2 = X(lat, HALF_LON);
makePath(
`M ${x1.toFixed(4)} ${y.toFixed(4)}
L ${x2.toFixed(4)} ${y.toFixed(4)}`,
"grid",
grid
);
}
// --------------------------------------------------
// МЕРИДИАН 0°
// --------------------------------------------------
{
let d = "";
for (let lat = -90; lat <= 90; lat += 1) {
const x = X(lat, 0);
const y = Y(lat);
if (lat === -90) {
d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
} else {
d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
}
makePath(d, "grid", grid);
}
// --------------------------------------------------
// МЕРИДИАНЫ ±3.75°
// --------------------------------------------------
for (const lon of [-3.75, 3.75]) {
let d = "";
for (let lat = -90; lat <= 90; lat += 1) {
const x = X(lat, lon);
const y = Y(lat);
if (lat === -90) {
d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
} else {
d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
}
makePath(d, "grid", grid);
}
// --------------------------------------------------
// КРАЯ ЛЕПЕСТКА
// --------------------------------------------------
for (const lon of [-HALF_LON, HALF_LON]) {
let d = "";
for (let lat = -90; lat <= 90; lat += 0.5) {
const x = X(lat, lon);
const y = Y(lat);
if (lat === -90) {
d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
} else {
d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
}
makePath(d, "edge", edges);
}
// --------------------------------------------------
// ПОЛЮСЫ
// --------------------------------------------------
function poleEdge(lat) {
let d = "";
for (let i = 0; i <= 30; i++) {
const lon = -HALF_LON + i * (15 / 30);
const x = X(lat, lon);
const y = Y(lat);
if (i === 0) {
d += `M ${x.toFixed(4)} ${y.toFixed(4)} `;
} else {
d += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
}
makePath(d, "edge", edges);
}
poleEdge(90);
poleEdge(-90);
// --------------------------------------------------
// СКАЧИВАНИЕ SVG
// --------------------------------------------------
document.getElementById("download").addEventListener("click", () => {
const clone = svg.cloneNode(true);
const serializer = new XMLSerializer();
let source = serializer.serializeToString(clone);
source =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
source;
const blob = new Blob(
[source],
{ type: "image/svg+xml;charset=utf-8" }
);
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "lepetok_zvezdnogo_globusa_1chas_1000mm.svg";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(() => {
URL.revokeObjectURL(url);
}, 1000);
});
</script>
</body>
</html>