
스마트팜 페이지의 레이아웃을 유지하기 위해 변경을 했다.
하지만, 필요한 정보가 달라서
기상청_단기예보 api를 받아와 습도, 강수량, 풍량, 풍속의 정보를 1시간 단위로 받아왔다.
const [humidity, setHumidity] = useState([]); // 습도 값을 상태로 관리
const [rain, setRain] = useState([]);
const [vec, setVec] = useState([]);
const [wsd, setWsd] = useState([]);
const fire_real_api_key = "";
useEffect(() => {
console.log("현재 위치:", location);
if (!location) return;
const today2 = new Date();
const formattedDate2 = `${today2.getFullYear()}${String(today2.getMonth() + 1).padStart(2,0)}${today2.getDate()}`; // 원하는 형식으로 날짜를 설정합니다.
const baseTimes = ["0200", "0500", "0800", "1100", "1400", "1700", "2000", "2300"];
const now = today2.getHours() * 100;
const base_time = baseTimes.reduce((prev, curr) =>
now >= curr ? curr : prev
);
const {nx, ny } = latLonToGrid(location.latitude, location.longitude);
const fetchData = async () => {
const url = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst";
const queryParams = new URLSearchParams({
serviceKey: decodeURIComponent(fire_real_api_key), // URL 디코딩 필요
numOfRows: "100",
pageNo: "1",
dataType: "JSON",
base_date: formattedDate2,
base_time: base_time,
nx,
ny,
});
try {
const response = await fetch(`${url}?${queryParams}`);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const text = await response.json(); //응답을 XML 문자열로 변환
console.log("text : ", text.response.body.items);
const humidityData = text.response.body.items.item.filter(item => item.category === "REH");
const rainData = text.response.body.items.item.filter(item => item.category === "POP");
const vecData = text.response.body.items.item.filter(item => item.category === "VEC");
const wsdData = text.response.body.items.item.filter(item => item.category === "WSD");
if(humidityData.length > 0){
setHumidity(humidityData);
}
if(rainData.length > 0){
setRain(rainData);
}
if(vecData.length > 0){
setVec(vecData);
}
if(wsdData.length > 0){
setWsd(wsdData);
}
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, [location]);
현재의 날짜와 기상청에서 제공하는 예보 시간을 가져와 설정을 해주었다.
base_date: formattedDate2,
base_time: base_time,
그리고 기상청에서 제공하는 설명서를 통해 원하는 데이터 값을 가져오기 위해 filter를 이용했고, 데이터를 배열에 넣어주었다. 배열을 사용한 이유는 시간단위로 여러 값이 들어가 있기 때문이다.
const [humidity, setHumidity] = useState([]); // 습도 값을 상태로 관리
const [rain, setRain] = useState([]);
const [vec, setVec] = useState([]);
const [wsd, setWsd] = useState([]);
const humidityData = text.response.body.items.item.filter(item => item.category === "REH");
const rainData = text.response.body.items.item.filter(item => item.category === "POP");
const vecData = text.response.body.items.item.filter(item => item.category === "VEC");
const wsdData = text.response.body.items.item.filter(item => item.category === "WSD");
if(humidityData.length > 0){
setHumidity(humidityData);
}
if(rainData.length > 0){
setRain(rainData);
}
if(vecData.length > 0){
setVec(vecData);
}
if(wsdData.length > 0){
setWsd(wsdData);
}
그리고,
<Card className="custom-box-shadow rounded-2"
style={{
padding: 0,
borderRadius: "16px",
background: 'linear-gradient(#617dac, #91AEC4)',
color: 'white',
maxHeight: "80vh",
overflow: "auto" // 내용이 넘치면 스크롤
}}>
<CardBody>
<div className="d-flex flex-column align-items-left text-left justify-content-center"
style={{ fontFamily: "KCC-Hanbit", fontSize: "clamp(10px, 2vw, 15px)" }}>
{/* 🔹 clamp(min, preferred, max) → 화면 크기에 따라 글자 크기 자동 조절 */}
단기예보
<div className='d-flex flex-row justifiy-content-between' style={{gap:"6px"}}>
<div className="d-flex flex-column justify-content-between" style={{ marginTop: 5 }}>
<div style={{ width: "70px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>시간</div>
<hr/>
<div style={{ width: "70px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>습도(%)</div>
<hr/>
<div style={{ width: "70px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>강수량(%)</div>
<hr/>
<div style={{ width: "70px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>풍향(°)</div>
<hr/>
<div style={{ width: "70px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>풍속(m/s)</div>
</div>
{humidity.map((a, i) => {
const formattedTime = `${humidity[i]?.fcstTime.slice(0, 2)}:${humidity[i]?.fcstTime.slice(2)}`;
return (
<div key={i} className="d-flex flex-column justify-content-between" style={{ marginTop: 5 }}>
<div style={{ width: "60px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>{formattedTime}</div>
<hr/>
<div style={{ width: "60px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>{humidity[i]?.fcstValue}</div>
<hr/>
<div style={{ width: "60px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>{rain[i]?.fcstValue}</div>
<hr/>
<div style={{ width: "60px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>{vec[i]?.fcstValue}</div>
<hr/>
<div style={{ width: "60px", textAlign: "left", fontSize: "clamp(10px, 1.5vw, 14px)" }}>{wsd[i]?.fcstValue}</div>
</div>
);
})}
</div>
</div>
</CardBody>
</Card>
card안에 div에 가져온 값을 넣어주었다. 가지고 있는 배열의 length는 같으므로 humidity를 기준으로 배열 순환을 해주었다.
그리고, 화면의 비율에 따라 글씨체를 조정하여, 현재 보여지는 장비현황, 단기예보, 날씨의 div가 화면을 벗어나지 않도록 하고 싶었다. 그래서, 폰트를 조정하도로 clamp를 사용했는데 적용이 안되는 것 같았다.
이 부분은 다시 수정이 필요하다.
현재는 card의 maxheigt를 지정해주어, 그걸 넘어가면 자동으로 스크롤이 생성되도록 설정만 해주었다.
비율이 변하면, div가 화면은 벗어나지는 않지만 보기에는 예쁘지 않다.
--> 데스크탑

--> 노트북 화면

이 부분에 대해서는 따로 공부하고 다시 적용할 필요가 있다.