barchart.js
const svg = d3
.select(".canvas")
.append("svg")
.attr("width", 600)
.attr("height", 600);
// 차트에 여백 만들기
const margin = { top: 20, right: 20, bottom: 100, left: 100 };
const graphWidth = 600 - margin.left - margin.right;
const graphHeight = 600 - margin.top - margin.bottom;
const graph = svg
.append("g")
.attr("width", graphWidth)
.attr("height", graphHeight)
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const xAxisGroup = graph
.append("g")
.attr("transform", `translate(0, ${graphHeight})`); // x축 아래로 translate
const yAxisGroup = graph.append("g");
// Data 적용해서 차트 만들기
d3.json("../menu.json").then(data => {
const rects = graph.selectAll("rect").data(data);
const y = d3
.scaleLinear() // 한계치 설정
.domain([0, d3.max(data, d => d.orders)])
.range([graphHeight, 0]);
const min = d3.min(data, d => d.orders); // 가장 작은 수 반환
const max = d3.max(data, d => d.orders); // 가장 큰 수 반환
const extent = d3.extent(data, d => d.orders); // [min, max] 반환
const x = d3
.scaleBand()
.domain(data.map(item => item.name)) // data 각각의 이름 설정
.range([0, 500])
.paddingInner(0.2) // 0.2 padding
.paddingOuter(0.2);
rects
.attr("width", x.bandwidth)
.attr("height", d => graphHeight - y(d.orders)) // data의 orders 값 적용
.attr("fill", "orange")
.attr("x", d => x(d.name)) // data index 값 * 70
.attr("y", d => y(d.orders));
// 반환되지 못한 나머지 data 가상 DOM으로 생성
rects
.enter()
.append("rect")
.attr("width", x.bandwidth)
.attr("height", d => graphHeight - y(d.orders))
.attr("fill", "orange")
.attr("x", d => x(d.name))
.attr("y", d => y(d.orders)); // 위에 있는 그래프 뒤집기
// x축 y축 (axis) 생성
const xAxis = d3.axisBottom(x);
const yAxis = d3
.axisLeft(y)
.ticks(3) //ticks 는 y축 눈금 갯수
.tickFormat(d => d + " orders"); // 눈금 값 설정
// 축 적용
xAxisGroup.call(xAxis);
yAxisGroup.call(yAxis);
xAxisGroup
.selectAll("text") // x축 눈금 값. text 선택
.attr("transform", "rotate(-40)")
.attr("text-anchor", "end")
.attr("fill", "orange");
});
차트에 적용한 Data
menu.json
[{
"name": "veg soup",
"orders": 200
},
{
"name": "veg curry",
"orders": 600
},
{
"name": "veg pasta",
"orders": 300
},
{
"name": "veg surprise",
"orders": 900
},
{
"name": "veg burger",
"orders": 1500
}
]
Json data를 사용해서 만들었던 Barchart를 Firebase db에 연동해서 같은 차트를 만들어 보자.
Firebase에 데이터베이스를 생성해주고 스크립트를 연결해준다.
index.html
<script src="https://www.gstatic.com/firebasejs/7.2.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.0/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: //
authDomain: //
databaseURL: //
projectId: //
storageBucket: //
messagingSenderId: //
appId: //
measurementId://
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const db = firebase.firestore(); // data베이스 연결
</script>
데이터를 연결하는 부분만 수정해주면 된다.
barchart.js
// Firebase Data 적용해서 차트 만들기
db.collection("dishes")
.get()
.then(res => {
let data = [];
res.docs.forEach(doc => {
data.push(doc.data());
});
console.log(data); // firebase data 배열
차트를 만드는 함수를 데이터에 따라 재사용할 수 있게 모듈화 시킨다.
// ***** update function 모듈화 하기 ******
const update = data => {
// updating scale domains
y.domain([0, d3.max(data, d => d.orders)]);
x.domain(data.map(item => item.name));
// data 와 rects 연결
const rects = graph.selectAll("rect").data(data);
// remove exit selection
rects.exit().remove();
// update current shape in hte DOM
rects
.attr("width", x.bandwidth)
.attr("height", d => graphHeight - y(d.orders)) // data의 orders 값 적용
.attr("fill", "orange")
.attr("x", d => x(d.name)) // data index 값 * 70
.attr("y", d => y(d.orders));
// 반환되지 못한 나머지 data 가상 DOM으로 생성
rects
.enter()
.append("rect")
.attr("width", x.bandwidth)
.attr("height", d => graphHeight - y(d.orders))
.attr("fill", "orange")
.attr("x", d => x(d.name))
.attr("y", d => y(d.orders)); // 위에 있는 그래프 뒤집기
// 축 적용
xAxisGroup.call(xAxis);
yAxisGroup.call(yAxis);
};
// Firebase Data 적용해서 차트 만들기
db.collection("dishes")
.get()
.then(res => {
let data = [];
res.docs.forEach(doc => {
data.push(doc.data());
});
console.log(data); // firebase data 배열
update(data); // 한번 호출로 차트 생성
onSnapshot() 메서드로 문서를 수신 대기할 수 있습니다. 사용자가 제공하는 콜백이 최초로 호출될 때는 단일 문서의 현재 내용으로 문서 스냅샷이 즉시 생성됩니다. 그런 다음 내용이 변경될 때마다 콜백이 호출되어 문서 스냅샷을 업데이트합니다.
data type에 따라 실시간으로 상태를 업데이트한다.
let data = [];
// 실시간 업데이트 함수
db.collection("dishes").onSnapshot(res => {
res.docChanges().forEach(change => {
const doc = { ...change.doc.data(), id: change.doc.id };
switch (change.type) {
case "added":
data.push(doc);
break;
case "modified":
const index = data.findIndex(item => item.id == doc.id);
data[index] = doc;
break;
case "removed":
data = data.filter(item => item.id !== doc.id);
break;
default:
break;
}
});
updatae(data);
차트가 아래에서 위로 올라오는 transition 효과
rects
.enter()
.append("rect")
.attr("width", x.bandwidth)
.attr("height", d => 0)
.attr("fill", "orange")
.attr("x", d => x(d.name))
.attr("y", graphHeight)
.transition() // transition 효과 주기
.duration(500)
.attr("y", d => y(d.orders)) // 위에 있는 그래프 뒤집기
.attr("height", d => graphHeight - y(d.orders));