ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Vue.js 카카오맵API 날씨RSS를 통한 주소지 날씨 받기
    WEB 2021. 6. 26. 23:11

    입력하는 주소의 날씨를 알아봐야 하는 경우가 생겼다.

     

    이 부분을 구현할때 몇가지 사항을 고려해야 한다.

     

    1. 대부분 주소를 입력하는 경우 주소가 명확하지 않은 경우가 있다.

    예를 들어 "충청북도"를 "충북"이라고 기재한다거나, 동이나 지번을 생략하는 경우가 있다.

    >카카오맵 API를 사용하면 생략되거나 간략 기재된 주소인식률이 높다.

     

    2.날씨를 알려주는 RSS나 RestfulAPI 서비스 중 무료.

    https://openweathermap.org/ 가 있으나, 지역이라던지 결과값이 한글표기가 아닌듯 했다.

    > http://www.kma.go.kr/weather/lifenindustry/sevice_rss.jsp 에서 검색한 내용을

    http://www.kma.go.kr/wid/queryDFS.jsp?gridx=61&gridy=127 의 위도와 경도를 넣어서 받을 수 있다.

    > 1번 카카오맵API를 이용하여 위도와 경도를 뽑을 수 있다.

    > 위도와 경도를 그리드로 변환해야한다. dfs_xy_conv() 참고

       Geocoder()를 사용해야하는데 SDK를 불러오는 부분에 '&libraries=services'이 구문을 넣자.

     

    3. 카카오 개발 API에 가입하여 WEB을 사용하고,

       localhost로 테스트중이라면 도메인 등록에 localhost와 포트까지 추가해야한다.

       또한, Vue에서는 카카오 맵 모듈의 탑재에 대해 정식적인 방안이 없다.

       여러 방법을 찾아 테스트하였으며 아래 기재하였다. 

     

    4. Vue에서 2번 항목 접근시 CORS가 발생한다.

    > vue.config.js를 생성 또는 그 안에 내용을 추가해야한다.

    > npm run serve로 실행해야 한다.

    module.exports = {
      devServer: {
        proxy : {
          '/wid': {
            target: 'http://www.kma.go.kr',
            //changeOrigin: true
          }
        }
      }
    };

     

    5. XML 파싱

    > DOMParser()라는것을 이용하여 직접 파싱을 해줘야 한다.

    > 데이터의 내용은 보면 충분히 알 것이다.

     

    6. 아래는 Vue의 소스

    > 제일 기본적인 맵 표시와, 기본 포인트에 대한 로그출력이 있으므로 참고하자.

    > 추가로, const self = this라고 표기되어있는데, 테스트를 위해 간편하게 기재한 것이고,

       함수의 ES6와 관련이 있는 내용으로 해결해야 한다.

    <template>
        <div id="map" style="width:500px;height:400px;">
        </div>
    </template>
    <script>
    import axios from "axios";
    
    export default {
      name: 'HelloWorld',
      props: {
        msg: String
      },
      data() {
        return {
          //geoval : ""
        }
      },
      methods: {
        initMap() {
          //axios를 위해 변환을 해줘야함
          const self = this;
    
          var mapContainer = document.getElementById('map'), // 지도를 표시할 div
              mapOption = {
                center: new kakao.maps.LatLng(37.564343, 126.947613), // 지도의 중심좌표
                level: 3, // 지도의 확대 레벨
              };
    
          var map = new kakao.maps.Map(mapContainer, mapOption);
    
          //마커추가하려면 객체를 아래와 같이 하나 만든다. 
          var marker = new kakao.maps.Marker({ position: map.getCenter() }); 
          marker.setMap(map);
    
          // 주소-좌표 변환 객체를 생성합니다
          var geocoder = new kakao.maps.services.Geocoder();
    
          // 주소로 좌표를 검색합니다
          geocoder.addressSearch('주소', function(result, status) {
            // 정상적으로 검색이 완료됐으면 
            if (status === kakao.maps.services.Status.OK) {
              var coords = new kakao.maps.LatLng(result[0].y, result[0].x);
              var message = 'latlng: new kakao.maps.LatLng(' + result[0].y + ', ';
              message += result[0].x + ')';
              
              console.log(message);
              var gridXY = self.dfs_xy_conv("toXY", result[0].y, result[0].x);
              self.getWeather(gridXY)
    
          
              // 결과값으로 받은 위치를 마커로 표시합니다
              var marker = new kakao.maps.Marker({
                  map: map,
                  position: coords
              });
    
              // 인포윈도우로 장소에 대한 설명을 표시합니다
              var infowindow = new kakao.maps.InfoWindow({
                  content: '<div style="width:150px;text-align:center;padding:6px 0;">장소</div>'
              });
              infowindow.open(map, marker);
    
              // 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
              map.setCenter(coords);
            } 
          });
        },
        getWeather(params) {
          //좌표에 따른 날씨 XML데이터로 받아옴
          var strQuery = "/wid/queryDFS.jsp?gridx=" + params.x + "&gridy=" + params.y;
          //var strQuery = "http://www.kma.go.kr/wid/queryDFS.jsp?gridx=" + params.x + " &gridy=" + params.y;
          console.log(strQuery);
          axios
            .get(strQuery, {timeout: 5000})
            .then((response) => {
              console.log(response.data); 
              var parser = new DOMParser();
              var xml = parser.parseFromString(response.data, 'text/xml');
              var children = xml.getElementsByTagName('body')[0].getElementsByTagName('data')[0].getElementsByTagName('wfKor')[0].childNodes[0].nodeValue;
              console.log(children);
            })
            .catch((error) => {
              self.loading = false;
              throw error;
            });
        },
        dfs_xy_conv(code, v1, v2) {
          //<!--
          //
          // LCC DFS 좌표변환을 위한 기초 자료
          //
          var RE = 6371.00877; // 지구 반경(km)
          var GRID = 5.0; // 격자 간격(km)
          var SLAT1 = 30.0; // 투영 위도1(degree)
          var SLAT2 = 60.0; // 투영 위도2(degree)
          var OLON = 126.0; // 기준점 경도(degree)
          var OLAT = 38.0; // 기준점 위도(degree)
          var XO = 43; // 기준점 X좌표(GRID)
          var YO = 136; // 기1준점 Y좌표(GRID)
          //
          // LCC DFS 좌표변환 ( code : "toXY"(위경도->좌표, v1:위도, v2:경도), "toLL"(좌표->위경도,v1:x, v2:y) )
          //
          
            var DEGRAD = Math.PI / 180.0;
            var RADDEG = 180.0 / Math.PI;
    
            var re = RE / GRID;
            var slat1 = SLAT1 * DEGRAD;
            var slat2 = SLAT2 * DEGRAD;
            var olon = OLON * DEGRAD;
            var olat = OLAT * DEGRAD;
    
            var sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5);
            sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn);
            var sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
            sf = Math.pow(sf, sn) * Math.cos(slat1) / sn;
            var ro = Math.tan(Math.PI * 0.25 + olat * 0.5);
            ro = re * sf / Math.pow(ro, sn);
            var rs = {};
            if (code == "toXY") {
                rs['lat'] = v1;
                rs['lng'] = v2;
                var ra = Math.tan(Math.PI * 0.25 + (v1) * DEGRAD * 0.5);
                ra = re * sf / Math.pow(ra, sn);
                var theta = v2 * DEGRAD - olon;
                if (theta > Math.PI) theta -= 2.0 * Math.PI;
                if (theta < -Math.PI) theta += 2.0 * Math.PI;
                theta *= sn;
                rs['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
                rs['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
            }
            else {
                rs['x'] = v1;
                rs['y'] = v2;
                var xn = v1 - XO;
                var yn = ro - v2 + YO;
                ra = Math.sqrt(xn * xn + yn * yn);
                if (sn < 0.0) - ra;
                var alat = Math.pow((re * sf / ra), (1.0 / sn));
                alat = 2.0 * Math.atan(alat) - Math.PI * 0.5;
    
                if (Math.abs(xn) <= 0.0) {
                    theta = 0.0;
                }
                else {
                    if (Math.abs(yn) <= 0.0) {
                        theta = Math.PI * 0.5;
                        if (xn < 0.0) - theta;
                    }
                    else theta = Math.atan2(xn, yn);
                }
                var alon = theta / sn + olon;
                rs['lat'] = alat * RADDEG;
                rs['lng'] = alon * RADDEG;
            }
            return rs;
        }
      },
      mounted(){
        if (window.kakao && window.kakao.maps) {
          this.initMap();
        } else {
          const script = document.createElement('script');
          
          script.onload = () => kakao.maps.load(this.initMap);
          //카카오 개발자 서비스에서 서버 주소 등록해야 함
          script.src =
            '//dapi.kakao.com/v2/maps/sdk.js?autoload=false&appkey=카카오키값&libraries=services';
          document.head.appendChild(script);
        }
      }
    }
    </script>
    
    

    'WEB' 카테고리의 다른 글

    InfluxDB 1.8.1 윈도우 설치  (0) 2023.07.17
    Node.js 연동 ajax 기본  (0) 2022.09.29
    pm2 명령어를 찾을 수 없습니다.  (0) 2022.09.27
    mariadb 최초 설정  (1) 2022.09.26
    공공데이터포털을 통한 날씨 받기  (0) 2021.07.05

    댓글

Designed by Tistory.