From d4a98a50e5a6aaeb5462784ff879b53b4f1a110f Mon Sep 17 00:00:00 2001 From: Parksunghyeon <79688915+pshdev1030@users.noreply.github.com> Date: Thu, 8 Sep 2022 13:53:05 +0900 Subject: [PATCH] feat(view): add cloc linechart (#105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add cloc linechart cloc 차트를 구현하였습니다. 차후 수정해야할 부분을 주석의 TODO로 정리 해두었습니다. * fix: data가 없을 경우 early return --- .../ClocLineChart/ClocLineChart.tsx | 72 ++++++++++++++++++- .../TemporalFilter/TemporalFilter.util.ts | 7 ++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/packages/view/src/components/TemporalFilter/ClocLineChart/ClocLineChart.tsx b/packages/view/src/components/TemporalFilter/ClocLineChart/ClocLineChart.tsx index 21065467..bc9b823f 100644 --- a/packages/view/src/components/TemporalFilter/ClocLineChart/ClocLineChart.tsx +++ b/packages/view/src/components/TemporalFilter/ClocLineChart/ClocLineChart.tsx @@ -1,8 +1,76 @@ +import { + axisBottom, + axisLeft, + extent, + scaleBand, + scaleLinear, + scaleTime, + select, + ticks, + timeTicks, +} from "d3"; +import { useEffect, useRef } from "react"; + import type { CommitNode } from "../TemporalFilter.type"; +import { getCloc, timeFormatter } from "../TemporalFilter.util"; + +// TODO margin 추가하기 const ClocLineChart = ({ data }: { data: CommitNode[] }) => { - console.log(data); - return <>ClocLineChart; + const wrapperRef = useRef(null); + const ref = useRef(null); + + useEffect(() => { + if (!wrapperRef.current || !ref.current || !data) return; + + const { width, height } = wrapperRef.current.getBoundingClientRect(); + const svg = select(ref.current).attr("width", width).attr("height", height); + + // TODO cleanup으로 옮기기 + svg.selectAll("*").remove(); + + const xMin = data[0].commit.commitDate; + const xMax = data[data.length - 1].commit.commitDate; + + const [yMin, yMax] = extent(data, (d) => getCloc(d)) as [number, number]; + + const xScale = scaleTime() + .domain([new Date(xMin), new Date(xMax)]) + .range([0, width]); + + const xScaleBand = scaleBand() + .domain(data.map((commitNode) => commitNode.commit.commitDate)) + .range([0, width]); + + const xAxis = axisBottom(xScale) + .tickValues(timeTicks(new Date(xMin), new Date(xMax), 10)) + .tickFormat((d) => timeFormatter(new Date(d))); + + const yScale = scaleLinear().domain([yMin, yMax]).range([height, 0]); + + const yAxis = axisLeft(yScale).tickValues(ticks(yMin, yMax, 10)); + + svg.append("g").call(xAxis).attr("transform", `translate(0,${height})`); + + svg.append("g").call(yAxis).attr("transform", `translate(${width},0)`); + + svg + .selectAll(".cloc") + .data(data) + .join("rect") + .classed("cloc", true) + .attr("x", (d) => xScale(new Date(d.commit.commitDate))) + .attr("y", (d) => yScale(getCloc(d))) + .attr("height", (d) => height - yScale(getCloc(d))) + .attr("width", xScaleBand.bandwidth()) + .attr("fill", "black"); + }, [data]); + + return ( +
+ +
+ ); }; export default ClocLineChart; diff --git a/packages/view/src/components/TemporalFilter/TemporalFilter.util.ts b/packages/view/src/components/TemporalFilter/TemporalFilter.util.ts index 220f1e4f..c4d96da1 100644 --- a/packages/view/src/components/TemporalFilter/TemporalFilter.util.ts +++ b/packages/view/src/components/TemporalFilter/TemporalFilter.util.ts @@ -1,3 +1,5 @@ +import { timeFormat } from "d3"; + import type { ClusterNode } from "types/NodeTypes.temp"; import type { CommitNode } from "./TemporalFilter.type"; @@ -14,3 +16,8 @@ export function sortBasedOnCommitNode(data: ClusterNode[]): CommitNode[] { }) ); } + +export const getCloc = (d: CommitNode) => + d.commit.diffStatistics.insertions + d.commit.diffStatistics.deletions; + +export const timeFormatter = timeFormat("%y-%m-%d");