팡이네

준비물: 시도 shp, 시군구 shp, 읍면동 shp

프로그램: mapshaper, QGIS, python 3.9.1

 

국내 행정구역 shp 파일은 용량도 크고 너무 세밀하게 표현된 부분이 많아서

웹에 단순한 행정구역을 표시할 때 용량과 속도 등에서 제약사항이 발생한다.

 

국내 행정구역 shp 파일에서 사용된 좌표계는 GRS80 (EPSG: 5179) 이므로

네이버 지도에서 사용하는 위도와 경도 좌표계 WGS84 (EPSG: 4326)로 변환해야 한다.

 

변환 과정 요약

1. mapshaper 등의 프로그램으로 simplify 과정을 거쳐 단순화(shp ▶ shp)

2. QGIS 등의 프로그램을 이용하여 WGS 84 좌표로 변환(shp ▶ json(geojson))

3. python 등을 이용해 전체 geojson 파일에서 필요한 행정구역 파일로 분할 저장(json ▶ json(geojson))

 

[시군구 geojson 분할 저장] python 3.9.1

//--------------------------------------
// 시군구 geojson 분할 저장
//--------------------------------------
#python 3.9.1
import json

#json 파일 읽기
with open('d:\\sig_202005_wgs84.geojson', 'r', encoding='UTF8') as rf:
    geojson = json.load(rf)

#시군구 반복
for item in geojson['features']:
    code = item['properties']['SIG_CD']     #행정구역코드
    name = item['properties']['SIG_KOR_NM'] #행정구역명
    item['id'] = code;                      #네이버 지도용 id 설정

    #json 파일 저장 경로
    path = 'd:\\sig\\'+ code +'.json'
    print(path +' '+ name)

    #json 객체 생성
    geo = dict()
    geo['type'] = 'FeatureCollection'
    geo['features'] = []            #features는 배열
    geo['features'].append(item)

    #json 파일 저장
    with open(path, 'w', encoding='UTF8') as wf:
        json.dump(geo, wf, ensure_ascii=False)  #한글 유니코드 저장 방지

[행정구역 json 파일 로드]

//--------------------------------------
// 행정구역 json 파일 로드
//--------------------------------------
var HOME_PATH = window.HOME_PATH || '.',
    urlPrefix = HOME_PATH +'/data/region',
    urlSuffix = '.json',
    regionGeoJson = [],
    loadCount = 0;

// 행정구역 json 파일 로드
naver.maps.Event.once(map, 'init_stylemap', function () {
    for (var i = 1; i < 18; i++) {
        var keyword = i +'';

        if (keyword.length === 1) {
            keyword = '0'+ keyword;
        }

        $.ajax({
            url: urlPrefix + keyword + urlSuffix,
            success: function(idx) {
                return function(geojson) {
                    regionGeoJson[idx] = geojson;

                    loadCount++;

                    if (loadCount === 17) {
                        startDataLayer();
                    }
                }
            }(i - 1)
        });
    }
});

[Geojson 파일 형태]

//--------------------------------------
// Geojson 파일 형태
//--------------------------------------
// 툴팁 설정
var tooltip = $('<div style="position: absolute; z-index: 1000; padding: 5px 10px; background-color: #fff; border: solid 2px #000; font-size: 14px; pointer-events: none; display: none;"> </div>');
tooltip.appendTo(map.getPanes().floatPane);

// 로드된 행정구역은 아래와 같은 형태
regionGeoJson.push({
	"type": "FeatureCollection",
	"features": [{
		"id": "11140", 
		"type": "Feature", 
		"properties": {"SIG_CD": "11140", "SIG_ENG_NM": "Jung-gu", "SIG_KOR_NM": "중구"}, 
		"geometry": {
			"type": "MultiPolygon", 
			"coordinates": [[[
				[127.0233653, 37.5719143], [127.0233917, 37.5719073], [127.0235305, 37.5671585], [127.0235359, 37.5669135], [127.0235319, 37.5668462], 
				[127.0235326, 37.5668336], [127.0217938, 37.5575103], [127.0217328, 37.5575278], [127.0195773, 37.5574955], [127.0196807, 37.5572629], 
				[127.0180939, 37.5568746], [127.0178901, 37.5567028], [127.0162301, 37.5528015], [127.0159829, 37.552589], [127.015938, 37.5525498], 
				[127.015858, 37.552471], [127.0089881, 37.5441349], [127.0050173, 37.5461716], [127.0061278, 37.5481932], [127.0046885, 37.5486851], 
				[127.0045604, 37.5498499], [127.0043733, 37.5501537], [127.0043557, 37.5501974], [127.0043362, 37.5502112], [127.0042094, 37.5501507], 
				[127.0034213, 37.5500195], [127.0028642, 37.5496416], [127.0016841, 37.5500597], [126.9983251, 37.5496954], [126.9944593, 37.547488], 
				[126.9787954, 37.5540872], [126.9724082, 37.5548773], [126.96571, 37.5541518], [126.963376, 37.552259], [126.962778, 37.551848], 
				[126.9626113, 37.5517331], [126.9623428, 37.5515489], [126.9623691, 37.5516032], [126.962376, 37.5516286], [126.9624048, 37.5516477], 
				[126.9623107, 37.55277], [126.9620066, 37.5540349], [126.9619314, 37.554448], [126.9617737, 37.5547951], [126.9617773, 37.554982], 
				[126.9619781, 37.5551268], [126.9621418, 37.5555309], [126.9624769, 37.5559106], [126.9627196, 37.5559726], [126.9631727, 37.5565488], 
				[126.9633575, 37.5566854], [126.9634369, 37.5568535], [126.9634273, 37.5569479], [126.9634093, 37.5569943], [126.963052, 37.5574148], 
				[126.9630411, 37.5580298], [126.9620761, 37.5584566], [126.9615951, 37.5584184], [126.9617358, 37.5588129], [126.961711, 37.5589526], 
				[126.9616892, 37.5589824], [126.9616726, 37.5590258], [126.962956, 37.5591763], [126.9632096, 37.5591958], [126.9633065, 37.5592155], 
				[126.9668376, 37.561274], [126.9674439, 37.5615089], [126.9681526, 37.5616215], [126.969265, 37.5619273], [126.9694319, 37.5619679], 
				[126.9694641, 37.5619758], [126.9693301, 37.5622305], [126.9689586, 37.5629149], [126.967562, 37.5648787], [126.9666982, 37.56582], 
				[126.9668651, 37.5659861], [126.9668874, 37.5660078], [126.9966167, 37.5686865], [126.9968368, 37.5687099], [126.997025, 37.5687315], 
				[127.0007881, 37.5693806], [127.0013078, 37.5694769], [127.014613, 37.5697183], [127.0147018, 37.5697206], [127.0176066, 37.5702101], 
				[127.0177723, 37.5702912], [127.0233653, 37.5719143]
			]]]
		}
	}]
});

[행정구역 표시]

//--------------------------------------
// 행정구역 표시
//--------------------------------------
function startDataLayer() {
    map.data.setStyle(function(feature) {
        var styleOptions = {
            fillColor: '#ff0000',
            fillOpacity: 0.0001,
            strokeColor: '#ff0000',
            strokeWeight: 4,
            strokeOpacity: 0.4
        };

        if (feature.getProperty('focus')) {
            styleOptions.fillOpacity = 0.6;
            styleOptions.fillColor = '#0f0';
            styleOptions.strokeColor = '#0f0';
            styleOptions.strokeWeight = 4;
            styleOptions.strokeOpacity = 1;
        }

        return styleOptions;
    });

    regionGeoJson.forEach(function(geojson) {
        map.data.addGeoJson(geojson);
    });

    map.data.addListener('click', function(e) {
        var feature = e.feature;

        if (feature.getProperty('focus') !== true) {
            feature.setProperty('focus', true);
        } else {
            feature.setProperty('focus', false);
        }
    });

    map.data.addListener('mouseover', function(e) {
        var feature = e.feature;
		var regionName = feature.getProperty('SIG_KOR_NM');

        tooltip.css({
            display: '',
            left: e.offset.x,
            top: e.offset.y
        }).text(regionName);

        map.data.overrideStyle(feature, {
            fillOpacity: 0.6,
            strokeWeight: 4,
            strokeOpacity: 1
        });
    });

    map.data.addListener('mouseout', function(e) {
        tooltip.hide().empty();
        map.data.revertStyle();
    });
}

startDataLayer();

참고

https://blog.hkwon.me/draw-korean-map-chart-with-geojson/

http://www.gisdeveloper.co.kr/?p=2332