@coinmeca/ui
Version:
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
217 lines • 9.54 kB
JSX
"use client";
import { useTheme } from "../../../hooks";
import { sort } from "../../../lib/utils";
import { createChart } from "lightweight-charts";
import { Suspense, memo, useEffect, useRef, useState } from "react";
import Style from "./Chart.styled";
import { Root } from "../../../lib/style";
export const Line = (props) => {
const up = props?.up || "up";
const down = props?.down || "down";
const { theme: detectedTheme } = useTheme();
const theme = props?.color?.theme
? props?.color?.theme === "light"
? "0,0,0"
: "255,255,255"
: detectedTheme === "light"
? "0,0,0"
: "255,255,255";
const getColor = (color, fallback) => {
if (!color || color === "")
return fallback;
// if (color?.includes(",")) {
// const length = color.split(",")?.length;
// return length === 3 ? `rgb(${color})` : `rgba(${color})`;
// }
return color !== Root.Color(color) ? Root.Color(color) : color;
};
const color = {
default: getColor(props?.color?.default, theme),
up: getColor(props?.color?.up, "0,192,96"),
down: getColor(props?.color?.down, "255,0,64"),
theme: {
strong: `rgba(${theme}, 0.6)`,
semi: `rgba(${theme}, 0.45)`,
medium: `rgba(${theme}, 0.3)`,
regular: `rgba(${theme}, 0.15)`,
light: `rgba(${theme}, 0.05)`,
},
};
const key = {
time: props?.field?.time || "time",
value: props?.field?.value || "value",
volume: props?.field?.volume || "volume",
};
const [data, setData] = useState([]);
const [volume, setVolume] = useState([]);
const chartRef = useRef(null);
useEffect(() => {
const handleResize = () => {
createChart(chartRef?.current).applyOptions({
width: chartRef?.current?.clientWidth,
height: chartRef?.current?.clientHeight,
});
};
chartRef?.current?.addEventListener("resize", handleResize);
return () => chartRef?.current?.removeEventListener("resize", handleResize);
}, []);
useEffect(() => {
if (props?.data && props?.data?.length > 0)
setData(sort(props?.data?.map((v) => {
return {
time: v?.time,
value: parseFloat(v[key.value]?.toString() || "0"),
};
}), key.time, props?.data && props?.data?.length > 0 && typeof (props?.data[0])[key.time] === "number"
? "number"
: "string", true));
}, [props?.data]);
useEffect(() => {
if (props?.volume && props?.volume?.length > 0)
setVolume(sort(props?.volume?.map((v) => {
return {
time: v?.time,
value: parseFloat(v[key.volume]?.toString() || "0"),
color: v?.type === up && color.up
? `rgba(${color.up}, 0.3)`
: color.down
? `rgba(${color.down}, 0.3)`
: `rgba(${color.default}, 0.3)`,
// color: v.type === up ? `rgb(${Root.Color(color.up)})` : `rgb(${Root.Color(color.down)})`,
};
}), key.time, props?.volume && props?.volume?.length > 0 && typeof (props?.volume[0])[key.time] === "number"
? "number"
: "string", true));
}, [props?.volume, up, down, color]);
useEffect(() => {
// const chart = createChart(document.getElementById('container'), );
if (chartRef?.current) {
const handleResize = () => {
chart.applyOptions({
width: chartRef?.current?.clientWidth,
height: chartRef?.current?.clientHeight,
});
};
const chart = createChart(chartRef?.current, {
layout: {
background: {
color: "transparent",
},
fontSize: 10,
fontFamily: "'Montserrat', 'Noto Sans KR', sans-serif",
textColor: color.theme.strong,
},
grid: {
vertLines: { color: color.theme.light },
horzLines: { color: color.theme.light },
},
rightPriceScale: {
borderVisible: true,
borderColor: color.theme.regular,
},
timeScale: {
borderColor: color.theme.regular,
},
trackingMode: {},
crosshair: {
// Change mode from default 'magnet' to 'normal'.
// Allows the crosshair to move freely without snapping to datapoints
mode: 0,
// Vertical crosshair line (showing Date in Label)
vertLine: {
width: 4,
color: color.theme.regular,
// style: LightweightCharts.LineStyle.Solid,
style: 0,
labelBackgroundColor: color.theme.medium,
},
// Horizontal crosshair line (showing Price in Label)
horzLine: {
color: color.theme.semi,
labelBackgroundColor: color.theme.medium,
},
},
width: chartRef?.current?.clientWidth,
height: chartRef?.current?.clientHeight,
});
if (data) {
const series = chart.addLineSeries({
color: `rgb(${color.default})`,
priceFormat: {
type: (typeof props?.type === "string"
? props?.type
: typeof props?.type === "object" &&
typeof props?.type?.line === "string" &&
props?.type?.line) || "volume",
},
// set as an overlay by setting a blank priceScaleId
// priceScaleId: "",
// set the positioning of the volume series
});
series.priceScale().applyOptions({
scaleMargins: {
// positioning the price scale for the area series
top: 0.1,
bottom: volume ? 0.4 : 0,
},
});
series.setData(data);
if ((typeof props?.unit === "string" && props?.unit !== "") ||
(typeof props?.unit === "object" && props?.unit?.line))
series.applyOptions({
priceFormat: {
type: "custom",
formatter: (price) => (typeof props?.format === "function"
? props?.format(price)
: typeof props?.format === "object" && typeof props?.format?.line === "function"
? props?.format?.line(price)
: price).toString() + props?.unit,
},
});
}
if (volume) {
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: (typeof props?.type === "string"
? props?.type
: typeof props?.type === "object" &&
typeof props?.type?.histogram === "string" &&
props?.type?.histogram) || "volume",
},
// set as an overlay by setting a blank priceScaleId
// priceScaleId: "",
// set the positioning of the volume series
});
// volumeSeries.priceScale().applyOptions({
// scaleMargins: {
// top: 0.8, // highest point of the series will be 70% away from the top
// bottom: 0,
// },
// });
volumeSeries.setData(volume);
if (typeof props?.unit === "object" && props?.unit?.histogram)
volumeSeries.applyOptions({
priceFormat: {
type: "custom",
formatter: (price) => (typeof props?.format === "object" && typeof props?.format?.histogram === "function"
? props?.format?.histogram(price)
: price).toString() + props?.unit,
},
});
}
props?.fit
? chart.timeScale().fitContent()
: chart.timeScale().applyOptions({
barSpacing: 10,
});
return () => {
chart.remove();
};
}
}, [chartRef, data, color, up, down, props?.fit]);
return (<Suspense fallback={props?.fallback || <div>Loading...</div>}>
<Style ref={chartRef} style={props?.style}/>
</Suspense>);
};
export default memo(Line);
//# sourceMappingURL=Line.jsx.map