@adrienhobbs/candlekit 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +66 -10
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -327,6 +327,8 @@ function ChartComponent({
|
|
|
327
327
|
const mouseDownPosRef = useRef(null);
|
|
328
328
|
const heightRef = useRef(height);
|
|
329
329
|
heightRef.current = height;
|
|
330
|
+
const lineEditEnabledRef = useRef(false);
|
|
331
|
+
lineEditEnabledRef.current = Boolean(onAddLine || onClearAllLines);
|
|
330
332
|
useEffect(() => {
|
|
331
333
|
if (!chartContainerRef.current) return;
|
|
332
334
|
chartContainerRef.current.style.position = "relative";
|
|
@@ -344,6 +346,12 @@ function ChartComponent({
|
|
|
344
346
|
vertLines: { color: "#1e293b" },
|
|
345
347
|
horzLines: { color: "#1e293b" }
|
|
346
348
|
},
|
|
349
|
+
// Render axis ticks + crosshair in the viewer's LOCAL timezone (lightweight-
|
|
350
|
+
// charts otherwise renders numeric times as UTC, which mismatches any
|
|
351
|
+
// local-time table/labels alongside the chart).
|
|
352
|
+
localization: {
|
|
353
|
+
timeFormatter: localCrosshairTimeFormatter
|
|
354
|
+
},
|
|
347
355
|
width: chartContainerRef.current.clientWidth,
|
|
348
356
|
// Auto-fill the container's height unless an explicit `height` is given.
|
|
349
357
|
// Fall back to 600 only when the container hasn't been laid out yet (a
|
|
@@ -352,7 +360,8 @@ function ChartComponent({
|
|
|
352
360
|
timeScale: {
|
|
353
361
|
timeVisible: true,
|
|
354
362
|
secondsVisible: true,
|
|
355
|
-
borderColor: "#334155"
|
|
363
|
+
borderColor: "#334155",
|
|
364
|
+
tickMarkFormatter: localTickMarkFormatter
|
|
356
365
|
},
|
|
357
366
|
rightPriceScale: {
|
|
358
367
|
borderColor: "#334155"
|
|
@@ -416,6 +425,7 @@ function ChartComponent({
|
|
|
416
425
|
const resizeObserver = new ResizeObserver(handleResize);
|
|
417
426
|
resizeObserver.observe(chartContainerRef.current);
|
|
418
427
|
const handleContextMenu = (e) => {
|
|
428
|
+
if (!lineEditEnabledRef.current) return;
|
|
419
429
|
e.preventDefault();
|
|
420
430
|
e.stopPropagation();
|
|
421
431
|
if (!candlestickSeriesRef.current) {
|
|
@@ -527,16 +537,37 @@ function ChartComponent({
|
|
|
527
537
|
if (!chartRef.current || !focusTradeId) return;
|
|
528
538
|
const trade = trades.find((t) => t.id === focusTradeId);
|
|
529
539
|
if (!trade) return;
|
|
530
|
-
const
|
|
531
|
-
const
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
540
|
+
const seen = /* @__PURE__ */ new Set();
|
|
541
|
+
const series = [];
|
|
542
|
+
for (const b of [...bars].sort((a, b2) => a.timestamp - b2.timestamp)) {
|
|
543
|
+
if (seen.has(b.timestamp)) continue;
|
|
544
|
+
seen.add(b.timestamp);
|
|
545
|
+
series.push(b.timestamp);
|
|
546
|
+
}
|
|
547
|
+
if (series.length === 0) return;
|
|
548
|
+
const nearestIdx = (ms) => {
|
|
549
|
+
let lo = 0;
|
|
550
|
+
let hi = series.length - 1;
|
|
551
|
+
let idx = series.length - 1;
|
|
552
|
+
while (lo <= hi) {
|
|
553
|
+
const mid = lo + hi >> 1;
|
|
554
|
+
if (series[mid] >= ms) {
|
|
555
|
+
idx = mid;
|
|
556
|
+
hi = mid - 1;
|
|
557
|
+
} else {
|
|
558
|
+
lo = mid + 1;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return idx;
|
|
562
|
+
};
|
|
563
|
+
const entryIdx = nearestIdx(trade.entryTime);
|
|
564
|
+
const exitIdx = Math.max(entryIdx, nearestIdx(trade.exitTime));
|
|
565
|
+
const PAD = 15;
|
|
535
566
|
const raf = requestAnimationFrame(() => {
|
|
536
567
|
try {
|
|
537
|
-
chartRef.current?.timeScale().
|
|
538
|
-
from:
|
|
539
|
-
to:
|
|
568
|
+
chartRef.current?.timeScale().setVisibleLogicalRange({
|
|
569
|
+
from: entryIdx - PAD,
|
|
570
|
+
to: exitIdx + PAD
|
|
540
571
|
});
|
|
541
572
|
} catch {
|
|
542
573
|
}
|
|
@@ -878,7 +909,7 @@ function ChartComponent({
|
|
|
878
909
|
}
|
|
879
910
|
)
|
|
880
911
|
] }),
|
|
881
|
-
chartContainerRef.current && lines.map((line) => {
|
|
912
|
+
onDeleteLine && chartContainerRef.current && lines.map((line) => {
|
|
882
913
|
const pos = linePositions.get(line.id);
|
|
883
914
|
if (!pos) return null;
|
|
884
915
|
return createPortal(
|
|
@@ -983,6 +1014,31 @@ function getLineStyle(style) {
|
|
|
983
1014
|
return LineStyle.Solid;
|
|
984
1015
|
}
|
|
985
1016
|
}
|
|
1017
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1018
|
+
function localTickMarkFormatter(time, tickMarkType) {
|
|
1019
|
+
const d = new Date(time * 1e3);
|
|
1020
|
+
switch (tickMarkType) {
|
|
1021
|
+
case 0:
|
|
1022
|
+
return String(d.getFullYear());
|
|
1023
|
+
case 1:
|
|
1024
|
+
return d.toLocaleString(void 0, { month: "short" });
|
|
1025
|
+
case 2:
|
|
1026
|
+
return d.toLocaleString(void 0, { month: "short", day: "numeric" });
|
|
1027
|
+
case 4:
|
|
1028
|
+
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`;
|
|
1029
|
+
default:
|
|
1030
|
+
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
function localCrosshairTimeFormatter(time) {
|
|
1034
|
+
return new Date(time * 1e3).toLocaleString(void 0, {
|
|
1035
|
+
month: "short",
|
|
1036
|
+
day: "2-digit",
|
|
1037
|
+
hour: "2-digit",
|
|
1038
|
+
minute: "2-digit",
|
|
1039
|
+
hour12: false
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
986
1042
|
var IndicatorCategory = /* @__PURE__ */ ((IndicatorCategory2) => {
|
|
987
1043
|
IndicatorCategory2["TREND"] = "Trend";
|
|
988
1044
|
IndicatorCategory2["MOMENTUM"] = "Momentum";
|