Простое преобразование geojson в SVGHtml

Программисты Html
Ответить
Anonymous
 Простое преобразование geojson в SVG

Сообщение Anonymous »

Мне нужно простое веб-приложение, которое преобразует geojson в SVG. И у меня есть хороший отклик от использования ChatGPT. Включены коды, которые должны работать на этой странице.
Поскольку код создан искусственным интеллектом, и есть некоторые опасения по поводу его цитирования:
  • Подтвердить использование искусственного интеллекта: Да, я хотел бы подтвердить, что весь код был создан с использованием OpenAI ChatGPT (версия от 14 марта 2023 г.)
  • Принять ответственность: я отказываюсь претендовать на точность, функциональность и этические последствия кода.
Моя цель этого поста:
  • Опубликовать несколько вопросов по использованию приложения
  • Ответить на мои собственные вопросы
Мой вопрос:
  • Как получить ответ, то есть сгенерированный SVG-код текущего кода geoJSON в поле. Приложение должно позволять пользователю загружать код SVG, но здесь оно не работает. Почему?
  • (Это будет добавлено позже)

Код: Выделить всё

/*
Steps:
1. parse GeoJSON
2. convert lon/lat -> Web Mercator (x, y) in meters
3. compute bbox of projected coords
4. compute uniform scale and translate to fit viewport with padding
5.  build SVG path string and insert into container
*/

function lonLatToWebMercator(lon, lat) {
// returns {x, y} in meters (EPSG:3857)
const R = 6378137;
const x = R * lon * Math.PI / 180;
const latRad = lat * Math.PI / 180;
const y = R * Math.log(Math.tan(Math.PI / 4 + latRad / 2));
return { x, y };
}

function projectPolygon(coords) {
// coords: array of linear rings; we use the outer ring (coords[0])
const ring = coords[0];
return ring.map(([lon, lat]) => lonLatToWebMercator(lon, lat));
}

function buildPathString(points) {
if (!points.length) return '';
return points.map((p, i) => (i === 0 ? 'M' : 'L') + p.x.toFixed(2) + ' ' + p.y.toFixed(2)).join(' ') + ' Z';
}

function fitToViewport(points, width, height, padding = 20) {
// points: array of {x,y} in projected units
const xs = points.map(p => p.x), ys = points.map(p => p.y);
const minx = Math.min(...xs), maxx = Math.max(...xs);
const miny = Math.min(...ys), maxy = Math.max(...ys);
const dx = maxx - minx || 1;
const dy = maxy - miny || 1;

// scale to fit with preserved aspect
const availW = width - 2 * padding, availH = height - 2 * padding;
const scale = Math.min(availW / dx, availH / dy);

// translate so minx, maxy maps to padding, padding (we will flip y)
// SVG y increases downward, but Mercator y increases upward.
// We map mercator y so that larger y is smaller SVG y: svgY = (maxy - y)*scale + padding
const tx = -minx * scale + padding;
const ty = -maxy * scale + padding; // used with flip in mapping

const mapped = points.map(p => {
return {
x: p.x * scale + tx,
y: (p.y * -1) * scale - ty + height // easier: compute y as (maxy - p.y)*scale + padding
};
});

// For clearer calculation do proper mapping below:
const mapped2 = points.map(p => {
const sx = (p.x - minx) * scale + padding;
const sy = (maxy - p.y) * scale + padding; // flip Y
return { x: sx, y: sy };
});

return {
mapped: mapped2,
minx, maxx, miny, maxy,
scale,
padding
};
}

function renderGeoJSONToSVG(geojson, width=640, height=420) {
if (!geojson || !geojson.geometry) throw new Error('Invalid GeoJSON');

const geom = geojson.geometry;
if (geom.type !== 'Polygon') throw new Error('Only Polygon geometry is supported in this demo');

const proj = projectPolygon(geom.coordinates);
const fit = fitToViewport(proj, width, height, 20);
const mapped = fit.mapped;

// build path string from mapped coords
const d = mapped.map((p,i) => (i===0 ? 'M' : 'L') + p.x.toFixed(2) + ' ' + p.y.toFixed(2)).join(' ') + ' Z';

// create svg element
const ns = 'http://www.w3.org/2000/svg';
const svg = document.createElementNS(ns, 'svg');
svg.setAttribute('width', width);
svg.setAttribute('height', height);
svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svg.style.background = '#071016';

// defs (optional styles)
const defs = document.createElementNS(ns, 'defs');
svg.appendChild(defs);

// polygon path
const path = document.createElementNS(ns, 'path');
path.setAttribute('d', d);
path.setAttribute('fill', 'rgba(0,180,120,0.15)');
path.setAttribute('stroke', '#00b488');
path.setAttribute('stroke-width', '2');
path.setAttribute('stroke-linejoin', 'round');
svg.appendChild(path);

// draw points
mapped.forEach(p =>  {
const c = document.createElementNS(ns, 'circle');
c.setAttribute('cx', p.x.toFixed(2));
c.setAttribute('cy', p.y.toFixed(2));
c.setAttribute('r', '3');
c.setAttribute('fill', '#fff');
c.setAttribute('stroke', '#007f5f');
svg.appendChild(c);
});

// bbox info text
const info = document.createElementNS(ns, 'text');
info.setAttribute('x', 10);
info.setAttribute('y', height - 8);
info.setAttribute('fill', '#9ca3af');
info.setAttribute('font-size', '11');
info.textContent = `scale: ${fit.scale.toFixed(6)}  bbox: [${fit.minx.toFixed(2)},${fit.miny.toFixed(2)}] - [${fit.maxx.toFixed(2)},${fit.maxy.toFixed(2)}]`;
svg.appendChild(info);

return svg;
}

// UI wiring
const textarea = document.getElementById('gj');
const container = document.getElementById('svgContainer');
const meta = document.getElementById('meta');

function doRender() {
container.innerHTML = '';
meta.textContent = '';
let g;
try {
g = JSON.parse(textarea.value.trim());
} catch (e) {
meta.textContent = 'Invalid JSON: ' + e.message;
return;
}
try {
const svg = renderGeoJSONToSVG(g, container.clientWidth, container.clientHeight);
container.appendChild(svg);
meta.textContent = 'Rendered polygon (projected via Web Mercator).';
} catch (e) {
meta.textContent = 'Error: ' + e.message;
}
}

document.getElementById('render').addEventListener('click', doRender);

// Download SVG
document.getElementById('download').addEventListener('click', () => {
const svgEl = container.querySelector('svg');
if (!svgEl) { alert('No SVG to download'); return; }
const serializer = new XMLSerializer();
const svgStr = serializer.serializeToString(svgEl);
const blob = new Blob([svgStr], {type: 'image/svg+xml'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'polygon.svg';
a.click();
URL.revokeObjectURL(url);
});

// initial render
doRender();

Код: Выделить всё

body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial; padding: 12px; background:#111; color:#ddd; }
.container { display:flex; gap:12px; align-items:flex-start; }
textarea { width:420px; height:160px; background:#0f1720; color:#d1d5db; border:1px solid #263238; padding:8px; font-family:monospace; }
.controls { display:flex; flex-direction:column; gap:8px; }
.btn { padding:8px 12px; background:#0ea5a4; color:#042; border:0; cursor:pointer; border-radius:6px; }
.preview { border:1px solid #333; background:#0b1220; padding:8px; }
.info { font-size:12px; color:#9ca3af; }

Код: Выделить всё


GeoJSON → SVG (Polygon)



GeoJSON → SVG (Polygon)

This example projects lon/lat → Web Mercator and scales the polygon to fit an SVG viewport.



GeoJSON (polygon):


{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[100.53232,13.73673],[100.53262,13.73668],[100.53251,13.73649],[100.53229,13.73657]]]},"properties":{}}


Render SVG
Download SVG











Подробнее здесь: https://stackoverflow.com/questions/798 ... conversion
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Html»