게임 후 최종 점수 DB에 넣고 확인(Chart.js 이용(시간, 색상, 정보 추가)

개발공부·2023년 1월 5일
0
post-thumbnail

* 결과

1) 게임 후 결과 저장하기 전에 이동 불가

2) 게임 후 결과 확인(시간 추가)

3) 게임 후 결과 확인(정보 표시, 가장 최근 데이터만 색상 변경)
chartjs-plugin-datalabels 설치

npm i chartjs-plugin-datalabels
ChartJS.register(BarElement, CategoryScale, LinearScale, Tooltip, Legend);
ChartJS.register(ChartDataLabels); //등록하기

development: {
username: "root",
password: process.env.DB_PASSWORD,
database: "DB이름",
host: "127.0.0.1",
dialect: "mysql",
timestamps: true,
timezone: "Asia/Seoul",
dialectOptions: { //해당 부분 추가
charset: "utf8mb4",
dateStrings: true,
typeCast: true,
},
},

* sequelize 오류

▶ sequelize의 테이블 초기화 할 때 생긴 오류
참고한 방법
sequelize에서 SET foreign_key_checks = 0; 적용

오류 코드
errno: 3730,
sqlState: 'HY000',
sqlMessage: "Cannot drop table 'games' referenced by a foreign key constraint 'scores_ibfk_2' on table 'scores'.",
sql: 'DROP TABLE IF EXISTS games;',
parameters: undefined

db.sequelize.query("SET FOREIGN_KEY_CHECKS = 0"); //해당 부분 추가
db.sequelize
  .sync({ force: true })
  .then(() => {
    console.log("DB 연결 성공");
  })
  .catch(console.error);

* 매번 게임 시 맞춘 개수 확인하기

[진행 순서]
▶ 게임이 끝난 후 "결과 저장" 버튼 클릭 시 결과값 저장
▶ 결과가 저장되면 내 정보에서 최근 진행된 게임 결과 확인 가능
▶ (추가할 사항) 시간 초과 됬을 때도 "결과 저장" 버튼 존재
▶ "결과 저장" 버튼을 누르지 않으면 게임 종료 불가능하게 함

await Result.findAll({
limit: 1,
where: {
UserId: req.user.id,
},
order: [["createdAt", "DESC"]],
});

* [차트 작성하기]

작성에 도움 준 글
차트 chart.js로 작성하기
데이터를 불러와서 차트에 적용하기(loop)
차트의 x, y축 결정

[차트 포함된 진행 순서]

▶ loadGameRequest로 Result값 불러오기(그 중 오늘 날짜만 불러올 것)

const { Op } = require("sequelize");
const moment = require("moment");
const TODAY_START = moment().format("YYYY-MM-DD 00:00");
const NOW = moment().format("YYYY-MM-DD 23:59");

router.get("/", async (req, res, next) => {
  try {
    const games = await Result.findAll({
      raw: true,
      UserId: req.user.id,
      where: {
        createdAt: {
          [Op.between]: [TODAY_START, NOW],
        },
      },
      order: [
        ["createdAt", "DESC"], //최신 것부터
      ],
    });
    res.status(200).json(games);
  } catch (error) {
    console.error(error);
    next(error);
  }
});

* API

const games = await Result.findAll({
      UserId: req.user.id,
      createdAt: {
        [Op.gt]: TODAY_START,
        [Op.lt]: NOW,
      },
      order: [
        ["createdAt", "DESC"], //최신 게시글부터
      ],
    });
    const scores = games.map((g) => g.score); //전체 내용 중 score 부분만 전달

    res.status(200).json(scores);

[components/profile/TodayChart.js]

import {
  Chart as ChartJS,
  BarElement,
  CategoryScale,
  LinearScale,
  Tooltip,
  Legend,
} from "chart.js";
import ChartDataLabels from "chartjs-plugin-datalabels";

import { Bar } from "react-chartjs-2";
import { useCallback, useEffect } from "react";
import { loadGamesRequest } from "../../redux/feature/gameSlice";
import { useDispatch, useSelector } from "react-redux";
import { useRouter } from "next/router";

ChartJS.register(BarElement, CategoryScale, LinearScale, Tooltip, Legend);
ChartJS.register(ChartDataLabels);

const TodayChart = () => {
  const dispatch = useDispatch();
  const router = useRouter();
  const { gameScoreLists } = useSelector((state) => state.game);

  useEffect(() => {
    dispatch(loadGamesRequest());
  }, []);

  const ResultArray = [];

  gameScoreLists.map((lists, i) => {
    const splitTimes = lists.createdAt.split(" ");
    const time = splitTimes[1].split(":");
    const result = time[0] + "시" + time[1] + "분" + time[2] + "초";
    ResultArray.push({
      score: `[${parseInt(lists.score)}]`,
      time: result,
    });
  });

  var lineChartData = {
    labels: [""],
    datasets: [],
  };

  const colors = ["rgba(240, 187, 98, 0.5)", "rgba(78, 108, 80, 0.5)"];

  ResultArray.forEach((a, i) => {
    lineChartData.datasets.push({
      label: `${a.time}`,
      //가장 처음 값만 다르게 색상 표시
      fillColor: `${ResultArray[0].score === a.score ? colors[0] : colors[1]}`,
      borderColor: `${
        ResultArray[0].score === a.score ? colors[0] : colors[1]
      }`,
      backgroundColor: `${
        ResultArray[0].score === a.score ? colors[0] : colors[1]
      }`,
      borderWidth: 1,
      data: JSON.parse(a.score),
      datalabels: {
        // This code is used to display data values
        anchor: "end",
        align: "top",
        formatter: Math.round,
        font: {
          weight: "bold",
          size: 16,
        },
      },
    });
  });

  const data = {
    labels: lineChartData.labels,
    datasets: lineChartData.datasets,
  };

  console.log("data", data);

  const options = {
    scales: {
      y: {
        suggestedMin: 0,
        suggestedMax: 100,
      },
      x: {
        suggestedMin: 0,
        suggestedMax: 100,
      },
    },
  };

  const onGoGame = useCallback(() => {
    router.push("/game");
  }, []);

  return (
    <div>
      {lineChartData.datasets.length === 0 && (
        <div className="mt-5 mb-5">
          <p>오늘 게임에 참여한 적이 없습니다.</p>
          <button
            onClick={onGoGame}
            className="mt-2 font-bold bg-light-green text-white hover:bg-gray-100 hover:text-light-green px-4 py-2 rounded"
          >
            게임 시작하기
          </button>
        </div>
      )}
      {lineChartData.datasets.length !== 0 && (
        <div>
          <h1 className="font-bold">오늘의 결과</h1>
          <p>(점수가 0인 경우 표에 표시되지 않습니다.)</p>
          <Bar data={data} options={options}></Bar>
        </div>
      )}
    </div>
  );
};

export default TodayChart;
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글