[Flask] 초간단! HTML과 Flask 통신 - 3

2024. 2. 4. 23:02BE/Flask

728x90

본 포스팅에서는 Naver Cloud Flatform의 API를 이용해 Flask서버에서 지도 정보를 받아서 웹 페이지에서 지도를 그려주는 것에 관해 다룹니다.

Naver Cloud Flatform에서는 네이버 지도에 관한 여러 어플리케이션(e.g. Web Dynamic Map, Geocoding)을 API로 제공합니다. 회원 가입을 하고 ID를 발급 받는 과정등은 추후에 다른 포스팅에서 다루도록하고 본 포스팅에서는 geocoding을 이용하여 어떻게 지도를 불러오고 웹페이지에 그리는지에 대해 다루도록 하겠습니다.

먼저 flask서버에서 geocoding을 이용할 수 있도록 관련 설정을 해주고, requests 라이브러리의 get함수를 통해서 url의 정보를 가져옵니다. 그 후, 이것을 parsing하여 원하는 정보를 추출합니다. API의 response에 대한 정보는 코드 아래와 같습니다.

client_id = "CLIENT_ID"
client_secret = "CLIENT_SECRET"
endpoint = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode"
headers = {
    "X-NCP-APIGW-API-KEY-ID": client_id,
    "X-NCP-APIGW-API-KEY": client_secret,
}
address = "불정로 6"
@app.route('/userPost')
def userPost():
    url = f"{endpoint}?query={address}"
    res = requests.get(url, headers=headers)
    if res.json()['addresses']:
        return render_template('userPost.html', lat=res.json()['addresses'][0]['x'], lon=res.json()['addresses'][0]['y'])
    else:
        return render_template('userPost.html', lat=127.1052133, lon=37.3595316)
{
    "status": "OK",
    "meta": {
        "totalCount": 1,
        "page": 1,
        "count": 1
    },
    "addresses": [
        {
            "roadAddress": "경기도 성남시 분당구 불정로 6 그린팩토리",
            "jibunAddress": "경기도 성남시 분당구 정자동 178-1 그린팩토리",
            "englishAddress": "6, Buljeong-ro, Bundang-gu, Seongnam-si, Gyeonggi-do, Republic of Korea",
            "addressElements": [
                {
                    "types": [
                        "POSTAL_CODE"
                    ],
                    "longName": "13561",
                    "shortName": "",
                    "code": ""
                }
            ],
            "x": "127.10522081658463",
            "y": "37.35951219616309",
            "distance": 20.925857741585514
        }
    ],
    "errorMessage": ""
}

위의 플라스크 서버에서 lat, lon을 전달해주었으므로, HTML 파일에서는 jinaj2 템플릿 엔진을 통해 아래와 같이 정보를 이용할 수 있습니다. 먼저 div 태그를 통해 지도가 들어갈 크기를 정해주고, script 태그에서는 지도 div 태그의 아이디를 이용하여 지도를 그려줍니다. 아래의 예시에서는 지도를 확대, 축소하는 여러가지 기능들이 포함되어 있으므로 기호에 맞게 사용하면 됩니다.

<div id="map" style="width: 70%; height: 300px; margin:auto"></div>
<script id="code">
    var center = new naver.maps.LatLng("{{lon}}", "{{lat}}");
    var map = new naver.maps.Map('map', {
      center: center,
      zoom: 13,
      minZoom: 7, //지도의 최소 줌 레벨
      zoomControl: true, //줌 컨트롤의 표시 여부
      zoomControlOptions: { //줌 컨트롤의 옵션
        position: naver.maps.Position.TOP_RIGHT
      }
    });
    map.setOptions("mapTypeControl", true); //지도 유형 컨트롤의 표시 여부

    naver.maps.Event.addListener(map, 'zoom_changed', function (zoom) {
      console.log('zoom:' + zoom);
    });

    map.setOptions('minZoom', 10);
    console.log('잘못된 참조 시점', map.getOptions('minZoom'), map.getOptions('minZoom') === 10);

    // 지도의 옵션 참조는 init 이벤트 이후에 참조해야 합니다.
    naver.maps.Event.once(map, 'init', function () {
      console.log('올바른 참조 시점', map.getOptions('minZoom') === 10);
    });

    // 지도 인터랙션 옵션
    $("#interaction").on("click", function (e) {
      e.preventDefault();

      if (map.getOptions("draggable")) {
        map.setOptions({ //지도 인터랙션 끄기
          draggable: false,
          pinchZoom: false,
          scrollWheel: false,
          keyboardShortcuts: false,
          disableDoubleTapZoom: true,
          disableDoubleClickZoom: true,
          disableTwoFingerTapZoom: true
        });

        $(this).removeClass("control-on");
      } else {
        map.setOptions({ //지도 인터랙션 켜기
          draggable: true,
          pinchZoom: true,
          scrollWheel: true,
          keyboardShortcuts: true,
          disableDoubleTapZoom: false,
          disableDoubleClickZoom: false,
          disableTwoFingerTapZoom: false
        });

        $(this).addClass("control-on");
      }
    });

    // 관성 드래깅 옵션
    $("#kinetic").on("click", function (e) {
      e.preventDefault();

      if (map.getOptions("disableKineticPan")) {
        map.setOptions("disableKineticPan", false); //관성 드래깅 켜기
        $(this).addClass("control-on");
      } else {
        map.setOptions("disableKineticPan", true); //관성 드래깅 끄기
        $(this).removeClass("control-on");
      }
    });

    // 타일 fadeIn 효과
    $("#tile-transition").on("click", function (e) {
      e.preventDefault();

      if (map.getOptions("tileTransition")) {
        map.setOptions("tileTransition", false); //타일 fadeIn 효과 끄기

        $(this).removeClass("control-on");
      } else {
        map.setOptions("tileTransition", true); //타일 fadeIn 효과 켜기
        $(this).addClass("control-on");
      }
    });

    // min/max 줌 레벨
    $("#min-max-zoom").on("click", function (e) {
      e.preventDefault();

      if (map.getOptions("minZoom") === 10) {
        map.setOptions({
          minZoom: 7,
          maxZoom: 21
        });
        $(this).val(this.name + ': 7 ~ 21');
      } else {
        map.setOptions({
          minZoom: 10,
          maxZoom: 21
        });
        $(this).val(this.name + ': 10 ~ 21');
      }
    });

    //지도 컨트롤
    $("#controls").on("click", function (e) {
      e.preventDefault();

      if (map.getOptions("scaleControl")) {
        map.setOptions({ //모든 지도 컨트롤 숨기기
          scaleControl: false,
          logoControl: false,
          mapDataControl: false,
          zoomControl: false,
          mapTypeControl: false
        });
        $(this).removeClass('control-on');
      } else {
        map.setOptions({ //모든 지도 컨트롤 보이기
          scaleControl: true,
          logoControl: true,
          mapDataControl: true,
          zoomControl: true,
          mapTypeControl: true
        });
        $(this).addClass('control-on');
      }
    });

    $("#interaction, #tile-transition, #controls").addClass("control-on");
</script>

'BE > Flask' 카테고리의 다른 글

[Flask] 초간단! HTML과 Jinja2  (0) 2024.01.30
[Flask] 초간단! HTML과 Flask 통신 - 2  (2) 2024.01.29
[Flask] 초간단! HTML과 Flask 통신 - 1  (1) 2024.01.29