From ed7858d0a133cae0d899e6844f0fbb2ccde7b346 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 09:32:20 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(component):?= =?UTF-8?q?=20width,=20height=20=EC=86=8D=EC=84=B1=20=ED=95=84=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EA=B0=81=20?= =?UTF-8?q?=EB=B3=80=EC=97=90=20=EC=B6=95=EC=9D=84=20=EA=B7=B8=EB=A6=AC?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BandAxis/BandAxis.stories.tsx | 34 +++------- .../charts/BandAxis/BandAxis.styles.ts | 22 ++++++- src/components/charts/BandAxis/BandAxis.tsx | 66 +++++++++++++------ .../charts/BandAxis/BandAxis.types.ts | 4 +- .../BandAxis/__test__/BandAxis.test.tsx | 46 +++++-------- .../__test__/getAxisOrientConfig.test.ts | 28 -------- src/utils/getAxisOrientConfig.ts | 19 ------ 7 files changed, 96 insertions(+), 123 deletions(-) delete mode 100644 src/utils/__test__/getAxisOrientConfig.test.ts delete mode 100644 src/utils/getAxisOrientConfig.ts diff --git a/src/components/charts/BandAxis/BandAxis.stories.tsx b/src/components/charts/BandAxis/BandAxis.stories.tsx index 9f12518..5cf62c9 100644 --- a/src/components/charts/BandAxis/BandAxis.stories.tsx +++ b/src/components/charts/BandAxis/BandAxis.stories.tsx @@ -29,38 +29,24 @@ const xScale = scaleBand() .range([0, length]); export const Default: Story = { - render: () => ( - - - - ), + render: () => , }; -export const Direction: Story = { +export const Orient: Story = { render: () => ( - - - - - - - - +
+ + + + +
), }; export const LabelHide: Story = { - render: () => ( - - - - ), + render: () => , }; export const LineHide: Story = { - render: () => ( - - - - ), + render: () => , }; diff --git a/src/components/charts/BandAxis/BandAxis.styles.ts b/src/components/charts/BandAxis/BandAxis.styles.ts index aed8f3b..ef090ef 100644 --- a/src/components/charts/BandAxis/BandAxis.styles.ts +++ b/src/components/charts/BandAxis/BandAxis.styles.ts @@ -1,5 +1,25 @@ import { tv } from "@utils/customTV"; export const BandAxisVariants = tv({ - base: "stroke-black", + slots: { + root: "stroke-surface-on", + axisLine: "", + labelText: "", + }, + variants: { + lineHide: { + true: { + axisLine: "hidden", + }, + }, + labelHide: { + true: { + labelText: "hidden", + }, + }, + }, + defaultVariants: { + lineHide: false, + labelHide: false, + }, }); diff --git a/src/components/charts/BandAxis/BandAxis.tsx b/src/components/charts/BandAxis/BandAxis.tsx index 671d045..5480797 100644 --- a/src/components/charts/BandAxis/BandAxis.tsx +++ b/src/components/charts/BandAxis/BandAxis.tsx @@ -1,9 +1,10 @@ -import { getAxisOrientConfig } from "@utils/getAxisOrientConfig"; import { isEven } from "@utils/isEven"; import { BandAxisVariants } from "./BandAxis.styles"; import { BandAxisProps } from "./BandAxis.types"; const BandAxis = ({ + width, + height, orient = "DOWN", axisScale, outerTickLength = 6, @@ -21,35 +22,60 @@ const BandAxis = ({ (endPoint - startPoint) / 2 - axisScale.step() * (isEven(tickCount) ? tickCount / 2 - 0.5 : Math.floor(tickCount / 2)); - const [textdX, textdY, path] = getAxisOrientConfig({ orient, startPoint, endPoint, outerTickLength }); + const pathConfig: { [key: string]: string } = { + DOWN: `M${startPoint + 0.5},${outerTickLength}V0H${endPoint - 0.5}V${outerTickLength}`, + UP: `M${startPoint + 0.5},${height - outerTickLength}V${height}H${endPoint - 0.5}V${height - outerTickLength}`, + RIGHT: `M${outerTickLength},${startPoint + 0.5}H0V${endPoint - 0.5}H${outerTickLength}`, + LEFT: `M${width - outerTickLength},${startPoint + 0.5}H${width}V${endPoint - 0.5}H${width - outerTickLength}`, + }; + + const path = pathConfig[orient]; + + const textAlign = { + DOWN: [`translate(0, ${innerTickLength + 6})`, undefined, "hanging"], //transform, textAnchor, dominantBaseline + UP: [`translate(0, -6)`, undefined, undefined], + RIGHT: [`translate(${innerTickLength + 6}, 0)`, "start", "central"], + LEFT: [`translate(-6, 0)`, "end", "central"], + }; + + const [transform, textAnchor, dominantBaseline] = textAlign[orient]; + + const { root, axisLine, labelText } = BandAxisVariants(); return ( - - {!lineHide && } + + {axisScale.domain().map((label, i) => ( - {!lineHide && ( - - )} - {!labelHide && ( - - {label} - - )} + + + {label} + ))} - + ); }; diff --git a/src/components/charts/BandAxis/BandAxis.types.ts b/src/components/charts/BandAxis/BandAxis.types.ts index c0ca66b..aa76585 100644 --- a/src/components/charts/BandAxis/BandAxis.types.ts +++ b/src/components/charts/BandAxis/BandAxis.types.ts @@ -7,6 +7,8 @@ export type AxisOrient = "UP" | "DOWN" | "RIGHT" | "LEFT"; type BandAxisBaseProps = { axisScale: ScaleBand; + width: number; + height: number; outerTickLength?: number; innerTickLength?: number; orient?: AxisOrient; @@ -14,6 +16,6 @@ type BandAxisBaseProps = { lineHide?: boolean; }; -export type BandAxisProps = Omit, "textAnchor"> & +export type BandAxisProps = Omit, "width" | "height" | "textAnchor"> & VariantProps & BandAxisBaseProps; diff --git a/src/components/charts/BandAxis/__test__/BandAxis.test.tsx b/src/components/charts/BandAxis/__test__/BandAxis.test.tsx index d97011c..06d367f 100644 --- a/src/components/charts/BandAxis/__test__/BandAxis.test.tsx +++ b/src/components/charts/BandAxis/__test__/BandAxis.test.tsx @@ -21,60 +21,46 @@ describe("BandAxis", () => { }; it("에러 없이 렌더링", () => { - render(); + render(); }); it("data에 맞는 tick 개수", () => { - const { container } = render(); - const ticks = container.querySelectorAll("g > g"); + const { container } = render(); + const ticks = container.querySelectorAll("svg > g"); expect(ticks.length).toBe(4); }); - it("lineHide일 때 path, line 태그 없음", () => { - const { container } = render(); + it("lineHide일 때 path, line 태그 hidden", () => { + const { container } = render(); const path = container.querySelector("path"); const line = container.querySelector("line"); - expect(path).toBe(null); - expect(line).toBe(null); + expect(path).toHaveClass("hidden"); + expect(line).toHaveClass("hidden"); }); it("labelHide일 때 text 태그 없음", () => { - const { container } = render(); - const texts = container.querySelectorAll("text"); - expect(texts.length).toBe(0); - }); - - it("orient가 UP | DOWN 일 경우, transform 속성", () => { - const regex = /^translate\([\d.]+,\s*0\)$/; - ["UP", "DOWN"].forEach((orient) => { - const { container } = render(); - const tick = container.querySelector("g > g"); - expect(tick).toHaveAttribute("transform", expect.stringMatching(regex)); - }); + const { container } = render(); + const text = container.querySelector("text"); + expect(text).toHaveClass("hidden"); }); it("orient가 UP | DOWN 일 경우, line의 y2 존재 및 x2 속성 없음", () => { ["UP", "DOWN"].forEach((orient) => { - const { container } = render(); + const { container } = render( + , + ); const line = container.querySelector("line"); expect(line).toHaveAttribute("y2"); expect(line).not.toHaveAttribute("x2"); }); }); - it("orient가 LEFT | RIGHT 일 경우, transform 속성", () => { - const regex = /^translate\(0,\s*[\d.]+\)$/; - ["LEFT", "RIGHT"].forEach((orient) => { - const { container } = render(); - const tick = container.querySelector("g > g"); - expect(tick).toHaveAttribute("transform", expect.stringMatching(regex)); - }); - }); - it("orient가 LEFT | RIGHT 일 경우, line의 x2 존재 및 y2 속성 없음", () => { ["LEFT", "RIGHT"].forEach((orient) => { - const { container } = render(); + const { container } = render( + , + ); const line = container.querySelector("line"); expect(line).toHaveAttribute("x2"); expect(line).not.toHaveAttribute("y2"); diff --git a/src/utils/__test__/getAxisOrientConfig.test.ts b/src/utils/__test__/getAxisOrientConfig.test.ts deleted file mode 100644 index 4fdc527..0000000 --- a/src/utils/__test__/getAxisOrientConfig.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, test } from "vitest"; -import { getAxisOrientConfig } from "@utils/getAxisOrientConfig"; - -describe("getAxisOrientConfig", () => { - const startPoint = 0; - const endPoint = 100; - const outerTickLength = 10; - - test("returns correct config for UP orientation", () => { - const result = getAxisOrientConfig({ orient: "UP", startPoint, endPoint, outerTickLength }); - expect(result).toEqual([0, -6, "M0.5,0V10H99.5V0"]); - }); - - test("returns correct config for DOWN orientation", () => { - const result = getAxisOrientConfig({ orient: "DOWN", startPoint, endPoint, outerTickLength }); - expect(result).toEqual([0, 24, "M0.5,10V0H99.5V10"]); - }); - - test("returns correct config for LEFT orientation", () => { - const result = getAxisOrientConfig({ orient: "LEFT", startPoint, endPoint, outerTickLength }); - expect(result).toEqual([-24, 6, "M0,0.5H10V99.5H0"]); - }); - - test("returns correct config for RIGHT orientation", () => { - const result = getAxisOrientConfig({ orient: "RIGHT", startPoint, endPoint, outerTickLength }); - expect(result).toEqual([28, 6, "M10,0.5H0V99.5H10"]); - }); -}); diff --git a/src/utils/getAxisOrientConfig.ts b/src/utils/getAxisOrientConfig.ts deleted file mode 100644 index d299e79..0000000 --- a/src/utils/getAxisOrientConfig.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AxisOrient } from "@charts/BandAxis/BandAxis.types"; - -type getAxisOrientConfigParams = { - orient: AxisOrient; - startPoint: number; - endPoint: number; - outerTickLength: number; -}; - -export const getAxisOrientConfig = ({ orient, startPoint, endPoint, outerTickLength }: getAxisOrientConfigParams) => { - const pathConfig: { [key: string]: [number, number, string] } = { - UP: [0, -6, `M${startPoint + 0.5},0V${outerTickLength}H${endPoint - 0.5}V0`], - DOWN: [0, 24, `M${startPoint + 0.5},${outerTickLength}V0H${endPoint - 0.5}V${outerTickLength}`], - LEFT: [-24, 6, `M0,${startPoint + 0.5}H${outerTickLength}V${endPoint - 0.5}H0`], - RIGHT: [28, 6, `M${outerTickLength},${startPoint + 0.5}H0V${endPoint - 0.5}H${outerTickLength}`], - }; - - return pathConfig[orient]; -}; From 2f3d51c4dad0291eb3c993fb17f1aed7ec5325ab Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 09:54:07 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=92=84=20style(css):=20label?= =?UTF-8?q?=EC=9D=84=20height=20=EC=A4=91=EC=95=99=EC=97=90=20=EC=98=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20textAlign=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20tickAlign=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/charts/BandAxis/BandAxis.tsx | 37 +++++++++------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/components/charts/BandAxis/BandAxis.tsx b/src/components/charts/BandAxis/BandAxis.tsx index 5480797..ee19189 100644 --- a/src/components/charts/BandAxis/BandAxis.tsx +++ b/src/components/charts/BandAxis/BandAxis.tsx @@ -14,6 +14,8 @@ const BandAxis = ({ className, ...props }: BandAxisProps) => { + const { root, axisLine, labelText } = BandAxisVariants(); + const [startPoint, endPoint] = axisScale.range(); const tickCount = axisScale.domain().length; const isVertical = orient === "LEFT" || orient === "RIGHT"; @@ -29,46 +31,37 @@ const BandAxis = ({ LEFT: `M${width - outerTickLength},${startPoint + 0.5}H${width}V${endPoint - 0.5}H${width - outerTickLength}`, }; - const path = pathConfig[orient]; - - const textAlign = { - DOWN: [`translate(0, ${innerTickLength + 6})`, undefined, "hanging"], //transform, textAnchor, dominantBaseline - UP: [`translate(0, -6)`, undefined, undefined], - RIGHT: [`translate(${innerTickLength + 6}, 0)`, "start", "central"], - LEFT: [`translate(-6, 0)`, "end", "central"], + const tickAlign = { + DOWN: `translate(0, 0)`, + UP: `translate(0, ${height - innerTickLength})`, + RIGHT: `translate(0, 0)`, + LEFT: `translate(${width - innerTickLength}, 0)`, }; - const [transform, textAnchor, dominantBaseline] = textAlign[orient]; - - const { root, axisLine, labelText } = BandAxisVariants(); - return ( - + {axisScale.domain().map((label, i) => ( {label} From dc6cdd2679ac0cf13872ea5085a9620a5d42719d Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 09:54:41 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=93=9D=20docs(story):=20bandAxis=20?= =?UTF-8?q?Story=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/charts/BandAxis/BandAxis.stories.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/charts/BandAxis/BandAxis.stories.tsx b/src/components/charts/BandAxis/BandAxis.stories.tsx index 5cf62c9..21d6961 100644 --- a/src/components/charts/BandAxis/BandAxis.stories.tsx +++ b/src/components/charts/BandAxis/BandAxis.stories.tsx @@ -29,22 +29,22 @@ const xScale = scaleBand() .range([0, length]); export const Default: Story = { - render: () => , + render: () => , }; export const Orient: Story = { render: () => (
- - - - + + + +
), }; export const LabelHide: Story = { - render: () => , + render: () => , }; export const LineHide: Story = { From ff8c41a8e2862c118721ef62f0ddefd48d223258 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 10:02:22 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=9A=9A=20chore(component):=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/charts/BandAxis/BandAxis.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/charts/BandAxis/BandAxis.tsx b/src/components/charts/BandAxis/BandAxis.tsx index ee19189..0a97708 100644 --- a/src/components/charts/BandAxis/BandAxis.tsx +++ b/src/components/charts/BandAxis/BandAxis.tsx @@ -2,6 +2,8 @@ import { isEven } from "@utils/isEven"; import { BandAxisVariants } from "./BandAxis.styles"; import { BandAxisProps } from "./BandAxis.types"; +// TODO width, height가 없는 반응형 대응이 필요 +// TODO 조립형으로 하면 각 컴포넌트 별로 props 분리 및 label 회전, 포맷팅도 가능할 듯 -> 꼭 필요한가? 싶긴 함 const BandAxis = ({ width, height, From dcbdbadb997e246e5dcec75a53f16174306b9766 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 10:14:00 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=9A=9A=20chore(component):=20barCha?= =?UTF-8?q?rt=EC=97=90=EC=84=9C=20Axis=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?animate=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BarChart/BarChart.styles.ts | 1 - src/components/charts/BarChart/BarChart.tsx | 37 +++---------------- .../charts/BarChart/BarChart.types.ts | 1 - 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/src/components/charts/BarChart/BarChart.styles.ts b/src/components/charts/BarChart/BarChart.styles.ts index f4ffd33..3c84bd9 100644 --- a/src/components/charts/BarChart/BarChart.styles.ts +++ b/src/components/charts/BarChart/BarChart.styles.ts @@ -3,6 +3,5 @@ import { tv } from "@utils/customTV"; export const barChartVariants = tv({ slots: { bar: "stroke-secondary fill-secondary font-bold text-sm", - xAxis: "text-sm fill-surface-on-variant", }, }); diff --git a/src/components/charts/BarChart/BarChart.tsx b/src/components/charts/BarChart/BarChart.tsx index b79ba1c..8480d02 100644 --- a/src/components/charts/BarChart/BarChart.tsx +++ b/src/components/charts/BarChart/BarChart.tsx @@ -1,20 +1,8 @@ import { max, scaleBand, scaleLinear } from "d3"; -import BandAxis from "@charts/BandAxis"; import { barChartVariants } from "./BarChart.styles"; import type { BarChartProps, BarProps } from "./BarChart.types"; -//TODO useBar를 통한 속성 제어가 필요할지도? -//useBar가 있으면 nullBarHeight를 별도로 제공해줄 필요가 없을수도? -const Bar = ({ - xScale, - yScale, - data, - nullBarHeight = 0, - animationDuration = "0.3s", - rx, - labelPostfix = "", - ...props -}: BarProps) => { +const Bar = ({ xScale, yScale, data, nullBarHeight = 0, rx, labelPostfix = "", ...props }: BarProps) => { const rectWidth = xScale.bandwidth(); const rectHeight = yScale(0) - yScale(data.value || nullBarHeight); const rectX = xScale(data.label.toString())!; @@ -33,37 +21,25 @@ const Bar = ({ stroke={data.value === null ? "inherit" : undefined} strokeDasharray={data.value === null ? "6, 4" : undefined} fill={data.value === null ? "none" : undefined} - > - - - + /> {data.value ? `${data.value}${labelPostfix}` : "?"} - ); }; -// TODO useBar와 useAxis를 이용하면 줄일 수 있을 지도? +// TODO 방향 설정이 필요 const BarChart = ({ width, height, data, padding = 0.5 }: BarChartProps) => { - const margin = { x: 0, y: 32 }; - const xScale = scaleBand() .domain(data.map((d) => d.label.toString())) - .range([margin.x, width - margin.x]) + .range([0, width]) .padding(padding); const yScale = scaleLinear() .domain([0, max(data, (d) => (d.value ? d.value : 0))!]) .nice() - .range([height - margin.y, margin.y]); + .range([height, 0]); const nullBarHeight = data.reduce((acc, cur) => { @@ -71,7 +47,7 @@ const BarChart = ({ width, height, data, padding = 0.5 }: BarChartProps) => { return acc; }, 0) / data.length; - const { bar, xAxis } = barChartVariants(); + const { bar } = barChartVariants(); return ( @@ -89,7 +65,6 @@ const BarChart = ({ width, height, data, padding = 0.5 }: BarChartProps) => { /> ); })} - ); }; diff --git a/src/components/charts/BarChart/BarChart.types.ts b/src/components/charts/BarChart/BarChart.types.ts index 951f783..7b436b5 100644 --- a/src/components/charts/BarChart/BarChart.types.ts +++ b/src/components/charts/BarChart/BarChart.types.ts @@ -17,6 +17,5 @@ export type BarProps = PolymorphicPropsType<"g"> & yScale: ScaleLinear; data: BarChartDataType; nullBarHeight?: number; - animationDuration?: string; labelPostfix?: string; }; From 79c2eb9960b043723dd0320fb5ff1c4e0a637ed6 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 11:51:10 +0900 Subject: [PATCH 06/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(component):?= =?UTF-8?q?=20bar=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BarChart/BarChart.stories.tsx | 13 +++- .../charts/BarChart/BarChart.styles.ts | 11 ++- src/components/charts/BarChart/BarChart.tsx | 67 +++++++------------ .../charts/BarChart/BarChart.types.ts | 2 + 4 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/components/charts/BarChart/BarChart.stories.tsx b/src/components/charts/BarChart/BarChart.stories.tsx index d141c01..377a121 100644 --- a/src/components/charts/BarChart/BarChart.stories.tsx +++ b/src/components/charts/BarChart/BarChart.stories.tsx @@ -22,5 +22,16 @@ const data = [ ]; export const Default: Story = { - render: () => , + render: () => , +}; + +export const Orient: Story = { + render: () => ( +
+ + + + +
+ ), }; diff --git a/src/components/charts/BarChart/BarChart.styles.ts b/src/components/charts/BarChart/BarChart.styles.ts index 3c84bd9..c8b874b 100644 --- a/src/components/charts/BarChart/BarChart.styles.ts +++ b/src/components/charts/BarChart/BarChart.styles.ts @@ -1,7 +1,14 @@ import { tv } from "@utils/customTV"; export const barChartVariants = tv({ - slots: { - bar: "stroke-secondary fill-secondary font-bold text-sm", + base: "font-bold text-sm", + variants: { + value: { + true: "fill-secondary", + false: "stroke-secondary fill-none", + }, + }, + defaultVariants: { + value: true, }, }); diff --git a/src/components/charts/BarChart/BarChart.tsx b/src/components/charts/BarChart/BarChart.tsx index 8480d02..1fe9e6c 100644 --- a/src/components/charts/BarChart/BarChart.tsx +++ b/src/components/charts/BarChart/BarChart.tsx @@ -1,45 +1,23 @@ import { max, scaleBand, scaleLinear } from "d3"; import { barChartVariants } from "./BarChart.styles"; -import type { BarChartProps, BarProps } from "./BarChart.types"; +import type { BarChartProps } from "./BarChart.types"; -const Bar = ({ xScale, yScale, data, nullBarHeight = 0, rx, labelPostfix = "", ...props }: BarProps) => { - const rectWidth = xScale.bandwidth(); - const rectHeight = yScale(0) - yScale(data.value || nullBarHeight); - const rectX = xScale(data.label.toString())!; - const rectY = yScale(data.value || nullBarHeight); - - const labelOffset = 12; +// TODO 방향 설정이 필요 +const BarChart = ({ width, height, data, orient = "UP", padding = 0.5 }: BarChartProps) => { + const isVertical = orient === "UP" || orient === "DOWN"; - return ( - - - - {data.value ? `${data.value}${labelPostfix}` : "?"} - - - ); -}; + const labelRange = isVertical ? width : height; + const valueRange = isVertical ? height : width; -// TODO 방향 설정이 필요 -const BarChart = ({ width, height, data, padding = 0.5 }: BarChartProps) => { - const xScale = scaleBand() + const labelScale = scaleBand() .domain(data.map((d) => d.label.toString())) - .range([0, width]) + .range([0, labelRange]) .padding(padding); - const yScale = scaleLinear() + const valueScale = scaleLinear() .domain([0, max(data, (d) => (d.value ? d.value : 0))!]) .nice() - .range([height, 0]); + .range([0, valueRange]); const nullBarHeight = data.reduce((acc, cur) => { @@ -47,21 +25,26 @@ const BarChart = ({ width, height, data, padding = 0.5 }: BarChartProps) => { return acc; }, 0) / data.length; - const { bar } = barChartVariants(); - return ( {data.map((data, i) => { + const rectWidth = isVertical ? labelScale.bandwidth() : valueScale(data.value || nullBarHeight); + const rectHeight = isVertical ? valueScale(data.value || nullBarHeight) : labelScale.bandwidth(); + const rectX = isVertical ? labelScale(data.label.toString()) : orient === "LEFT" ? 0 : width - rectWidth; + const rectY = isVertical ? (orient === "UP" ? height - rectHeight : 0) : labelScale(data.label.toString()); + + console.log(data); + return ( - ); })} diff --git a/src/components/charts/BarChart/BarChart.types.ts b/src/components/charts/BarChart/BarChart.types.ts index 7b436b5..382f22b 100644 --- a/src/components/charts/BarChart/BarChart.types.ts +++ b/src/components/charts/BarChart/BarChart.types.ts @@ -1,10 +1,12 @@ import type { ScaleBand, ScaleLinear } from "d3"; import type { PropsWithChildren } from "react"; import type { PolymorphicPropsType } from "@customTypes/polymorphicType"; +import type { AxisOrient } from "@charts/BandAxis"; type BarChartDataType = { label: number; value: number | null }; export type BarChartProps = { + orient?: AxisOrient; width: number; height: number; data: BarChartDataType[]; From 9ad7f68f6a0eb640b1efe3c15ecf3ba65d4c3e16 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 11:55:36 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=92=84=20style(constant):=20orient?= =?UTF-8?q?=EB=A5=BC=20BarChart=EC=99=80=20=EB=8F=99=EC=9D=BC=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=86=8D=EC=84=B1=20css=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BandAxis/BandAxis.styles.ts | 4 ++-- src/components/charts/BandAxis/BandAxis.tsx | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/charts/BandAxis/BandAxis.styles.ts b/src/components/charts/BandAxis/BandAxis.styles.ts index ef090ef..6d2e7c2 100644 --- a/src/components/charts/BandAxis/BandAxis.styles.ts +++ b/src/components/charts/BandAxis/BandAxis.styles.ts @@ -3,8 +3,8 @@ import { tv } from "@utils/customTV"; export const BandAxisVariants = tv({ slots: { root: "stroke-surface-on", - axisLine: "", - labelText: "", + axisLine: "fill-none", + labelText: "stroke-none", }, variants: { lineHide: { diff --git a/src/components/charts/BandAxis/BandAxis.tsx b/src/components/charts/BandAxis/BandAxis.tsx index 0a97708..34f6aba 100644 --- a/src/components/charts/BandAxis/BandAxis.tsx +++ b/src/components/charts/BandAxis/BandAxis.tsx @@ -7,7 +7,7 @@ import { BandAxisProps } from "./BandAxis.types"; const BandAxis = ({ width, height, - orient = "DOWN", + orient = "UP", axisScale, outerTickLength = 6, innerTickLength = 6, @@ -27,22 +27,22 @@ const BandAxis = ({ axisScale.step() * (isEven(tickCount) ? tickCount / 2 - 0.5 : Math.floor(tickCount / 2)); const pathConfig: { [key: string]: string } = { - DOWN: `M${startPoint + 0.5},${outerTickLength}V0H${endPoint - 0.5}V${outerTickLength}`, - UP: `M${startPoint + 0.5},${height - outerTickLength}V${height}H${endPoint - 0.5}V${height - outerTickLength}`, + UP: `M${startPoint + 0.5},${outerTickLength}V0H${endPoint - 0.5}V${outerTickLength}`, + DOWN: `M${startPoint + 0.5},${height - outerTickLength}V${height}H${endPoint - 0.5}V${height - outerTickLength}`, RIGHT: `M${outerTickLength},${startPoint + 0.5}H0V${endPoint - 0.5}H${outerTickLength}`, LEFT: `M${width - outerTickLength},${startPoint + 0.5}H${width}V${endPoint - 0.5}H${width - outerTickLength}`, }; const tickAlign = { - DOWN: `translate(0, 0)`, - UP: `translate(0, ${height - innerTickLength})`, + UP: `translate(0, 0)`, + DOWN: `translate(0, ${height - innerTickLength})`, RIGHT: `translate(0, 0)`, LEFT: `translate(${width - innerTickLength}, 0)`, }; return ( - - + + {axisScale.domain().map((label, i) => ( Date: Mon, 27 May 2024 12:22:30 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=E2=9C=A8=20feat(component):=20label=20?= =?UTF-8?q?=EB=B0=8F=20showLabel=20props=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BarChart/BarChart.stories.tsx | 4 ++ .../charts/BarChart/BarChart.styles.ts | 13 +++-- src/components/charts/BarChart/BarChart.tsx | 47 ++++++++++++------- .../charts/BarChart/BarChart.types.ts | 1 + 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/components/charts/BarChart/BarChart.stories.tsx b/src/components/charts/BarChart/BarChart.stories.tsx index 377a121..246f49b 100644 --- a/src/components/charts/BarChart/BarChart.stories.tsx +++ b/src/components/charts/BarChart/BarChart.stories.tsx @@ -35,3 +35,7 @@ export const Orient: Story = { ), }; + +export const LabelHide: Story = { + render: () => , +}; diff --git a/src/components/charts/BarChart/BarChart.styles.ts b/src/components/charts/BarChart/BarChart.styles.ts index c8b874b..7e2029d 100644 --- a/src/components/charts/BarChart/BarChart.styles.ts +++ b/src/components/charts/BarChart/BarChart.styles.ts @@ -1,14 +1,21 @@ import { tv } from "@utils/customTV"; export const barChartVariants = tv({ - base: "font-bold text-sm", + slots: { + bar: "font-bold text-sm", + labelText: "", + }, variants: { value: { - true: "fill-secondary", - false: "stroke-secondary fill-none", + true: { bar: "fill-secondary" }, + false: { bar: "stroke-secondary fill-none" }, + }, + showLabel: { + false: { labelText: "hidden" }, }, }, defaultVariants: { value: true, + showLabel: false, }, }); diff --git a/src/components/charts/BarChart/BarChart.tsx b/src/components/charts/BarChart/BarChart.tsx index 1fe9e6c..bf018fd 100644 --- a/src/components/charts/BarChart/BarChart.tsx +++ b/src/components/charts/BarChart/BarChart.tsx @@ -2,12 +2,14 @@ import { max, scaleBand, scaleLinear } from "d3"; import { barChartVariants } from "./BarChart.styles"; import type { BarChartProps } from "./BarChart.types"; -// TODO 방향 설정이 필요 -const BarChart = ({ width, height, data, orient = "UP", padding = 0.5 }: BarChartProps) => { +// TODO label을 위한 gap 설정, label transform 커스텀 설정 필요 +const BarChart = ({ width, height, data, orient = "UP", padding = 0.5, showLabel }: BarChartProps) => { const isVertical = orient === "UP" || orient === "DOWN"; + const labelOffset = 0; + const labelRange = isVertical ? width : height; - const valueRange = isVertical ? height : width; + const valueRange = isVertical ? height - labelOffset : width - labelOffset; const labelScale = scaleBand() .domain(data.map((d) => d.label.toString())) @@ -25,27 +27,40 @@ const BarChart = ({ width, height, data, orient = "UP", padding = 0.5 }: BarChar return acc; }, 0) / data.length; + const { bar, labelText } = barChartVariants(); + return ( {data.map((data, i) => { const rectWidth = isVertical ? labelScale.bandwidth() : valueScale(data.value || nullBarHeight); const rectHeight = isVertical ? valueScale(data.value || nullBarHeight) : labelScale.bandwidth(); - const rectX = isVertical ? labelScale(data.label.toString()) : orient === "LEFT" ? 0 : width - rectWidth; - const rectY = isVertical ? (orient === "UP" ? height - rectHeight : 0) : labelScale(data.label.toString()); + const rectX = isVertical ? labelScale(data.label.toString())! : orient === "LEFT" ? 0 : width - rectWidth; + const rectY = isVertical ? (orient === "UP" ? height - rectHeight : 0) : labelScale(data.label.toString())!; + + const labelAlign = { + UP: [rectX + rectWidth / 2, rectY - 24], + DOWN: [rectX + rectWidth / 2, rectHeight + 24], + LEFT: [rectWidth + 28, rectY + rectHeight / 2], + RIGHT: [rectX - 28, rectY + rectHeight / 2], + }; - console.log(data); + const [labelX, labelY] = labelAlign[orient]; return ( - + + + + {data.value ? `${data.value}` : "?"} + + ); })} diff --git a/src/components/charts/BarChart/BarChart.types.ts b/src/components/charts/BarChart/BarChart.types.ts index 382f22b..af473bd 100644 --- a/src/components/charts/BarChart/BarChart.types.ts +++ b/src/components/charts/BarChart/BarChart.types.ts @@ -11,6 +11,7 @@ export type BarChartProps = { height: number; data: BarChartDataType[]; padding?: number; + showLabel?: boolean; }; export type BarProps = PolymorphicPropsType<"g"> & From 98482a864be450a178ec6fa656646f67e6df1426 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 13:21:43 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=92=84=20style(css):=20labelOffset?= =?UTF-8?q?=20=EB=B0=8F=20style=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../charts/BarChart/BarChart.stories.tsx | 4 ++-- .../charts/BarChart/BarChart.styles.ts | 2 +- src/components/charts/BarChart/BarChart.tsx | 20 +++++++++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/components/charts/BarChart/BarChart.stories.tsx b/src/components/charts/BarChart/BarChart.stories.tsx index 246f49b..8a086c3 100644 --- a/src/components/charts/BarChart/BarChart.stories.tsx +++ b/src/components/charts/BarChart/BarChart.stories.tsx @@ -36,6 +36,6 @@ export const Orient: Story = { ), }; -export const LabelHide: Story = { - render: () => , +export const ShowLabel: Story = { + render: () => , }; diff --git a/src/components/charts/BarChart/BarChart.styles.ts b/src/components/charts/BarChart/BarChart.styles.ts index 7e2029d..b3986c7 100644 --- a/src/components/charts/BarChart/BarChart.styles.ts +++ b/src/components/charts/BarChart/BarChart.styles.ts @@ -2,7 +2,7 @@ import { tv } from "@utils/customTV"; export const barChartVariants = tv({ slots: { - bar: "font-bold text-sm", + bar: "", labelText: "", }, variants: { diff --git a/src/components/charts/BarChart/BarChart.tsx b/src/components/charts/BarChart/BarChart.tsx index bf018fd..d651039 100644 --- a/src/components/charts/BarChart/BarChart.tsx +++ b/src/components/charts/BarChart/BarChart.tsx @@ -2,12 +2,20 @@ import { max, scaleBand, scaleLinear } from "d3"; import { barChartVariants } from "./BarChart.styles"; import type { BarChartProps } from "./BarChart.types"; -// TODO label을 위한 gap 설정, label transform 커스텀 설정 필요 -const BarChart = ({ width, height, data, orient = "UP", padding = 0.5, showLabel }: BarChartProps) => { +// TODO 반응형 대응 +// TODO 애니메이션 설정 +// TODO label을 잘리지 않게 하기 위한 labelOffset 설정, label transform, formatting 등 커스텀 설정 필요 +const BarChart = ({ + width, + height, + data, + orient = "UP", + padding = 0.5, + showLabel, + labelOffset = 24, +}: BarChartProps) => { const isVertical = orient === "UP" || orient === "DOWN"; - const labelOffset = 0; - const labelRange = isVertical ? width : height; const valueRange = isVertical ? height - labelOffset : width - labelOffset; @@ -38,8 +46,8 @@ const BarChart = ({ width, height, data, orient = "UP", padding = 0.5, showLabel const rectY = isVertical ? (orient === "UP" ? height - rectHeight : 0) : labelScale(data.label.toString())!; const labelAlign = { - UP: [rectX + rectWidth / 2, rectY - 24], - DOWN: [rectX + rectWidth / 2, rectHeight + 24], + UP: [rectX + rectWidth / 2, rectY - 16], + DOWN: [rectX + rectWidth / 2, rectHeight + 16], LEFT: [rectWidth + 28, rectY + rectHeight / 2], RIGHT: [rectX - 28, rectY + rectHeight / 2], }; From f9f7fb152599049d7c08cfef0915f95604945896 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 13:22:08 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=9A=9A=20chore(type):=20barProps=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/charts/BarChart/BarChart.types.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/components/charts/BarChart/BarChart.types.ts b/src/components/charts/BarChart/BarChart.types.ts index af473bd..dfa163c 100644 --- a/src/components/charts/BarChart/BarChart.types.ts +++ b/src/components/charts/BarChart/BarChart.types.ts @@ -1,6 +1,3 @@ -import type { ScaleBand, ScaleLinear } from "d3"; -import type { PropsWithChildren } from "react"; -import type { PolymorphicPropsType } from "@customTypes/polymorphicType"; import type { AxisOrient } from "@charts/BandAxis"; type BarChartDataType = { label: number; value: number | null }; @@ -12,13 +9,5 @@ export type BarChartProps = { data: BarChartDataType[]; padding?: number; showLabel?: boolean; + labelOffset?: number; }; - -export type BarProps = PolymorphicPropsType<"g"> & - PropsWithChildren & { - xScale: ScaleBand; - yScale: ScaleLinear; - data: BarChartDataType; - nullBarHeight?: number; - labelPostfix?: string; - }; From 5bf7134f5b164f205e5cf5f1829debb30504bed0 Mon Sep 17 00:00:00 2001 From: bh2980 Date: Mon, 27 May 2024 13:24:54 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=93=9D=20docs(story):=20padding=20S?= =?UTF-8?q?tory=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/charts/BarChart/BarChart.stories.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/charts/BarChart/BarChart.stories.tsx b/src/components/charts/BarChart/BarChart.stories.tsx index 8a086c3..e3abd07 100644 --- a/src/components/charts/BarChart/BarChart.stories.tsx +++ b/src/components/charts/BarChart/BarChart.stories.tsx @@ -39,3 +39,13 @@ export const Orient: Story = { export const ShowLabel: Story = { render: () => , }; + +export const Padding: Story = { + render: () => ( +
+ + + +
+ ), +};