Anonymous
Простое преобразование geojson в SVG
Сообщение
Anonymous » 10 ноя 2025, 20:55
Мне нужно простое веб-приложение, которое преобразует 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
1762797313
Anonymous
Мне нужно простое веб-приложение, которое преобразует geojson в SVG. И у меня есть хороший отклик от использования ChatGPT. Включены коды, которые должны работать на этой странице. Поскольку код создан искусственным интеллектом, и есть некоторые опасения по поводу его цитирования: [list] [*]Подтвердить использование искусственного интеллекта: Да, я хотел бы подтвердить, что весь код был создан с использованием OpenAI ChatGPT (версия от 14 марта 2023 г.) [*]Принять ответственность: я отказываюсь претендовать на точность, функциональность и этические последствия кода. [/list] Моя цель этого поста: [list] [*]Опубликовать несколько вопросов по использованию приложения [*]Ответить на мои собственные вопросы [/list] Мой вопрос: [list] [*]Как получить ответ, то есть сгенерированный SVG-код текущего кода geoJSON в поле. Приложение должно позволять пользователю нажать кнопку, чтобы загрузить код SVG, но здесь оно не работает. Почему? [*](Это будет добавлено позже) [/list] [code]/* 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();[/code] [code] 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; } [/code] [code] 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 [/code] Подробнее здесь: [url]https://stackoverflow.com/questions/79815204/simple-geojson-to-svg-conversion[/url]