Merge commit 'ffb15a7e3a64f6b798e58fbcbc6bd10e4b6481bf' into iipbs/wr/dev
This commit is contained in:
@@ -12,25 +12,31 @@ import {
|
||||
} from "./lib/chart";
|
||||
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
|
||||
|
||||
export default function Chart(props: { chartStyle: CSSProperties | undefined; chartConfig: ChartConfig; chartData: any[] | undefined; }) {
|
||||
export default function Chart(props: { chartConfig: ChartConfig; chartData: any[] | undefined; chartTitle: string}) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ChartContainer style={props.chartStyle} config={props.chartConfig}>
|
||||
<BarChart accessibilityLayer data={props.chartData}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
<Card className="h-full">
|
||||
<CardContent className="h-full">
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>): null}
|
||||
<div className="h-[calc(100%-42px)] flex justify-center">
|
||||
<ChartContainer config={props.chartConfig} className="h-full w-full">
|
||||
<BarChart accessibilityLayer data={props.chartData} className="h-full">
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="dashed" />}/>
|
||||
<Bar dataKey="val" radius={10} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
/>
|
||||
<ChartTooltip cursor={false} content={<ChartTooltipContent indicator="dashed" />}/>
|
||||
<Bar dataKey="val" radius={10} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -12,31 +12,35 @@ import {
|
||||
ChartTooltipContent,
|
||||
type ChartConfig
|
||||
} from "./lib/chart";
|
||||
import type { CSSProperties } from "react";
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export default (props: { chartConfig: ChartConfig; chartStyle: CSSProperties | undefined; chartData: never[] | undefined; }) =>{
|
||||
export default (props: { chartConfig: ChartConfig; chartData: never[] | undefined; chartTitle:string}) =>{
|
||||
return (
|
||||
<Card className="flex flex-col">
|
||||
<CardContent className="flex-1 pb-0">
|
||||
<ChartContainer
|
||||
config={props.chartConfig}
|
||||
className="mx-auto aspect-square max-h-[300px]"
|
||||
style={props.chartStyle}
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={props.chartData}
|
||||
dataKey="val"
|
||||
nameKey="label"
|
||||
innerRadius={60}
|
||||
/>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>): null}
|
||||
<div className="h-[calc(100%-42px)] justify-center">
|
||||
<ChartContainer
|
||||
config={props.chartConfig}
|
||||
className="mx-auto aspect-square max-h-[300px]"
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={props.chartData}
|
||||
dataKey="val"
|
||||
nameKey="label"
|
||||
innerRadius={60}
|
||||
/>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
"use client"
|
||||
import type { CSSProperties } from "react";
|
||||
import { Bar, CartesianGrid, ComposedChart, Legend, Line, Tooltip, XAxis, YAxis } from "recharts";
|
||||
import {
|
||||
Card,
|
||||
CardContent
|
||||
} from "./lib/card";
|
||||
import {
|
||||
ChartContainer,
|
||||
type ChartConfig
|
||||
} from "./lib/chart";
|
||||
import React from "react";
|
||||
|
||||
// 툴팁 커스텀 css
|
||||
/** 차트 기본 스타일 */
|
||||
const styles = {
|
||||
tooltipDiv: {
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "white",
|
||||
padding: "10px",
|
||||
boxShadow: "0px 2px 10px rgba(0,0,0,0.2)",
|
||||
width: "180px", // 적절한 크기로 설정
|
||||
} as React.CSSProperties,
|
||||
tooltipLabel: {
|
||||
fontWeight: "bold",
|
||||
fontSize: "12px",
|
||||
marginBottom: "5px",
|
||||
borderBottom: "1px solid #ddd",
|
||||
paddingBottom: "3px",
|
||||
} as React.CSSProperties,
|
||||
tooltipText: {
|
||||
fontSize: "11px",
|
||||
fontWeight:"bold",
|
||||
} as React.CSSProperties,
|
||||
legendContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: "20px",
|
||||
fontSize: "9px",
|
||||
fontWeight : "bold",
|
||||
marginTop: "10px",
|
||||
} as CSSProperties,
|
||||
};
|
||||
|
||||
// 커스텀 툴팁
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
if (active && payload && payload.length) {
|
||||
return (
|
||||
<div style={styles.tooltipDiv}>
|
||||
<p style={styles.tooltipLabel}>{label}</p>
|
||||
{payload.map((item, index) => (
|
||||
<div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
{/* 색상 박스 추가 (범례 색상과 동일) */}
|
||||
<div style={{ width: "10px", height: "10px", backgroundColor: item.color, borderRadius: "50%" }}></div>
|
||||
<span style={styles.tooltipText}>{`${item.name}: ${item.value}`}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
|
||||
const CustomLegend = (props: any) => {
|
||||
const { payload } = props;
|
||||
return (
|
||||
<div style={styles.legendContainer}>
|
||||
{payload.map((entry, index) => (
|
||||
<div key={`legend-${index}`} style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<div style={{ width: "12px", height: "12px", backgroundColor: entry.color, borderRadius: "50%" }}></div>
|
||||
<span>{entry.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function LineBarchart(props: { chartConfig: ChartConfig; chartData: any[] | undefined; chartTitle:string }) {
|
||||
return (
|
||||
<Card className="h-full">
|
||||
<CardContent className="h-full">
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>): null}
|
||||
<div className="h-[calc(100%-42px)] flex justify-center">
|
||||
<ChartContainer config={props.chartConfig} className="h-full w-full" >
|
||||
<ComposedChart data={props.chartData} className="h-full ">
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold"/>
|
||||
{/* 왼쪽 Y축: lineVal (정상) */}
|
||||
<YAxis yAxisId="left" orientation="left" />
|
||||
{/* 오른쪽 Y축: barVal (위에서 아래로 반전) */}
|
||||
<YAxis yAxisId="right" orientation="right" reversed />
|
||||
<Tooltip content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />} />
|
||||
<Legend content={CustomLegend}/>
|
||||
{/* 바 차트 (오른쪽 Y축 사용, 위에서 아래로) */}
|
||||
<Bar yAxisId="right" dataKey="barVal" fill="#8884d8" name="강수량(mm/일)"/>
|
||||
{/* 라인 차트 (왼쪽 Y축 사용) */}
|
||||
<Line yAxisId="left" type="monotone" dataKey="lineVal" stroke="orange" strokeWidth={2} dot={{r: 0}} name="BOD(mg/L)"/>
|
||||
</ComposedChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -10,41 +10,92 @@ import {
|
||||
ChartTooltipContent,
|
||||
type ChartConfig
|
||||
} from "./lib/chart";
|
||||
import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
|
||||
import { CartesianGrid, Legend, Line, LineChart, Tooltip, XAxis, YAxis } from "recharts";
|
||||
|
||||
export default function Linechart(props: { chartStyle: CSSProperties | undefined; chartConfig: ChartConfig; chartData: any[] | undefined; }) {
|
||||
/** 차트 기본 스타일 */
|
||||
const styles = {
|
||||
tooltipDiv: {
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "white",
|
||||
padding: "10px",
|
||||
boxShadow: "0px 2px 10px rgba(0,0,0,0.2)",
|
||||
width: "180px", // 적절한 크기로 설정
|
||||
} as React.CSSProperties,
|
||||
tooltipLabel: {
|
||||
fontWeight: "bold",
|
||||
fontSize: "12px",
|
||||
marginBottom: "5px",
|
||||
borderBottom: "1px solid #ddd",
|
||||
paddingBottom: "3px",
|
||||
} as React.CSSProperties,
|
||||
tooltipText: {
|
||||
fontSize: "11px",
|
||||
fontWeight:"bold",
|
||||
} as React.CSSProperties,
|
||||
legendContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: "20px",
|
||||
fontSize: "9px",
|
||||
fontWeight : "bold",
|
||||
marginTop: "10px",
|
||||
} as CSSProperties,
|
||||
};
|
||||
|
||||
// 커스텀 툴팁
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
if (active && payload && payload.length) {
|
||||
return (
|
||||
<div style={styles.tooltipDiv}>
|
||||
<p style={styles.tooltipLabel}>{label}</p>
|
||||
{payload.map((item, index) => (
|
||||
<div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
{/* 색상 박스 추가 (범례 색상과 동일) */}
|
||||
<div style={{ width: "10px", height: "10px", backgroundColor: item.color, borderRadius: "50%" }}></div>
|
||||
<span style={styles.tooltipText}>{`${item.name}: ${item.value}`}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
|
||||
const CustomLegend = (props: any) => {
|
||||
const { payload } = props;
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ChartContainer style={props.chartStyle} config={props.chartConfig}>
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
data={props.chartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Line
|
||||
dataKey="val"
|
||||
type="linear"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
<div style={styles.legendContainer}>
|
||||
{payload.map((entry, index) => (
|
||||
<div key={`legend-${index}`} style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<div style={{ width: "12px", height: "12px", backgroundColor: entry.color, borderRadius: "50%" }}></div>
|
||||
<span>{entry.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Linechart(props: { chartConfig: ChartConfig; chartData: any[] | undefined; chartTitle:string}) {
|
||||
return (
|
||||
<Card className="h-full">
|
||||
<CardContent className="h-full">
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>): null}
|
||||
<div className="h-[calc(100%-42px)] flex justify-center">
|
||||
<ChartContainer config={props.chartConfig} className="h-full w-full">
|
||||
<LineChart data={props.chartData} className="h-full">
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold"/>
|
||||
<YAxis yAxisId="left" orientation="left" />
|
||||
<Tooltip content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />} />
|
||||
<Legend content={CustomLegend}/>
|
||||
<Line yAxisId="left" dataKey="val" type="linear" strokeWidth={2} dot={false} name="값"/>
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
|
||||
import React from 'react'
|
||||
import React from 'react';
|
||||
import BarChart from './BarChart';
|
||||
import LineChart from './LineChart';
|
||||
import DoughnutChart from './DoughnutChart';
|
||||
import {type ChartConfig } from './lib/chart';
|
||||
|
||||
/** 차트 기본 스타일 */
|
||||
const styles = {
|
||||
divHeight : {
|
||||
height: '400px',
|
||||
width : '500px'
|
||||
} as React.CSSProperties
|
||||
}
|
||||
import { type ChartConfig } from './lib/chart';
|
||||
import LineChart from './LineChart';
|
||||
import LineBarchart from './LineBarChart';
|
||||
|
||||
/**차트 FORM */
|
||||
const CHART_FORM = {
|
||||
@@ -20,35 +13,36 @@ const CHART_FORM = {
|
||||
/**라인 차트 형태*/
|
||||
LINE:'line',
|
||||
/**도넛 차트 형태*/
|
||||
DN :'daughnut'
|
||||
DN :'daughnut',
|
||||
/**LINE,BAR차트 */
|
||||
LINEBAR : 'linebar'
|
||||
};
|
||||
|
||||
function MainChart(props: { chartForm: string; chartConfig: any; chartData: any; }) {
|
||||
function MainChart(props: { chartForm: string; chartConfig: any; chartData: any; chartTitle:string; }) {
|
||||
if( props.chartForm == CHART_FORM.BAR ){
|
||||
return (
|
||||
<div>
|
||||
<BarChart chartConfig={props.chartConfig} chartStyle={styles.divHeight} chartData={props.chartData}>
|
||||
</BarChart>
|
||||
</div>
|
||||
<BarChart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle}>
|
||||
</BarChart>
|
||||
);
|
||||
} else if( props.chartForm == CHART_FORM.LINE ){
|
||||
return (
|
||||
<div>
|
||||
<LineChart chartConfig={props.chartConfig} chartStyle={styles.divHeight} chartData={props.chartData}>
|
||||
</LineChart>
|
||||
</div>
|
||||
<LineChart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle}>
|
||||
</LineChart>
|
||||
);
|
||||
} else if( props.chartForm == CHART_FORM.DN ){
|
||||
return (
|
||||
<div>
|
||||
<DoughnutChart chartConfig={props.chartConfig} chartStyle={styles.divHeight} chartData={props.chartData}>
|
||||
</DoughnutChart>
|
||||
</div>
|
||||
<DoughnutChart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle}>
|
||||
</DoughnutChart>
|
||||
);
|
||||
} else if (props.chartForm == CHART_FORM.LINEBAR){
|
||||
return (
|
||||
<LineBarchart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle}>
|
||||
</LineBarchart>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {MainChart};
|
||||
export { MainChart };
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export {CHART_FORM};
|
||||
export type {ChartConfig};
|
||||
export { CHART_FORM };
|
||||
export type { ChartConfig };
|
||||
|
||||
@@ -10,26 +10,28 @@ import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from "@comm
|
||||
import { cn } from "../../lib/utils";
|
||||
import { FormControl } from "../form";
|
||||
|
||||
type DatePickerProps = DayPickerSingleProps & { field: { value: Date; onChange: (date: Date | undefined) => void } };
|
||||
type DatePickerProps = DayPickerSingleProps & { field: { value: Date; onChange: (date: Date | undefined) => void } ,selectClass:string|undefined };
|
||||
|
||||
export function DatePicker({ field }: DatePickerProps) {
|
||||
export function DatePicker({ field, selectClass }: DatePickerProps) {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
color="white"
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
className={!selectClass? cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field?.value && "text-muted-foreground"
|
||||
)}
|
||||
!field?.value && "text-muted-foreground",
|
||||
|
||||
):selectClass}
|
||||
>
|
||||
{field?.value ? (
|
||||
format(field?.value, "PPP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
<CalendarIcon className="h-4" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
|
||||
Reference in New Issue
Block a user