Merge branch 'feature/Location' into feature/react.js
# Conflicts: # package-lock.json # package.json
Showing
8 changed files
with
262 additions
and
0 deletions
html/index.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html> | ||
3 | + <head> | ||
4 | + <title>Take an Umbrella</title> | ||
5 | + <meta charset="UTF-8"> | ||
6 | + <link rel="stylesheet" type="text/css" href="style.css" /> | ||
7 | + </head> | ||
8 | + <body> | ||
9 | + <h1 style="font-family:Nanum Gothic;"> Take an Umbrella </h1> | ||
10 | + <h3 style="font-family:Nanum Gothic;"> 철학과 2017101598 맹주환 </h3> | ||
11 | + <pre align="center" style="font-family:Nanum Gothic;" font size="20"> | ||
12 | + 반가워요! | ||
13 | + Take an umbrella는 스마트 조명 제품 Philips hue API와 기상청 공공데이터 날씨 API로 구성되어 있어요. | ||
14 | + Hue가 연결된 WI-FI로 접속하셔서 아래의 지도로 현재 위치를 조회하시면, 해당 지역 기상 예보를 받아와 조명을 통해 우산을 챙겨야 하는지 알려줘요! | ||
15 | + </pre> | ||
16 | + <div id="map"></div> | ||
17 | + <!-- Async script executes immediately and must be after any DOM elements used in callback. --> | ||
18 | + | ||
19 | + <h1 style="font-family:Nanum Gothic;"> 당신의 현재 위치 </h1> | ||
20 | + <div align="center">현재 위도: <span id="lat"></span></div> | ||
21 | + <div align="center">현재 경도: <span id="lng"></span></div> | ||
22 | + </body> | ||
23 | + <script src="map.js"></script> | ||
24 | + <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> | ||
25 | + <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAguo3zH8vWZJbzXEqyp8D8UvnBh3zX8rQ&callback=initMap&v=weekly" async> </script> | ||
26 | +</html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
html/map.js
0 → 100644
1 | +// Note: This example requires that you consent to location sharing when | ||
2 | +// prompted by your browser. If you see the error "The Geolocation service | ||
3 | +// failed.", it means you probably did not give permission for the browser to | ||
4 | +// locate you. | ||
5 | + | ||
6 | +let map, infoWindow; | ||
7 | + | ||
8 | +function initMap() { | ||
9 | + map = new google.maps.Map(document.getElementById("map"), { | ||
10 | + center: { lat: 37.5642135, lng: 127.0016985 }, | ||
11 | + zoom: 10, | ||
12 | + }); | ||
13 | + infoWindow = new google.maps.InfoWindow(); | ||
14 | + | ||
15 | + const locationButton = document.createElement("button"); | ||
16 | + | ||
17 | + locationButton.textContent = "위치 조회 하기"; | ||
18 | + locationButton.classList.add("custom-map-control-button"); | ||
19 | + map.controls[google.maps.ControlPosition.TOP_CENTER].push(locationButton); | ||
20 | + locationButton.addEventListener("click", () => { | ||
21 | + // Try HTML5 geolocation. | ||
22 | + if (navigator.geolocation) { | ||
23 | + navigator.geolocation.getCurrentPosition( | ||
24 | + (position) => { | ||
25 | + const pos = { | ||
26 | + lat: position.coords.latitude, | ||
27 | + lng: position.coords.longitude, | ||
28 | + }; | ||
29 | + infoWindow.setPosition(pos); | ||
30 | + infoWindow.setContent("위치를 찾았습니다."); | ||
31 | + infoWindow.open(map); | ||
32 | + map.setCenter(pos); | ||
33 | + document.getElementById("lat").innerHTML = pos.lat; | ||
34 | + document.getElementById("lng").innerHTML = pos.lng; | ||
35 | + // console.log(dfs_xy_conv("toXY",pos.lat,pos.lng)); | ||
36 | + | ||
37 | + }, | ||
38 | + () => { | ||
39 | + handleLocationError(true, infoWindow, map.getCenter()); | ||
40 | + } | ||
41 | + ); | ||
42 | + } else { | ||
43 | + // Browser doesn't support Geolocation | ||
44 | + handleLocationError(false, infoWindow, map.getCenter()); | ||
45 | + } | ||
46 | + }); | ||
47 | +} | ||
48 | + | ||
49 | +function handleLocationError(browserHasGeolocation, infoWindow, pos) { | ||
50 | + infoWindow.setPosition(pos); | ||
51 | + infoWindow.setContent( | ||
52 | + browserHasGeolocation | ||
53 | + ? "Error: 위치 조회 서비스가 실패하였습니다." | ||
54 | + : "Error: 브라우저가 위치 조회 기능을 지원하지 않습니다." | ||
55 | + ); | ||
56 | + infoWindow.open(map); | ||
57 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
html/style.css
0 → 100644
1 | +/* Always set the map height explicitly to define the size of the div | ||
2 | + * element that contains the map. */ | ||
3 | + | ||
4 | + @import url(http://fonts.googleapis.com/earlyaccess/nanumgothic.css); | ||
5 | + h1 { text-align: center; } | ||
6 | + h2 { text-align: center; } | ||
7 | + h3 { text-align: center; } | ||
8 | + | ||
9 | + #map { | ||
10 | + width:600px; | ||
11 | + height:400px; | ||
12 | + margin: 0 auto; | ||
13 | + | ||
14 | + | ||
15 | + } | ||
16 | + .custom-map-control-button { | ||
17 | + background-color: #fff; | ||
18 | + border: 0; | ||
19 | + border-radius: 2px; | ||
20 | + box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3); | ||
21 | + margin: 10px; | ||
22 | + padding: 0 0.5em; | ||
23 | + font: 400 18px Roboto, Arial, sans-serif; | ||
24 | + overflow: hidden; | ||
25 | + height: 40px; | ||
26 | + cursor: pointer; | ||
27 | + } | ||
28 | + .custom-map-control-button:hover { | ||
29 | + background: #ebebeb; | ||
30 | + } | ||
31 | + | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
import/Weather.js
0 → 100644
1 | +const request = require('request'); | ||
2 | +const moment = require('moment'); | ||
3 | +require('moment-timezone'); | ||
4 | +moment.tz.setDefault("Asia/seoul"); | ||
5 | +let date = new String(get_base_date()); | ||
6 | +let time = new String(get_base_time()); | ||
7 | +var url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst'; | ||
8 | +var queryParams = '?' + encodeURIComponent('serviceKey') + '=5e8RQfsCMcXO61FvD7j5tgt5fHf0NYadkSaW6%2FhYQHdoxSgQFXbN7VSb4CI%2BW9scLv2usb3riB7UAGNF7Wb6nA%3D%3D'; /* Service Key*/ | ||
9 | +queryParams += '&' + encodeURIComponent('pageNo') + '=' + encodeURIComponent('1'); /* */ | ||
10 | +queryParams += '&' + encodeURIComponent('numOfRows') + '=' + encodeURIComponent('10'); /* */ | ||
11 | +queryParams += '&' + encodeURIComponent('dataType') + '=' + encodeURIComponent('JSON'); /* */ | ||
12 | +queryParams += '&' + encodeURIComponent('base_date') + '=' + encodeURIComponent(date); /* */ | ||
13 | +queryParams += '&' + encodeURIComponent('base_time') + '=' + encodeURIComponent(time); /* */ | ||
14 | +queryParams += '&' + encodeURIComponent('nx') + '=' + encodeURIComponent('55'); /* */ | ||
15 | +queryParams += '&' + encodeURIComponent('ny') + '=' + encodeURIComponent('127'); /* */ | ||
16 | + | ||
17 | + | ||
18 | +function get_base_date() // 날짜 추출 함수 | ||
19 | +{ | ||
20 | + // 0000~0210 사이 시간대에 조회시 전일(date -1)로 변경 | ||
21 | + let date =moment().format('YYYYMMDD'); | ||
22 | + let time = new String(moment().format('HHmm')); | ||
23 | + if ('0000'<=time && time<'0210'){date -= 1} | ||
24 | + return date | ||
25 | +} | ||
26 | + | ||
27 | +function get_base_time() // 시간 추출 함수 | ||
28 | +{ | ||
29 | + //단기예보 | ||
30 | + //- Base_time : 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 (1일 8회) | ||
31 | + //- API 제공 시간(~이후) : 02:10, 05:10, 08:10, 11:10, 14:10, 17:10, 20:10, 23:10 | ||
32 | + //- 시간대 맞추기 | ||
33 | + let time = new String(moment().format('HHmm')); | ||
34 | + if ('0000'<=time && time<'0210'){time = '2300'} | ||
35 | + else if ('0210'<=time && time<'0510'){time = '0200'} | ||
36 | + else if ('0510'<=time && time<'0810'){time = '0500'} | ||
37 | + else if ('0810'<=time && time<'1110'){time = '0800'} | ||
38 | + else if ('1110'<=time && time<'1410'){time = '1100'} | ||
39 | + else if ('1410'<=time && time<'1710'){time = '1400'} | ||
40 | + else if ('1710'<=time && time<'2010'){time = '1700'} | ||
41 | + else if ('2010'<=time && time<'2310'){time = '2010'} | ||
42 | + else if ('2310'<=time && time<'2359'){time = '2300'} | ||
43 | + return time | ||
44 | + } | ||
45 | + | ||
46 | +request({ | ||
47 | + url: url + queryParams, | ||
48 | + method: 'GET' | ||
49 | +}, function (error, response, body) { | ||
50 | + console.log('Status', response.statusCode); | ||
51 | + console.log('Headers', JSON.stringify(response.headers)); | ||
52 | + console.log('Reponse received', body); | ||
53 | +}); | ||
54 | + | ||
55 | +// | ||
56 | +// (사용 예) | ||
57 | +// var rs = dfs_xy_conv("toLL","60","127"); | ||
58 | +// console.log(rs.lat, rs.lng); | ||
59 | + | ||
60 | +dfs_xy_conv = function (code, v1, v2) { | ||
61 | +// 소스출처 : http://www.kma.go.kr/weather/forecast/digital_forecast.jsp | ||
62 | +// LCC DFS 좌표변환 ( code : "toXY"(위경도->좌표, v1:위도, v2:경도), "toLL"(좌표->위경도,v1:x, v2:y) ) | ||
63 | + | ||
64 | + var RE = 6371.00877; // 지구 반경(km) | ||
65 | + var GRID = 5.0; // 격자 간격(km) | ||
66 | + var SLAT1 = 30.0; // 투영 위도1(degree) | ||
67 | + var SLAT2 = 60.0; // 투영 위도2(degree) | ||
68 | + var OLON = 126.0; // 기준점 경도(degree) | ||
69 | + var OLAT = 38.0; // 기준점 위도(degree) | ||
70 | + var XO = 43; // 기준점 X좌표(GRID) | ||
71 | + var YO = 136; // 기1준점 Y좌표(GRID) | ||
72 | + | ||
73 | + var DEGRAD = Math.PI / 180.0; | ||
74 | + var RADDEG = 180.0 / Math.PI; | ||
75 | + | ||
76 | + var re = RE / GRID; | ||
77 | + var slat1 = SLAT1 * DEGRAD; | ||
78 | + var slat2 = SLAT2 * DEGRAD; | ||
79 | + var olon = OLON * DEGRAD; | ||
80 | + var olat = OLAT * DEGRAD; | ||
81 | + | ||
82 | + var sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5); | ||
83 | + sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn); | ||
84 | + var sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5); | ||
85 | + sf = Math.pow(sf, sn) * Math.cos(slat1) / sn; | ||
86 | + var ro = Math.tan(Math.PI * 0.25 + olat * 0.5); | ||
87 | + ro = re * sf / Math.pow(ro, sn); | ||
88 | + var rs = {}; | ||
89 | + if (code == "toXY") { | ||
90 | + rs['lat'] = v1; | ||
91 | + rs['lng'] = v2; | ||
92 | + var ra = Math.tan(Math.PI * 0.25 + (v1) * DEGRAD * 0.5); | ||
93 | + ra = re * sf / Math.pow(ra, sn); | ||
94 | + var theta = v2 * DEGRAD - olon; | ||
95 | + if (theta > Math.PI) theta -= 2.0 * Math.PI; | ||
96 | + if (theta < -Math.PI) theta += 2.0 * Math.PI; | ||
97 | + theta *= sn; | ||
98 | + rs['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5); | ||
99 | + rs['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5); | ||
100 | + } | ||
101 | + else { | ||
102 | + rs['x'] = v1; | ||
103 | + rs['y'] = v2; | ||
104 | + var xn = v1 - XO; | ||
105 | + var yn = ro - v2 + YO; | ||
106 | + ra = Math.sqrt(xn * xn + yn * yn); | ||
107 | + if (sn < 0.0) - ra; | ||
108 | + var alat = Math.pow((re * sf / ra), (1.0 / sn)); | ||
109 | + alat = 2.0 * Math.atan(alat) - Math.PI * 0.5; | ||
110 | + | ||
111 | + if (Math.abs(xn) <= 0.0) { | ||
112 | + theta = 0.0; | ||
113 | + } | ||
114 | + else { | ||
115 | + if (Math.abs(yn) <= 0.0) { | ||
116 | + theta = Math.PI * 0.5; | ||
117 | + if (xn < 0.0) - theta; | ||
118 | + } | ||
119 | + else theta = Math.atan2(xn, yn); | ||
120 | + } | ||
121 | + var alon = theta / sn + olon; | ||
122 | + rs['lat'] = alat * RADDEG; | ||
123 | + rs['lng'] = alon * RADDEG; | ||
124 | + } | ||
125 | + return rs; | ||
126 | + } | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
run_server.js
0 → 100644
1 | +// 서비스 제공을 위한 html 홈페이지를 express로 구현하기 (기본적인 뼈대) | ||
2 | +var express = require('express') | ||
3 | +var app = express(); // express 선언 | ||
4 | +const port = 10000 //임의의 포트 10000 | ||
5 | + | ||
6 | +// request 와 response 라는 인자를 줘서 콜백 함수를 만든다. | ||
7 | +// localhost:port 브라우저에 res.sendFile() 내부의 파일이 띄워진다. | ||
8 | +app.use(express.static(__dirname + "/html")); | ||
9 | + | ||
10 | +app.get('/', function(req,res) { | ||
11 | + res.sendFile(__dirname + "/html/index.html") | ||
12 | +}) | ||
13 | + | ||
14 | +//임의의 포트 10000, 접속 주소 localhost:10000/ | ||
15 | +app.listen(port, function(){ | ||
16 | + console.log('서버 구동중 port : %d', port); | ||
17 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
No preview for this file type
No preview for this file type
-
Please register or login to post a comment