Загрузка данных
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Лепесток глобуса — 1000 мм</title>
<style>
html, body {
margin: 0;
padding: 0;
background: #e5e5e5;
}
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
box-sizing: border-box;
}
#download {
position: fixed;
top: 15px;
left: 15px;
z-index: 100;
padding: 10px 18px;
border: 1px solid #555;
border-radius: 5px;
background: white;
color: #222;
font-size: 16px;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0,0,0,.2);
}
#download:hover {
background: #f0f0f0;
}
svg {
display: block;
width: min(90vw, 1000px);
height: auto;
background: white;
}
/* Все внутренние линии */
.grid {
fill: none;
stroke: #f8f8f8;
stroke-width: 0.1;
vector-effect: non-scaling-stroke;
}
/* Края лепестка */
.edge {
fill: none;
stroke: #555;
stroke-width: 0.2;
vector-effect: non-scaling-stroke;
}
.petal-fill {
fill: white;
stroke: none;
}
</style>
</head>
<body>
<button id="download">Скачать SVG</button>
<svg
id="petal"
xmlns="http://www.w3.org/2000/svg"
width="1000mm"
height="1590.796mm"
viewBox="-80 -10 160 1590.796"
preserveAspectRatio="xMidYMin meet">
<path id="petalShape" class="petal-fill"></path>
<g id="grid"></g>
<g id="edges"></g>
</svg>
<script>
"use strict";
const NS = "http://www.w3.org/2000/svg";
const svg = document.getElementById("petal");
const petalShape = document.getElementById("petalShape");
const grid = document.getElementById("grid");
const edges = document.getElementById("edges");
const R = 500;
const HALF_LON = 7.5;
/* --------------------------------------------------
ПРОЕКЦИЯ ПО МЕРИДИАНУ
-------------------------------------------------- */
function Y(latDeg) {
const lat = latDeg * Math.PI / 180;
return R * (Math.PI / 2 - lat);
}
/* --------------------------------------------------
ШИРИНА ЛЕПЕСТКА
-------------------------------------------------- */
function X(latDeg, lonDeg) {
const lat = latDeg * Math.PI / 180;
const lon = lonDeg * Math.PI / 180;
return R * Math.sin(lon) * Math.cos(lat);
}
/* --------------------------------------------------
СОЗДАНИЕ SVG PATH
-------------------------------------------------- */
function createPath(d, className, parent) {
const path = document.createElementNS(NS, "path");
path.setAttribute("d", d);
path.setAttribute("class", className);
parent.appendChild(path);
return path;
}
/* ==================================================
1. ФОРМА ЛЕПЕСТКА
================================================== */
let petalPath = "";
/* Левая сторона: Север → Юг */
for (let lat = 90; lat >= -90; lat -= 0.25) {
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.75; lat <= 90; lat += 0.25) {
const x = X(lat, HALF_LON);
const y = Y(lat);
petalPath += `L ${x.toFixed(4)} ${y.toFixed(4)} `;
}
/* Замыкание */
petalPath += "Z";
petalShape.setAttribute("d", petalPath);
/* ==================================================
2. ПАРАЛЛЕЛИ КАЖДЫЕ 5°
================================================== */
for (let lat = 85; lat >= -85; lat -= 5) {
const y = Y(lat);
const xLeft = X(lat, -HALF_LON);
const xRight = X(lat, HALF_LON);
createPath(
`M ${xLeft.toFixed(4)} ${y.toFixed(4)}
L ${xRight.toFixed(4)} ${y.toFixed(4)}`,
"grid",
grid
);
}
/* ==================================================
3. МЕРИДИАНЫ ±3.75° И ЦЕНТРАЛЬНЫЙ 0°
================================================== */
for (const lon of [-3.75, 0, 3.75]) {
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)} `;
}
}
createPath(d, "grid", grid);
}
/* ==================================================
4. КРАЯ ЛЕПЕСТКА
================================================== */
for (const lon of [-HALF_LON, HALF_LON]) {
let d = "";
for (let lat = 90; lat >= -90; lat -= 0.25) {
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)} `;
}
}
createPath(d, "edge", edges);
}
/* ==================================================
5. ЛИНИИ ПОЛЮСОВ
================================================== */
function poleEdge(lat) {
let d = "";
for (let i = 0; i <= 40; i++) {
const lon =
-HALF_LON +
i * (15 / 40);
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)} `;
}
}
createPath(d, "edge", edges);
}
poleEdge(90);
poleEdge(-90);
/* ==================================================
6. СКАЧИВАНИЕ ГОТОВОГО SVG
================================================== */
document.getElementById("download").addEventListener("click", function () {
const clone = svg.cloneNode(true);
const style = document.createElementNS(NS, "style");
style.textContent = `
.grid {
fill: none;
stroke: #f8f8f8;
stroke-width: 0.1;
}
.edge {
fill: none;
stroke: #555;
stroke-width: 0.2;
}
.petal-fill {
fill: white;
stroke: none;
}
`;
clone.insertBefore(style, clone.firstChild);
const serializer = new XMLSerializer();
let source =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
serializer.serializeToString(clone);
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_globus_1000mm.svg";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(function () {
URL.revokeObjectURL(url);
}, 1000);
});
</script>
</body>
</html>