Processing math: 100%

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

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

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

Naver Cloud Flatform에서는 네이버 지도에 관한 여러 어플리케이션e.g.WebDynamicMap,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