Intro
인터넷을 찾아보다 Rechart라는 좋은 그래프 패키지를 찾았다.
디자인도 괜찮고 사용방법도 어렵지 않아 이 패키지로 센서 데이터를 시각화 해보기로 했다.
Rechart 패키지 설치
우선 rechart 패키지를 설치해주자.
npm install recharts
그 다음 App.js에 아래의 코드를 추가한 뒤에 차트가 잘 나오는지 테스트해보자.
import React, { PureComponent } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
const data = [
{
name: 'Page A', uv: 4000, pv: 2400, amt: 2400,
},
{
name: 'Page B', uv: 3000, pv: 1398, amt: 2210,
},
{
name: 'Page C', uv: 2000, pv: 9800, amt: 2290,
},
{
name: 'Page D', uv: 2780, pv: 3908, amt: 2000,
},
{
name: 'Page E', uv: 1890, pv: 4800, amt: 2181,
},
{
name: 'Page F', uv: 2390, pv: 3800, amt: 2500,
},
{
name: 'Page G', uv: 3490, pv: 4300, amt: 2100,
},
];
const Chart = () => {
return (
<LineChart
width={500}
height={300}
data={data}
margin={{
top: 5, right: 30, left: 20, bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
<Line type="monotone" dataKey="uv" stroke="#82ca9d" />
</LineChart>
);
}
function App() {
return (
<div>
<Chart />
</div>
);
}
실행하면 차트가 잘 나오는것을 확인할 수 있다.
Chart 컴포넌트 생성
상위 컴포넌트로부터 데이터 Object Array 및 다양한 설정값들을 받아 그래프를 출력하는 Chart 컴포넌트를 만들었다.
Chart.js
import React, { PureComponent } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
import './Chart.css'
class Chart extends PureComponent {
render() {
return (
<div className="chart__container">
<h2 className="chart__title">{this.props.title}</h2>
<ResponsiveContainer width="100%" height="90%">
<LineChart data={this.props.data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey={this.props.name} />
<YAxis domain={this.props.domain}/>
<Tooltip />
<Legend />
{Object.keys(this.props.data[0]).map((key, index) => {
if(key !== this.props.name) return <Line type="monotone" key={index} dataKey={key} stroke={this.props.stroke[key]} strokeWidth={1}/>
})}
</LineChart>
</ResponsiveContainer>
</div>
);
}
}
export default Chart;
상위 컴포넌트로부터 title, data, name, domain, stroke 총 5가지 Property를 받으며, 각각의 역할은 다음과 같다.
- title: 그래프 상단에 출력될 제목
- data: 그래프에 출력될 데이터 및 name 포함
- name: X축 값의 기준 (e.g. 시간)
- domain: Y축 값의 범위
- stroke: 선 색상
Chart를 ResponsiveContainer로 감싸줬는데, 기존 Chart는 Width와 Height를 %로 나타낼 수 없어서 감싸줬다.
Chart.css
.chart__container {
width: 45%;
height: 350px;
margin: 0 10px 60px 10px;
padding: 10px 20px 20px 20px;
border: 1px solid #e9e9e9;
border-radius: 5px;
box-shadow: 2px 2px 10px #f4f4f4;
background: #ffffff;
}
.chart__title {
margin: 5px 0;
text-align: center;
height: 10%;
}
그래프를 2x2로 출력할 것이기 때문에 너비를 45% 정도로 지정했다.
그래프 영역을 강조하기 위해 padding과 border, shadow를 줬다.
속성들을 넣어 그래프를 출력하면 아래와 같은 그래프가 나온다.
센서 데이터 요청
Axios를 사용해 Spring으로부터 센서 데이터를 조회해보자.
우선 그래프의 X축에 시간을 표시하기 위해 ISO 문자열에서 시/분/초를 추출하는 함수를 만들었다.
//2022-08-19T12:34:56.000000 -> 12:34:56
const timeFormat = (date) => date.substring(11, 19);
그 다음 useEffect 안에 2초 주기로 센서 정보를 요청해 state에 저장하는 함수를 넣어
센서 데이터를 지속적으로 갱신하도록 했다.
function App() {
const initialDate = timeFormat(new Date().toISOString());
const [eCO2, setECO2] = useState([{eCO2: 0, date: initialDate}])
const [TVOC, setTVOC] = useState([{TVOC: 0, date: initialDate}])
const [temp, setTemp] = useState([{Temp: 0, date: initialDate}])
const [accel, setAccel] = useState([{x: 0, y:0, z:0, date: initialDate}])
useEffect(() => {
const refresh = () => {
axios.get(`/api/1/sensor?size=10`)
.then(response => {
const data = response.data["sensorData"];
if(data === undefined) return;
setECO2(data.map(col => ({eCO2: col["eco2"], date: timeFormat(col["createdDate"])})).reverse())
setTVOC(data.map(col => ({TVOC: col["tvoc"], date: timeFormat(col["createdDate"])})).reverse())
setTemp(data.map(col => ({Temp: col["temp"], date: timeFormat(col["createdDate"])})).reverse())
setAccel(data.map(col => ({x: col["accel"]["x"], y: col["accel"]["y"], z: col["accel"]["z"], date: timeFormat(col["createdDate"])})).reverse())
})
.catch(error => console.log(error))
}
setInterval(refresh, 2000)
}, []);
return (
<div>
<Chart />
</div>
);
}
console.log로 data를 출력하면 아래와 같이 데이터가 정상적으로 들어오는것을 볼 수 있다.
센서 데이터 그래프 출력
state에 들어있는 센서 데이터를 이전에 만든 Chart 컴포넌트에 넣어 그래프로 출력해보자.
function App() {
...
return (
<div className="app">
<h1 className="app__title">Sensor Monitoring Panel</h1>
<div className="app__chart">
<Chart title="Equivalent CO2 (ppm)" data={eCO2} name="date" domain={[0, 2000]} stroke={{eCO2: "#7900FF"}}/>
<Chart title="Total Volatile Organic Compounds (ppb)" data={TVOC} name="date" domain={[0, 500]} stroke={{TVOC: "#548CFF"}}/>
<Chart title="Temperature (°C)" data={temp} name="date" domain={[20, 40]} stroke={{Temp: "#FF00BE"}}/>
<Chart title="Accelerometer (m/s)" data={accel} name="date" domain={[-15, 15]} stroke={{x: "#FF0000", y: "#00FF00", z: "#0000FF"}}/>
</div>
</div>
);
}
App.css
.app {
width: 80%;
margin: 30px 0 0 0;
}
.app__title {
text-align: center;
margin-bottom: 40px;
}
.app__chart {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: start;
flex-wrap: wrap;
flex-basis: 50%;
}
아래와 같이 데이터가 이쁘게 출력되는것을 볼 수 있다.
센서에 입김을 불면 eCO2, TVOC이 상승하고, MPU6050에 손가락을 대면 Temperature가 상승한다.
센서를 뒤집거나 때리면 가속도값이 변한다. 가속도 센서는 중력가속도의 영향을 받기 때문에 정지 상태일 때 모든 축의 값을 합하면 9.8m/s정도가 나온다.
일단 이쯤에서 마무리하고 발표준비를 할 예정이다.
안드로이드 앱은 발표준비가 완료되고 시간이 남으면 할 수 있을것 같다.
아쉽지만 그래도 이틀만에 이 정도 만든거면 잘 했다고 생각한다.
'Projects > 센서 모니터링 시스템' 카테고리의 다른 글
[센서 모니터링 시스템] 13. Android Chart 구현 (프로젝트 종료) (0) | 2022.08.19 |
---|---|
[센서 모니터링 시스템] 12. Android Request 구현 (0) | 2022.08.19 |
[센서 모니터링 시스템] 10. React 개발환경 구성 (0) | 2022.08.19 |
[센서 모니터링 시스템] 9. 라즈베리파이 Request 구현 (0) | 2022.08.18 |
[센서 모니터링 시스템] 8. Service, REST Controller 개발 (0) | 2022.08.18 |