๐Ÿ“Œ Leaflet์™€ GeoJSON์œผ๋กœ ํ–‰์ •๊ตฌ์—ญ ์ง€๋„ ๋งŒ๋“ค๊ธฐ

My Pale Blue Dotยท2025๋…„ 5์›” 12์ผ
0

SPRING BOOT

๋ชฉ๋ก ๋ณด๊ธฐ
16/40
post-thumbnail

๐Ÿ“… 2025-05-12

๐Ÿ“ ๋ชฉํ‘œ

  • Leaflet ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์›น ๋ธŒ๋ผ์šฐ์ €์— ์ง€๋„๋ฅผ ๋„์šฐ๊ณ 
  • GeoJSON ํŒŒ์ผ์„ ์‹œ๊ฐํ™”ํ•˜์—ฌ ๋Œ€๊ตฌ๊ด‘์—ญ์‹œ ํ–‰์ •๊ตฌ์—ญ(๊ตฌ/๋™)์„ ๊ตฌ๋ถ„
  • ์‚ฌ์šฉ์ž ํด๋ฆญ ์ด๋ฒคํŠธ๋กœ ๋งˆ์ปค ์ƒ์„ฑ, ๋‚ ์”จ API ์—ฐ๋™
  • Mapshaper.org๋ฅผ ์‚ฌ์šฉํ•ด ํ–‰์ •๊ตฌ์—ญ ๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ(dissolve)๊นŒ์ง€ ์ˆ˜ํ–‰

โœ… Step 1. ์‚ฌ์ „ ์ค€๋น„

1. HTML + JS ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ

  • ๊ธฐ๋ณธ ์›น ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋งŒ๋“ค๊ธฐ

๐Ÿ“ project/
โ””โ”€ index.html
โ””โ”€ /js/
โ””โ”€ KoreanTmsProviders.js (Daum ์ขŒํ‘œ๊ณ„์šฉ)
โ””โ”€ /geoJson/
โ””โ”€ daegu.json (ํ–‰์ •๊ตฌ์—ญ GeoJSON ํŒŒ์ผ)

2. ํ•„์š”ํ•œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • HTML <head>์— ์•„๋ž˜ CDN ์ถ”๊ฐ€:
<!-- Leaflet -->
<link rel="stylesheet" href="<https://unpkg.com/leaflet@1.9.4/dist/leaflet.css>" />
<script src="<https://unpkg.com/leaflet@1.9.4/dist/leaflet.js>"></script>

<!-- axios -->
<script src="<https://cdnjs.cloudflare.com/ajax/libs/axios/1.9.0/axios.min.js>"></script>

<!-- Daum ์ง€๋„ ์ขŒํ‘œ๊ณ„์šฉ ํ”Œ๋Ÿฌ๊ทธ์ธ -->
<script src="/js/KoreanTmsProviders/lib/proj4.js"></script>
<script src="/js/KoreanTmsProviders/lib/proj4leaflet.js"></script>
<script src="/js/KoreanTmsProviders/src/Leaflet.KoreanTmsProviders.js"></script>

โœ… Step 2. ์ง€๋„ ๋„์šฐ๊ธฐ (Daum ์ง€๋„)

<div id="map" style="height: 100vh;"></div>
const map = new L.Map('map', {
  center: new L.LatLng(35.829890, 128.532719), // ๋Œ€๊ตฌ ์ค‘์‹ฌ ์ขŒํ‘œ
  zoom: 8,
  crs: L.Proj.CRS.Daum // Daum ์ขŒํ‘œ๊ณ„
});
L.tileLayer.koreaProvider('DaumMap.Street').addTo(map);

โœ… Step 3. ํด๋ฆญ ์‹œ ๋งˆ์ปค + ๋‚ ์”จ API ์—ฐ๋™

map.on('click', function(e){
  const lat = e.latlng.lat;
  const lng = e.latlng.lng;

  const marker = L.marker([lat, lng]).addTo(map);

  axios.get(`/open/weather/get/${lat}/${lng}`)
    .then(resp => {
      const content = `
        <div>
          <strong>๊ธฐ์ƒ ์ •๋ณด</strong><br/>
          base: ${resp.data.base}<br/>
          cloud: ${resp.data.clouds.all}
        </div>`;
      marker.bindPopup(content);
    });
});

โœ… Step 4. GeoJSON ํ–‰์ •๊ตฌ์—ญ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ

const borderColors = {
  "์ค‘๊ตฌ": "red", "๋™๊ตฌ": "orange", "์„œ๊ตฌ": "yellow",
  "๋‚จ๊ตฌ": "green", "๋ถ๊ตฌ": "blue", "์ˆ˜์„ฑ๊ตฌ": "navy",
  "๋‹ฌ์„œ๊ตฌ": "black", "๋‹ฌ์„ฑ๊ตฐ": "royalblue"
};

axios.get("/geoJson/daegu.json")
  .then(resp => {
    const grouped = {};
    resp.data.features.forEach(f => {
      const key = f.properties.sggnm;
      if (!grouped[key]) grouped[key] = [];
      grouped[key].push(f);
    });

    Object.entries(grouped).forEach(([sggnm, features]) => {
      L.geoJSON(features, {
        style: {
          color: borderColors[sggnm],
          fillColor: borderColors[sggnm],
          fillOpacity: 0.6,
          weight: 2
        },
        onEachFeature: (feature, layer) => {
          const name = feature.properties.adm_nm;
          layer.bindTooltip(name);
          layer.on('click', () => {
            map.fitBounds(layer.getBounds());
            alert(`์„ ํƒํ•œ ํ–‰์ •๋™: ${name}`);
          });
        }
      }).addTo(map);
    });
  });

โœ… Step 5. Mapshaper.org๋กœ GeoJSON ๋ณ‘ํ•ฉ

๐Ÿ”น ๋ชฉ์ 

  • sggnm(์‹œ๊ตฐ๊ตฌ๋ช…) ๊ธฐ์ค€์œผ๋กœ ์—ฌ๋Ÿฌ Polygon โ†’ ํ•˜๋‚˜์˜ MultiPolygon์œผ๋กœ ๋ณ‘ํ•ฉ
  • ๋ Œ๋”๋ง ์„ฑ๋Šฅ ํ–ฅ์ƒ + ์‹œ๊ฐ์  ๋‹จ์ˆœํ™”

๐Ÿ”น ์ ˆ์ฐจ

  1. https://mapshaper.org ์ ‘์†

  2. GeoJSON ํŒŒ์ผ ๋“œ๋ž˜๊ทธ๋กœ ์—…๋กœ๋“œ

  3. ์ƒ๋‹จ ๋ฉ”๋‰ด โ†’ Console ํด๋ฆญ

  4. ๋ช…๋ น์–ด ์ž…๋ ฅ:

    dissolve sggnm
    
  5. ๊ฒฐ๊ณผ ํ™•์ธ ํ›„ ์šฐ์ธก ์ƒ๋‹จ Export โ†’ GeoJSON ์ €์žฅ

๐Ÿ’ก ์˜ต์…˜: ๊ธฐ์กด ์†์„ฑ ์œ ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด

dissolve sggnm keep-fields=adm_cd,adm_nm

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


๐Ÿ”ฅ ๋งˆ๋ฌด๋ฆฌ ์š”์•ฝ

ํ•ญ๋ชฉ๋‚ด์šฉ
๐Ÿ“ ์ง€๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌLeaflet + Daum CRS
๐Ÿ“ ๋ฐ์ดํ„ฐ ํ˜•์‹GeoJSON (MultiPolygon, properties.sggnm, adm_nm)
๐Ÿ“ ์ฃผ์š” ๊ธฐ๋Šฅ์ง€๋„ + ๋งˆ์ปค + ํŒ์—… + ํ–‰์ •๊ตฌ์—ญ ์ƒ‰์ƒ ์‹œ๊ฐํ™”
๐Ÿ“ ์‘์šฉํ–‰์ •๋™ ํ•„ํ„ฐ, ํ†ต๊ณ„ ์‹œ๊ฐํ™”, ๋“œ๋ฆด๋‹ค์šด ๊ฐ€๋Šฅ
๐Ÿ“ ๊ฐ€๊ณต ํˆดMapshaper๋กœ dissolve๋กœ ๋ณ‘ํ•ฉ ๋ฐ ์ •๋ฆฌ

profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€