hyperprop-charting-library 0.1.59 → 0.1.61
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/hyperprop-charting-library.cjs +141 -7
- package/dist/hyperprop-charting-library.d.ts +4 -2
- package/dist/hyperprop-charting-library.js +141 -7
- package/dist/index.cjs +141 -7
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +141 -7
- package/package.json +1 -1
|
@@ -964,6 +964,8 @@ function createChart(element, options = {}) {
|
|
|
964
964
|
let drawingSelectHandler = null;
|
|
965
965
|
let drawingHoverHandler = null;
|
|
966
966
|
let lastHoveredDrawingId = null;
|
|
967
|
+
const drawingToolDefaults = /* @__PURE__ */ new Map();
|
|
968
|
+
const getDrawingToolDefaults = (tool) => drawingToolDefaults.get(tool) ?? {};
|
|
967
969
|
const emitDrawingsChange = () => {
|
|
968
970
|
drawingsChangeHandler?.(drawings.map((drawing) => serializeDrawing(drawing)));
|
|
969
971
|
};
|
|
@@ -2021,6 +2023,16 @@ function createChart(element, options = {}) {
|
|
|
2021
2023
|
return chartBottom - (price - yMin) / yRange * chartHeight;
|
|
2022
2024
|
};
|
|
2023
2025
|
const xFromDrawingPoint = (point) => chartLeft + (point.index + 0.5 - xStart) / xSpan * chartWidth;
|
|
2026
|
+
const FIB_LEVELS = [
|
|
2027
|
+
{ ratio: 0, color: "#787b86" },
|
|
2028
|
+
{ ratio: 0.236, color: "#f23645", band: "rgba(242,54,69,0.10)" },
|
|
2029
|
+
{ ratio: 0.382, color: "#ff9800", band: "rgba(255,152,0,0.10)" },
|
|
2030
|
+
{ ratio: 0.5, color: "#4caf50", band: "rgba(76,175,80,0.10)" },
|
|
2031
|
+
{ ratio: 0.618, color: "#089981", band: "rgba(8,153,129,0.10)" },
|
|
2032
|
+
{ ratio: 0.786, color: "#00bcd4", band: "rgba(0,188,212,0.10)" },
|
|
2033
|
+
{ ratio: 1, color: "#787b86", band: "rgba(120,123,134,0.10)" },
|
|
2034
|
+
{ ratio: 1.618, color: "#2962ff", band: "rgba(41,98,255,0.08)" }
|
|
2035
|
+
];
|
|
2024
2036
|
const drawDrawingHandle = (x, y, color) => {
|
|
2025
2037
|
ctx.save();
|
|
2026
2038
|
ctx.setLineDash([]);
|
|
@@ -2097,6 +2109,72 @@ function createChart(element, options = {}) {
|
|
|
2097
2109
|
drawDrawingLabel(drawing.label, midX, midY, drawing.color);
|
|
2098
2110
|
}
|
|
2099
2111
|
}
|
|
2112
|
+
} else if (drawing.type === "fib-retracement") {
|
|
2113
|
+
const first = drawing.points[0];
|
|
2114
|
+
const second = drawing.points[1];
|
|
2115
|
+
if (first && second) {
|
|
2116
|
+
const firstX = xFromDrawingPoint(first);
|
|
2117
|
+
const secondX = xFromDrawingPoint(second);
|
|
2118
|
+
const firstY = yFromPrice(first.price);
|
|
2119
|
+
const secondY = yFromPrice(second.price);
|
|
2120
|
+
const lineLeft = chartLeft;
|
|
2121
|
+
const lineRight = chartRight;
|
|
2122
|
+
const levelLines = FIB_LEVELS.map((level) => {
|
|
2123
|
+
const price = first.price + (second.price - first.price) * (1 - level.ratio);
|
|
2124
|
+
return { ...level, price, y: yFromPrice(price) };
|
|
2125
|
+
});
|
|
2126
|
+
for (let index = 0; index < levelLines.length - 1; index += 1) {
|
|
2127
|
+
const top = levelLines[index];
|
|
2128
|
+
const bottom = levelLines[index + 1];
|
|
2129
|
+
const fillColor = bottom.band ?? top.band;
|
|
2130
|
+
if (!fillColor) continue;
|
|
2131
|
+
const bandTop = Math.min(top.y, bottom.y);
|
|
2132
|
+
const bandBottom = Math.max(top.y, bottom.y);
|
|
2133
|
+
ctx.save();
|
|
2134
|
+
ctx.fillStyle = fillColor;
|
|
2135
|
+
ctx.globalAlpha = draft ? 0.5 : 1;
|
|
2136
|
+
ctx.fillRect(lineLeft, bandTop, lineRight - lineLeft, bandBottom - bandTop);
|
|
2137
|
+
ctx.restore();
|
|
2138
|
+
}
|
|
2139
|
+
ctx.save();
|
|
2140
|
+
ctx.lineWidth = drawing.width;
|
|
2141
|
+
applyDashPattern(drawing.style, dashPatterns.dotted, dashPatterns.dashed);
|
|
2142
|
+
for (const level of levelLines) {
|
|
2143
|
+
ctx.strokeStyle = level.color;
|
|
2144
|
+
ctx.beginPath();
|
|
2145
|
+
ctx.moveTo(crisp(lineLeft), crisp(level.y));
|
|
2146
|
+
ctx.lineTo(crisp(lineRight), crisp(level.y));
|
|
2147
|
+
ctx.stroke();
|
|
2148
|
+
}
|
|
2149
|
+
ctx.restore();
|
|
2150
|
+
ctx.save();
|
|
2151
|
+
ctx.strokeStyle = "rgba(148,163,184,0.7)";
|
|
2152
|
+
ctx.setLineDash([4, 4]);
|
|
2153
|
+
ctx.lineWidth = 1;
|
|
2154
|
+
ctx.beginPath();
|
|
2155
|
+
ctx.moveTo(firstX, firstY);
|
|
2156
|
+
ctx.lineTo(secondX, secondY);
|
|
2157
|
+
ctx.stroke();
|
|
2158
|
+
ctx.restore();
|
|
2159
|
+
drawDrawingHandle(firstX, firstY, drawing.color);
|
|
2160
|
+
drawDrawingHandle(secondX, secondY, drawing.color);
|
|
2161
|
+
const prevFont = ctx.font;
|
|
2162
|
+
ctx.font = `500 11px ${mergedOptions.fontFamily}`;
|
|
2163
|
+
for (const level of levelLines) {
|
|
2164
|
+
const labelText = `${level.ratio} (${formatPrice(level.price)})`;
|
|
2165
|
+
const textWidth = ctx.measureText(labelText).width;
|
|
2166
|
+
const padding = 4;
|
|
2167
|
+
const bgX = lineLeft + 4;
|
|
2168
|
+
const bgY = level.y - 9;
|
|
2169
|
+
ctx.fillStyle = mergedOptions.backgroundColor;
|
|
2170
|
+
fillRoundedRect(bgX, bgY, textWidth + padding * 2, 16, 3);
|
|
2171
|
+
ctx.fillStyle = level.color;
|
|
2172
|
+
ctx.textAlign = "left";
|
|
2173
|
+
ctx.textBaseline = "middle";
|
|
2174
|
+
ctx.fillText(labelText, bgX + padding, bgY + 8);
|
|
2175
|
+
}
|
|
2176
|
+
ctx.font = prevFont;
|
|
2177
|
+
}
|
|
2100
2178
|
}
|
|
2101
2179
|
ctx.restore();
|
|
2102
2180
|
};
|
|
@@ -3183,6 +3261,28 @@ function createChart(element, options = {}) {
|
|
|
3183
3261
|
if (distanceToSegment(x, y, x1, y1, x2, y2) <= 6) {
|
|
3184
3262
|
return { drawing, target: "line" };
|
|
3185
3263
|
}
|
|
3264
|
+
} else if (drawing.type === "fib-retracement") {
|
|
3265
|
+
const first = drawing.points[0];
|
|
3266
|
+
const second = drawing.points[1];
|
|
3267
|
+
if (!first || !second) continue;
|
|
3268
|
+
const x1 = canvasXFromDrawingPoint(first);
|
|
3269
|
+
const y1 = canvasYFromDrawingPrice(first.price);
|
|
3270
|
+
const x2 = canvasXFromDrawingPoint(second);
|
|
3271
|
+
const y2 = canvasYFromDrawingPrice(second.price);
|
|
3272
|
+
if (Math.hypot(x - x1, y - y1) <= 9) {
|
|
3273
|
+
return { drawing, target: "handle", pointIndex: 0 };
|
|
3274
|
+
}
|
|
3275
|
+
if (Math.hypot(x - x2, y - y2) <= 9) {
|
|
3276
|
+
return { drawing, target: "handle", pointIndex: 1 };
|
|
3277
|
+
}
|
|
3278
|
+
const fibRatios = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1, 1.618];
|
|
3279
|
+
for (const ratio of fibRatios) {
|
|
3280
|
+
const price = first.price + (second.price - first.price) * (1 - ratio);
|
|
3281
|
+
const lineY = canvasYFromDrawingPrice(price);
|
|
3282
|
+
if (Math.abs(y - lineY) <= 5) {
|
|
3283
|
+
return { drawing, target: "line" };
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3186
3286
|
}
|
|
3187
3287
|
}
|
|
3188
3288
|
return null;
|
|
@@ -3248,13 +3348,14 @@ function createChart(element, options = {}) {
|
|
|
3248
3348
|
return false;
|
|
3249
3349
|
}
|
|
3250
3350
|
if (activeDrawingTool === "horizontal-line") {
|
|
3351
|
+
const defaults = getDrawingToolDefaults("horizontal-line");
|
|
3251
3352
|
drawings.push(
|
|
3252
3353
|
normalizeDrawingState({
|
|
3253
3354
|
type: "horizontal-line",
|
|
3254
3355
|
points: [point],
|
|
3255
|
-
color: "#38bdf8",
|
|
3256
|
-
style: "
|
|
3257
|
-
width: 1
|
|
3356
|
+
color: defaults.color ?? "#38bdf8",
|
|
3357
|
+
style: defaults.style ?? "solid",
|
|
3358
|
+
width: defaults.width ?? 1
|
|
3258
3359
|
})
|
|
3259
3360
|
);
|
|
3260
3361
|
emitDrawingsChange();
|
|
@@ -3274,18 +3375,50 @@ function createChart(element, options = {}) {
|
|
|
3274
3375
|
draw();
|
|
3275
3376
|
return true;
|
|
3276
3377
|
}
|
|
3378
|
+
const defaults = getDrawingToolDefaults("trendline");
|
|
3277
3379
|
draftDrawing = normalizeDrawingState({
|
|
3278
3380
|
type: "trendline",
|
|
3279
3381
|
points: [point, point],
|
|
3280
|
-
color: "#2563eb",
|
|
3281
|
-
style: "solid",
|
|
3282
|
-
width: 2
|
|
3382
|
+
color: defaults.color ?? "#2563eb",
|
|
3383
|
+
style: defaults.style ?? "solid",
|
|
3384
|
+
width: defaults.width ?? 2
|
|
3385
|
+
});
|
|
3386
|
+
draw();
|
|
3387
|
+
return true;
|
|
3388
|
+
}
|
|
3389
|
+
if (activeDrawingTool === "fib-retracement") {
|
|
3390
|
+
if (draftDrawing?.type === "fib-retracement") {
|
|
3391
|
+
const completed = normalizeDrawingState({
|
|
3392
|
+
...serializeDrawing(draftDrawing),
|
|
3393
|
+
points: [draftDrawing.points[0], point]
|
|
3394
|
+
});
|
|
3395
|
+
drawings.push(completed);
|
|
3396
|
+
draftDrawing = null;
|
|
3397
|
+
activeDrawingTool = null;
|
|
3398
|
+
emitDrawingsChange();
|
|
3399
|
+
draw();
|
|
3400
|
+
return true;
|
|
3401
|
+
}
|
|
3402
|
+
const defaults = getDrawingToolDefaults("fib-retracement");
|
|
3403
|
+
draftDrawing = normalizeDrawingState({
|
|
3404
|
+
type: "fib-retracement",
|
|
3405
|
+
points: [point, point],
|
|
3406
|
+
color: defaults.color ?? "#2563eb",
|
|
3407
|
+
style: defaults.style ?? "solid",
|
|
3408
|
+
width: defaults.width ?? 1
|
|
3283
3409
|
});
|
|
3284
3410
|
draw();
|
|
3285
3411
|
return true;
|
|
3286
3412
|
}
|
|
3287
3413
|
return false;
|
|
3288
3414
|
};
|
|
3415
|
+
const setDrawingDefaults = (tool, defaults) => {
|
|
3416
|
+
if (defaults === null) {
|
|
3417
|
+
drawingToolDefaults.delete(tool);
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3420
|
+
drawingToolDefaults.set(tool, { ...defaults });
|
|
3421
|
+
};
|
|
3289
3422
|
const updateDrawingDrag = (x, y) => {
|
|
3290
3423
|
if (!drawingDragState) {
|
|
3291
3424
|
return false;
|
|
@@ -3519,7 +3652,7 @@ function createChart(element, options = {}) {
|
|
|
3519
3652
|
setCrosshairPoint(null);
|
|
3520
3653
|
return;
|
|
3521
3654
|
}
|
|
3522
|
-
if (draftDrawing && activeDrawingTool === "trendline") {
|
|
3655
|
+
if (draftDrawing && (activeDrawingTool === "trendline" || activeDrawingTool === "fib-retracement")) {
|
|
3523
3656
|
const nextPoint = drawingPointFromCanvas(point.x, point.y);
|
|
3524
3657
|
if (nextPoint) {
|
|
3525
3658
|
draftDrawing = {
|
|
@@ -4134,6 +4267,7 @@ function createChart(element, options = {}) {
|
|
|
4134
4267
|
onDrawingsChange,
|
|
4135
4268
|
onDrawingSelect,
|
|
4136
4269
|
onDrawingHover,
|
|
4270
|
+
setDrawingDefaults,
|
|
4137
4271
|
setDoubleClickEnabled,
|
|
4138
4272
|
setDoubleClickAction,
|
|
4139
4273
|
registerIndicator,
|
|
@@ -43,7 +43,7 @@ interface ChartOptions {
|
|
|
43
43
|
drawings?: DrawingObjectOptions[];
|
|
44
44
|
}
|
|
45
45
|
type IndicatorPane = "overlay" | "separate";
|
|
46
|
-
type DrawingToolType = "horizontal-line" | "trendline";
|
|
46
|
+
type DrawingToolType = "horizontal-line" | "trendline" | "fib-retracement";
|
|
47
47
|
interface DrawingPoint {
|
|
48
48
|
index: number;
|
|
49
49
|
price: number;
|
|
@@ -73,6 +73,7 @@ interface DrawingHoverEvent {
|
|
|
73
73
|
x: number;
|
|
74
74
|
y: number;
|
|
75
75
|
}
|
|
76
|
+
type DrawingDefaults = Partial<Pick<DrawingObjectOptions, "color" | "style" | "width">>;
|
|
76
77
|
interface IndicatorInstanceOptions<TInputs extends Record<string, unknown> = Record<string, unknown>> {
|
|
77
78
|
id?: string;
|
|
78
79
|
type: string;
|
|
@@ -405,6 +406,7 @@ interface ChartInstance {
|
|
|
405
406
|
onDrawingsChange: (handler: ((drawings: DrawingObjectOptions[]) => void) | null) => void;
|
|
406
407
|
onDrawingSelect: (handler: ((event: DrawingSelectEvent) => void) | null) => void;
|
|
407
408
|
onDrawingHover: (handler: ((event: DrawingHoverEvent) => void) | null) => void;
|
|
409
|
+
setDrawingDefaults: (tool: DrawingToolType, defaults: DrawingDefaults | null) => void;
|
|
408
410
|
setDoubleClickEnabled: (enabled: boolean) => void;
|
|
409
411
|
setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
|
|
410
412
|
registerIndicator: (plugin: IndicatorPlugin<any>) => void;
|
|
@@ -440,4 +442,4 @@ interface ViewportState {
|
|
|
440
442
|
}
|
|
441
443
|
declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
|
|
442
444
|
|
|
443
|
-
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
|
445
|
+
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
|
@@ -940,6 +940,8 @@ function createChart(element, options = {}) {
|
|
|
940
940
|
let drawingSelectHandler = null;
|
|
941
941
|
let drawingHoverHandler = null;
|
|
942
942
|
let lastHoveredDrawingId = null;
|
|
943
|
+
const drawingToolDefaults = /* @__PURE__ */ new Map();
|
|
944
|
+
const getDrawingToolDefaults = (tool) => drawingToolDefaults.get(tool) ?? {};
|
|
943
945
|
const emitDrawingsChange = () => {
|
|
944
946
|
drawingsChangeHandler?.(drawings.map((drawing) => serializeDrawing(drawing)));
|
|
945
947
|
};
|
|
@@ -1997,6 +1999,16 @@ function createChart(element, options = {}) {
|
|
|
1997
1999
|
return chartBottom - (price - yMin) / yRange * chartHeight;
|
|
1998
2000
|
};
|
|
1999
2001
|
const xFromDrawingPoint = (point) => chartLeft + (point.index + 0.5 - xStart) / xSpan * chartWidth;
|
|
2002
|
+
const FIB_LEVELS = [
|
|
2003
|
+
{ ratio: 0, color: "#787b86" },
|
|
2004
|
+
{ ratio: 0.236, color: "#f23645", band: "rgba(242,54,69,0.10)" },
|
|
2005
|
+
{ ratio: 0.382, color: "#ff9800", band: "rgba(255,152,0,0.10)" },
|
|
2006
|
+
{ ratio: 0.5, color: "#4caf50", band: "rgba(76,175,80,0.10)" },
|
|
2007
|
+
{ ratio: 0.618, color: "#089981", band: "rgba(8,153,129,0.10)" },
|
|
2008
|
+
{ ratio: 0.786, color: "#00bcd4", band: "rgba(0,188,212,0.10)" },
|
|
2009
|
+
{ ratio: 1, color: "#787b86", band: "rgba(120,123,134,0.10)" },
|
|
2010
|
+
{ ratio: 1.618, color: "#2962ff", band: "rgba(41,98,255,0.08)" }
|
|
2011
|
+
];
|
|
2000
2012
|
const drawDrawingHandle = (x, y, color) => {
|
|
2001
2013
|
ctx.save();
|
|
2002
2014
|
ctx.setLineDash([]);
|
|
@@ -2073,6 +2085,72 @@ function createChart(element, options = {}) {
|
|
|
2073
2085
|
drawDrawingLabel(drawing.label, midX, midY, drawing.color);
|
|
2074
2086
|
}
|
|
2075
2087
|
}
|
|
2088
|
+
} else if (drawing.type === "fib-retracement") {
|
|
2089
|
+
const first = drawing.points[0];
|
|
2090
|
+
const second = drawing.points[1];
|
|
2091
|
+
if (first && second) {
|
|
2092
|
+
const firstX = xFromDrawingPoint(first);
|
|
2093
|
+
const secondX = xFromDrawingPoint(second);
|
|
2094
|
+
const firstY = yFromPrice(first.price);
|
|
2095
|
+
const secondY = yFromPrice(second.price);
|
|
2096
|
+
const lineLeft = chartLeft;
|
|
2097
|
+
const lineRight = chartRight;
|
|
2098
|
+
const levelLines = FIB_LEVELS.map((level) => {
|
|
2099
|
+
const price = first.price + (second.price - first.price) * (1 - level.ratio);
|
|
2100
|
+
return { ...level, price, y: yFromPrice(price) };
|
|
2101
|
+
});
|
|
2102
|
+
for (let index = 0; index < levelLines.length - 1; index += 1) {
|
|
2103
|
+
const top = levelLines[index];
|
|
2104
|
+
const bottom = levelLines[index + 1];
|
|
2105
|
+
const fillColor = bottom.band ?? top.band;
|
|
2106
|
+
if (!fillColor) continue;
|
|
2107
|
+
const bandTop = Math.min(top.y, bottom.y);
|
|
2108
|
+
const bandBottom = Math.max(top.y, bottom.y);
|
|
2109
|
+
ctx.save();
|
|
2110
|
+
ctx.fillStyle = fillColor;
|
|
2111
|
+
ctx.globalAlpha = draft ? 0.5 : 1;
|
|
2112
|
+
ctx.fillRect(lineLeft, bandTop, lineRight - lineLeft, bandBottom - bandTop);
|
|
2113
|
+
ctx.restore();
|
|
2114
|
+
}
|
|
2115
|
+
ctx.save();
|
|
2116
|
+
ctx.lineWidth = drawing.width;
|
|
2117
|
+
applyDashPattern(drawing.style, dashPatterns.dotted, dashPatterns.dashed);
|
|
2118
|
+
for (const level of levelLines) {
|
|
2119
|
+
ctx.strokeStyle = level.color;
|
|
2120
|
+
ctx.beginPath();
|
|
2121
|
+
ctx.moveTo(crisp(lineLeft), crisp(level.y));
|
|
2122
|
+
ctx.lineTo(crisp(lineRight), crisp(level.y));
|
|
2123
|
+
ctx.stroke();
|
|
2124
|
+
}
|
|
2125
|
+
ctx.restore();
|
|
2126
|
+
ctx.save();
|
|
2127
|
+
ctx.strokeStyle = "rgba(148,163,184,0.7)";
|
|
2128
|
+
ctx.setLineDash([4, 4]);
|
|
2129
|
+
ctx.lineWidth = 1;
|
|
2130
|
+
ctx.beginPath();
|
|
2131
|
+
ctx.moveTo(firstX, firstY);
|
|
2132
|
+
ctx.lineTo(secondX, secondY);
|
|
2133
|
+
ctx.stroke();
|
|
2134
|
+
ctx.restore();
|
|
2135
|
+
drawDrawingHandle(firstX, firstY, drawing.color);
|
|
2136
|
+
drawDrawingHandle(secondX, secondY, drawing.color);
|
|
2137
|
+
const prevFont = ctx.font;
|
|
2138
|
+
ctx.font = `500 11px ${mergedOptions.fontFamily}`;
|
|
2139
|
+
for (const level of levelLines) {
|
|
2140
|
+
const labelText = `${level.ratio} (${formatPrice(level.price)})`;
|
|
2141
|
+
const textWidth = ctx.measureText(labelText).width;
|
|
2142
|
+
const padding = 4;
|
|
2143
|
+
const bgX = lineLeft + 4;
|
|
2144
|
+
const bgY = level.y - 9;
|
|
2145
|
+
ctx.fillStyle = mergedOptions.backgroundColor;
|
|
2146
|
+
fillRoundedRect(bgX, bgY, textWidth + padding * 2, 16, 3);
|
|
2147
|
+
ctx.fillStyle = level.color;
|
|
2148
|
+
ctx.textAlign = "left";
|
|
2149
|
+
ctx.textBaseline = "middle";
|
|
2150
|
+
ctx.fillText(labelText, bgX + padding, bgY + 8);
|
|
2151
|
+
}
|
|
2152
|
+
ctx.font = prevFont;
|
|
2153
|
+
}
|
|
2076
2154
|
}
|
|
2077
2155
|
ctx.restore();
|
|
2078
2156
|
};
|
|
@@ -3159,6 +3237,28 @@ function createChart(element, options = {}) {
|
|
|
3159
3237
|
if (distanceToSegment(x, y, x1, y1, x2, y2) <= 6) {
|
|
3160
3238
|
return { drawing, target: "line" };
|
|
3161
3239
|
}
|
|
3240
|
+
} else if (drawing.type === "fib-retracement") {
|
|
3241
|
+
const first = drawing.points[0];
|
|
3242
|
+
const second = drawing.points[1];
|
|
3243
|
+
if (!first || !second) continue;
|
|
3244
|
+
const x1 = canvasXFromDrawingPoint(first);
|
|
3245
|
+
const y1 = canvasYFromDrawingPrice(first.price);
|
|
3246
|
+
const x2 = canvasXFromDrawingPoint(second);
|
|
3247
|
+
const y2 = canvasYFromDrawingPrice(second.price);
|
|
3248
|
+
if (Math.hypot(x - x1, y - y1) <= 9) {
|
|
3249
|
+
return { drawing, target: "handle", pointIndex: 0 };
|
|
3250
|
+
}
|
|
3251
|
+
if (Math.hypot(x - x2, y - y2) <= 9) {
|
|
3252
|
+
return { drawing, target: "handle", pointIndex: 1 };
|
|
3253
|
+
}
|
|
3254
|
+
const fibRatios = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1, 1.618];
|
|
3255
|
+
for (const ratio of fibRatios) {
|
|
3256
|
+
const price = first.price + (second.price - first.price) * (1 - ratio);
|
|
3257
|
+
const lineY = canvasYFromDrawingPrice(price);
|
|
3258
|
+
if (Math.abs(y - lineY) <= 5) {
|
|
3259
|
+
return { drawing, target: "line" };
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3162
3262
|
}
|
|
3163
3263
|
}
|
|
3164
3264
|
return null;
|
|
@@ -3224,13 +3324,14 @@ function createChart(element, options = {}) {
|
|
|
3224
3324
|
return false;
|
|
3225
3325
|
}
|
|
3226
3326
|
if (activeDrawingTool === "horizontal-line") {
|
|
3327
|
+
const defaults = getDrawingToolDefaults("horizontal-line");
|
|
3227
3328
|
drawings.push(
|
|
3228
3329
|
normalizeDrawingState({
|
|
3229
3330
|
type: "horizontal-line",
|
|
3230
3331
|
points: [point],
|
|
3231
|
-
color: "#38bdf8",
|
|
3232
|
-
style: "
|
|
3233
|
-
width: 1
|
|
3332
|
+
color: defaults.color ?? "#38bdf8",
|
|
3333
|
+
style: defaults.style ?? "solid",
|
|
3334
|
+
width: defaults.width ?? 1
|
|
3234
3335
|
})
|
|
3235
3336
|
);
|
|
3236
3337
|
emitDrawingsChange();
|
|
@@ -3250,18 +3351,50 @@ function createChart(element, options = {}) {
|
|
|
3250
3351
|
draw();
|
|
3251
3352
|
return true;
|
|
3252
3353
|
}
|
|
3354
|
+
const defaults = getDrawingToolDefaults("trendline");
|
|
3253
3355
|
draftDrawing = normalizeDrawingState({
|
|
3254
3356
|
type: "trendline",
|
|
3255
3357
|
points: [point, point],
|
|
3256
|
-
color: "#2563eb",
|
|
3257
|
-
style: "solid",
|
|
3258
|
-
width: 2
|
|
3358
|
+
color: defaults.color ?? "#2563eb",
|
|
3359
|
+
style: defaults.style ?? "solid",
|
|
3360
|
+
width: defaults.width ?? 2
|
|
3361
|
+
});
|
|
3362
|
+
draw();
|
|
3363
|
+
return true;
|
|
3364
|
+
}
|
|
3365
|
+
if (activeDrawingTool === "fib-retracement") {
|
|
3366
|
+
if (draftDrawing?.type === "fib-retracement") {
|
|
3367
|
+
const completed = normalizeDrawingState({
|
|
3368
|
+
...serializeDrawing(draftDrawing),
|
|
3369
|
+
points: [draftDrawing.points[0], point]
|
|
3370
|
+
});
|
|
3371
|
+
drawings.push(completed);
|
|
3372
|
+
draftDrawing = null;
|
|
3373
|
+
activeDrawingTool = null;
|
|
3374
|
+
emitDrawingsChange();
|
|
3375
|
+
draw();
|
|
3376
|
+
return true;
|
|
3377
|
+
}
|
|
3378
|
+
const defaults = getDrawingToolDefaults("fib-retracement");
|
|
3379
|
+
draftDrawing = normalizeDrawingState({
|
|
3380
|
+
type: "fib-retracement",
|
|
3381
|
+
points: [point, point],
|
|
3382
|
+
color: defaults.color ?? "#2563eb",
|
|
3383
|
+
style: defaults.style ?? "solid",
|
|
3384
|
+
width: defaults.width ?? 1
|
|
3259
3385
|
});
|
|
3260
3386
|
draw();
|
|
3261
3387
|
return true;
|
|
3262
3388
|
}
|
|
3263
3389
|
return false;
|
|
3264
3390
|
};
|
|
3391
|
+
const setDrawingDefaults = (tool, defaults) => {
|
|
3392
|
+
if (defaults === null) {
|
|
3393
|
+
drawingToolDefaults.delete(tool);
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
drawingToolDefaults.set(tool, { ...defaults });
|
|
3397
|
+
};
|
|
3265
3398
|
const updateDrawingDrag = (x, y) => {
|
|
3266
3399
|
if (!drawingDragState) {
|
|
3267
3400
|
return false;
|
|
@@ -3495,7 +3628,7 @@ function createChart(element, options = {}) {
|
|
|
3495
3628
|
setCrosshairPoint(null);
|
|
3496
3629
|
return;
|
|
3497
3630
|
}
|
|
3498
|
-
if (draftDrawing && activeDrawingTool === "trendline") {
|
|
3631
|
+
if (draftDrawing && (activeDrawingTool === "trendline" || activeDrawingTool === "fib-retracement")) {
|
|
3499
3632
|
const nextPoint = drawingPointFromCanvas(point.x, point.y);
|
|
3500
3633
|
if (nextPoint) {
|
|
3501
3634
|
draftDrawing = {
|
|
@@ -4110,6 +4243,7 @@ function createChart(element, options = {}) {
|
|
|
4110
4243
|
onDrawingsChange,
|
|
4111
4244
|
onDrawingSelect,
|
|
4112
4245
|
onDrawingHover,
|
|
4246
|
+
setDrawingDefaults,
|
|
4113
4247
|
setDoubleClickEnabled,
|
|
4114
4248
|
setDoubleClickAction,
|
|
4115
4249
|
registerIndicator,
|
package/dist/index.cjs
CHANGED
|
@@ -964,6 +964,8 @@ function createChart(element, options = {}) {
|
|
|
964
964
|
let drawingSelectHandler = null;
|
|
965
965
|
let drawingHoverHandler = null;
|
|
966
966
|
let lastHoveredDrawingId = null;
|
|
967
|
+
const drawingToolDefaults = /* @__PURE__ */ new Map();
|
|
968
|
+
const getDrawingToolDefaults = (tool) => drawingToolDefaults.get(tool) ?? {};
|
|
967
969
|
const emitDrawingsChange = () => {
|
|
968
970
|
drawingsChangeHandler?.(drawings.map((drawing) => serializeDrawing(drawing)));
|
|
969
971
|
};
|
|
@@ -2021,6 +2023,16 @@ function createChart(element, options = {}) {
|
|
|
2021
2023
|
return chartBottom - (price - yMin) / yRange * chartHeight;
|
|
2022
2024
|
};
|
|
2023
2025
|
const xFromDrawingPoint = (point) => chartLeft + (point.index + 0.5 - xStart) / xSpan * chartWidth;
|
|
2026
|
+
const FIB_LEVELS = [
|
|
2027
|
+
{ ratio: 0, color: "#787b86" },
|
|
2028
|
+
{ ratio: 0.236, color: "#f23645", band: "rgba(242,54,69,0.10)" },
|
|
2029
|
+
{ ratio: 0.382, color: "#ff9800", band: "rgba(255,152,0,0.10)" },
|
|
2030
|
+
{ ratio: 0.5, color: "#4caf50", band: "rgba(76,175,80,0.10)" },
|
|
2031
|
+
{ ratio: 0.618, color: "#089981", band: "rgba(8,153,129,0.10)" },
|
|
2032
|
+
{ ratio: 0.786, color: "#00bcd4", band: "rgba(0,188,212,0.10)" },
|
|
2033
|
+
{ ratio: 1, color: "#787b86", band: "rgba(120,123,134,0.10)" },
|
|
2034
|
+
{ ratio: 1.618, color: "#2962ff", band: "rgba(41,98,255,0.08)" }
|
|
2035
|
+
];
|
|
2024
2036
|
const drawDrawingHandle = (x, y, color) => {
|
|
2025
2037
|
ctx.save();
|
|
2026
2038
|
ctx.setLineDash([]);
|
|
@@ -2097,6 +2109,72 @@ function createChart(element, options = {}) {
|
|
|
2097
2109
|
drawDrawingLabel(drawing.label, midX, midY, drawing.color);
|
|
2098
2110
|
}
|
|
2099
2111
|
}
|
|
2112
|
+
} else if (drawing.type === "fib-retracement") {
|
|
2113
|
+
const first = drawing.points[0];
|
|
2114
|
+
const second = drawing.points[1];
|
|
2115
|
+
if (first && second) {
|
|
2116
|
+
const firstX = xFromDrawingPoint(first);
|
|
2117
|
+
const secondX = xFromDrawingPoint(second);
|
|
2118
|
+
const firstY = yFromPrice(first.price);
|
|
2119
|
+
const secondY = yFromPrice(second.price);
|
|
2120
|
+
const lineLeft = chartLeft;
|
|
2121
|
+
const lineRight = chartRight;
|
|
2122
|
+
const levelLines = FIB_LEVELS.map((level) => {
|
|
2123
|
+
const price = first.price + (second.price - first.price) * (1 - level.ratio);
|
|
2124
|
+
return { ...level, price, y: yFromPrice(price) };
|
|
2125
|
+
});
|
|
2126
|
+
for (let index = 0; index < levelLines.length - 1; index += 1) {
|
|
2127
|
+
const top = levelLines[index];
|
|
2128
|
+
const bottom = levelLines[index + 1];
|
|
2129
|
+
const fillColor = bottom.band ?? top.band;
|
|
2130
|
+
if (!fillColor) continue;
|
|
2131
|
+
const bandTop = Math.min(top.y, bottom.y);
|
|
2132
|
+
const bandBottom = Math.max(top.y, bottom.y);
|
|
2133
|
+
ctx.save();
|
|
2134
|
+
ctx.fillStyle = fillColor;
|
|
2135
|
+
ctx.globalAlpha = draft ? 0.5 : 1;
|
|
2136
|
+
ctx.fillRect(lineLeft, bandTop, lineRight - lineLeft, bandBottom - bandTop);
|
|
2137
|
+
ctx.restore();
|
|
2138
|
+
}
|
|
2139
|
+
ctx.save();
|
|
2140
|
+
ctx.lineWidth = drawing.width;
|
|
2141
|
+
applyDashPattern(drawing.style, dashPatterns.dotted, dashPatterns.dashed);
|
|
2142
|
+
for (const level of levelLines) {
|
|
2143
|
+
ctx.strokeStyle = level.color;
|
|
2144
|
+
ctx.beginPath();
|
|
2145
|
+
ctx.moveTo(crisp(lineLeft), crisp(level.y));
|
|
2146
|
+
ctx.lineTo(crisp(lineRight), crisp(level.y));
|
|
2147
|
+
ctx.stroke();
|
|
2148
|
+
}
|
|
2149
|
+
ctx.restore();
|
|
2150
|
+
ctx.save();
|
|
2151
|
+
ctx.strokeStyle = "rgba(148,163,184,0.7)";
|
|
2152
|
+
ctx.setLineDash([4, 4]);
|
|
2153
|
+
ctx.lineWidth = 1;
|
|
2154
|
+
ctx.beginPath();
|
|
2155
|
+
ctx.moveTo(firstX, firstY);
|
|
2156
|
+
ctx.lineTo(secondX, secondY);
|
|
2157
|
+
ctx.stroke();
|
|
2158
|
+
ctx.restore();
|
|
2159
|
+
drawDrawingHandle(firstX, firstY, drawing.color);
|
|
2160
|
+
drawDrawingHandle(secondX, secondY, drawing.color);
|
|
2161
|
+
const prevFont = ctx.font;
|
|
2162
|
+
ctx.font = `500 11px ${mergedOptions.fontFamily}`;
|
|
2163
|
+
for (const level of levelLines) {
|
|
2164
|
+
const labelText = `${level.ratio} (${formatPrice(level.price)})`;
|
|
2165
|
+
const textWidth = ctx.measureText(labelText).width;
|
|
2166
|
+
const padding = 4;
|
|
2167
|
+
const bgX = lineLeft + 4;
|
|
2168
|
+
const bgY = level.y - 9;
|
|
2169
|
+
ctx.fillStyle = mergedOptions.backgroundColor;
|
|
2170
|
+
fillRoundedRect(bgX, bgY, textWidth + padding * 2, 16, 3);
|
|
2171
|
+
ctx.fillStyle = level.color;
|
|
2172
|
+
ctx.textAlign = "left";
|
|
2173
|
+
ctx.textBaseline = "middle";
|
|
2174
|
+
ctx.fillText(labelText, bgX + padding, bgY + 8);
|
|
2175
|
+
}
|
|
2176
|
+
ctx.font = prevFont;
|
|
2177
|
+
}
|
|
2100
2178
|
}
|
|
2101
2179
|
ctx.restore();
|
|
2102
2180
|
};
|
|
@@ -3183,6 +3261,28 @@ function createChart(element, options = {}) {
|
|
|
3183
3261
|
if (distanceToSegment(x, y, x1, y1, x2, y2) <= 6) {
|
|
3184
3262
|
return { drawing, target: "line" };
|
|
3185
3263
|
}
|
|
3264
|
+
} else if (drawing.type === "fib-retracement") {
|
|
3265
|
+
const first = drawing.points[0];
|
|
3266
|
+
const second = drawing.points[1];
|
|
3267
|
+
if (!first || !second) continue;
|
|
3268
|
+
const x1 = canvasXFromDrawingPoint(first);
|
|
3269
|
+
const y1 = canvasYFromDrawingPrice(first.price);
|
|
3270
|
+
const x2 = canvasXFromDrawingPoint(second);
|
|
3271
|
+
const y2 = canvasYFromDrawingPrice(second.price);
|
|
3272
|
+
if (Math.hypot(x - x1, y - y1) <= 9) {
|
|
3273
|
+
return { drawing, target: "handle", pointIndex: 0 };
|
|
3274
|
+
}
|
|
3275
|
+
if (Math.hypot(x - x2, y - y2) <= 9) {
|
|
3276
|
+
return { drawing, target: "handle", pointIndex: 1 };
|
|
3277
|
+
}
|
|
3278
|
+
const fibRatios = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1, 1.618];
|
|
3279
|
+
for (const ratio of fibRatios) {
|
|
3280
|
+
const price = first.price + (second.price - first.price) * (1 - ratio);
|
|
3281
|
+
const lineY = canvasYFromDrawingPrice(price);
|
|
3282
|
+
if (Math.abs(y - lineY) <= 5) {
|
|
3283
|
+
return { drawing, target: "line" };
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3186
3286
|
}
|
|
3187
3287
|
}
|
|
3188
3288
|
return null;
|
|
@@ -3248,13 +3348,14 @@ function createChart(element, options = {}) {
|
|
|
3248
3348
|
return false;
|
|
3249
3349
|
}
|
|
3250
3350
|
if (activeDrawingTool === "horizontal-line") {
|
|
3351
|
+
const defaults = getDrawingToolDefaults("horizontal-line");
|
|
3251
3352
|
drawings.push(
|
|
3252
3353
|
normalizeDrawingState({
|
|
3253
3354
|
type: "horizontal-line",
|
|
3254
3355
|
points: [point],
|
|
3255
|
-
color: "#38bdf8",
|
|
3256
|
-
style: "
|
|
3257
|
-
width: 1
|
|
3356
|
+
color: defaults.color ?? "#38bdf8",
|
|
3357
|
+
style: defaults.style ?? "solid",
|
|
3358
|
+
width: defaults.width ?? 1
|
|
3258
3359
|
})
|
|
3259
3360
|
);
|
|
3260
3361
|
emitDrawingsChange();
|
|
@@ -3274,18 +3375,50 @@ function createChart(element, options = {}) {
|
|
|
3274
3375
|
draw();
|
|
3275
3376
|
return true;
|
|
3276
3377
|
}
|
|
3378
|
+
const defaults = getDrawingToolDefaults("trendline");
|
|
3277
3379
|
draftDrawing = normalizeDrawingState({
|
|
3278
3380
|
type: "trendline",
|
|
3279
3381
|
points: [point, point],
|
|
3280
|
-
color: "#2563eb",
|
|
3281
|
-
style: "solid",
|
|
3282
|
-
width: 2
|
|
3382
|
+
color: defaults.color ?? "#2563eb",
|
|
3383
|
+
style: defaults.style ?? "solid",
|
|
3384
|
+
width: defaults.width ?? 2
|
|
3385
|
+
});
|
|
3386
|
+
draw();
|
|
3387
|
+
return true;
|
|
3388
|
+
}
|
|
3389
|
+
if (activeDrawingTool === "fib-retracement") {
|
|
3390
|
+
if (draftDrawing?.type === "fib-retracement") {
|
|
3391
|
+
const completed = normalizeDrawingState({
|
|
3392
|
+
...serializeDrawing(draftDrawing),
|
|
3393
|
+
points: [draftDrawing.points[0], point]
|
|
3394
|
+
});
|
|
3395
|
+
drawings.push(completed);
|
|
3396
|
+
draftDrawing = null;
|
|
3397
|
+
activeDrawingTool = null;
|
|
3398
|
+
emitDrawingsChange();
|
|
3399
|
+
draw();
|
|
3400
|
+
return true;
|
|
3401
|
+
}
|
|
3402
|
+
const defaults = getDrawingToolDefaults("fib-retracement");
|
|
3403
|
+
draftDrawing = normalizeDrawingState({
|
|
3404
|
+
type: "fib-retracement",
|
|
3405
|
+
points: [point, point],
|
|
3406
|
+
color: defaults.color ?? "#2563eb",
|
|
3407
|
+
style: defaults.style ?? "solid",
|
|
3408
|
+
width: defaults.width ?? 1
|
|
3283
3409
|
});
|
|
3284
3410
|
draw();
|
|
3285
3411
|
return true;
|
|
3286
3412
|
}
|
|
3287
3413
|
return false;
|
|
3288
3414
|
};
|
|
3415
|
+
const setDrawingDefaults = (tool, defaults) => {
|
|
3416
|
+
if (defaults === null) {
|
|
3417
|
+
drawingToolDefaults.delete(tool);
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3420
|
+
drawingToolDefaults.set(tool, { ...defaults });
|
|
3421
|
+
};
|
|
3289
3422
|
const updateDrawingDrag = (x, y) => {
|
|
3290
3423
|
if (!drawingDragState) {
|
|
3291
3424
|
return false;
|
|
@@ -3519,7 +3652,7 @@ function createChart(element, options = {}) {
|
|
|
3519
3652
|
setCrosshairPoint(null);
|
|
3520
3653
|
return;
|
|
3521
3654
|
}
|
|
3522
|
-
if (draftDrawing && activeDrawingTool === "trendline") {
|
|
3655
|
+
if (draftDrawing && (activeDrawingTool === "trendline" || activeDrawingTool === "fib-retracement")) {
|
|
3523
3656
|
const nextPoint = drawingPointFromCanvas(point.x, point.y);
|
|
3524
3657
|
if (nextPoint) {
|
|
3525
3658
|
draftDrawing = {
|
|
@@ -4134,6 +4267,7 @@ function createChart(element, options = {}) {
|
|
|
4134
4267
|
onDrawingsChange,
|
|
4135
4268
|
onDrawingSelect,
|
|
4136
4269
|
onDrawingHover,
|
|
4270
|
+
setDrawingDefaults,
|
|
4137
4271
|
setDoubleClickEnabled,
|
|
4138
4272
|
setDoubleClickAction,
|
|
4139
4273
|
registerIndicator,
|
package/dist/index.d.cts
CHANGED
|
@@ -43,7 +43,7 @@ interface ChartOptions {
|
|
|
43
43
|
drawings?: DrawingObjectOptions[];
|
|
44
44
|
}
|
|
45
45
|
type IndicatorPane = "overlay" | "separate";
|
|
46
|
-
type DrawingToolType = "horizontal-line" | "trendline";
|
|
46
|
+
type DrawingToolType = "horizontal-line" | "trendline" | "fib-retracement";
|
|
47
47
|
interface DrawingPoint {
|
|
48
48
|
index: number;
|
|
49
49
|
price: number;
|
|
@@ -73,6 +73,7 @@ interface DrawingHoverEvent {
|
|
|
73
73
|
x: number;
|
|
74
74
|
y: number;
|
|
75
75
|
}
|
|
76
|
+
type DrawingDefaults = Partial<Pick<DrawingObjectOptions, "color" | "style" | "width">>;
|
|
76
77
|
interface IndicatorInstanceOptions<TInputs extends Record<string, unknown> = Record<string, unknown>> {
|
|
77
78
|
id?: string;
|
|
78
79
|
type: string;
|
|
@@ -405,6 +406,7 @@ interface ChartInstance {
|
|
|
405
406
|
onDrawingsChange: (handler: ((drawings: DrawingObjectOptions[]) => void) | null) => void;
|
|
406
407
|
onDrawingSelect: (handler: ((event: DrawingSelectEvent) => void) | null) => void;
|
|
407
408
|
onDrawingHover: (handler: ((event: DrawingHoverEvent) => void) | null) => void;
|
|
409
|
+
setDrawingDefaults: (tool: DrawingToolType, defaults: DrawingDefaults | null) => void;
|
|
408
410
|
setDoubleClickEnabled: (enabled: boolean) => void;
|
|
409
411
|
setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
|
|
410
412
|
registerIndicator: (plugin: IndicatorPlugin<any>) => void;
|
|
@@ -440,4 +442,4 @@ interface ViewportState {
|
|
|
440
442
|
}
|
|
441
443
|
declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
|
|
442
444
|
|
|
443
|
-
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
|
445
|
+
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
package/dist/index.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ interface ChartOptions {
|
|
|
43
43
|
drawings?: DrawingObjectOptions[];
|
|
44
44
|
}
|
|
45
45
|
type IndicatorPane = "overlay" | "separate";
|
|
46
|
-
type DrawingToolType = "horizontal-line" | "trendline";
|
|
46
|
+
type DrawingToolType = "horizontal-line" | "trendline" | "fib-retracement";
|
|
47
47
|
interface DrawingPoint {
|
|
48
48
|
index: number;
|
|
49
49
|
price: number;
|
|
@@ -73,6 +73,7 @@ interface DrawingHoverEvent {
|
|
|
73
73
|
x: number;
|
|
74
74
|
y: number;
|
|
75
75
|
}
|
|
76
|
+
type DrawingDefaults = Partial<Pick<DrawingObjectOptions, "color" | "style" | "width">>;
|
|
76
77
|
interface IndicatorInstanceOptions<TInputs extends Record<string, unknown> = Record<string, unknown>> {
|
|
77
78
|
id?: string;
|
|
78
79
|
type: string;
|
|
@@ -405,6 +406,7 @@ interface ChartInstance {
|
|
|
405
406
|
onDrawingsChange: (handler: ((drawings: DrawingObjectOptions[]) => void) | null) => void;
|
|
406
407
|
onDrawingSelect: (handler: ((event: DrawingSelectEvent) => void) | null) => void;
|
|
407
408
|
onDrawingHover: (handler: ((event: DrawingHoverEvent) => void) | null) => void;
|
|
409
|
+
setDrawingDefaults: (tool: DrawingToolType, defaults: DrawingDefaults | null) => void;
|
|
408
410
|
setDoubleClickEnabled: (enabled: boolean) => void;
|
|
409
411
|
setDoubleClickAction: (action: "reset" | "placeLimitOrder") => void;
|
|
410
412
|
registerIndicator: (plugin: IndicatorPlugin<any>) => void;
|
|
@@ -440,4 +442,4 @@ interface ViewportState {
|
|
|
440
442
|
}
|
|
441
443
|
declare function createChart(element: HTMLElement, options?: ChartOptions): ChartInstance;
|
|
442
444
|
|
|
443
|
-
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
|
445
|
+
export { type AxisOptions, type BuiltInIndicatorInfo, type ChartClickEvent, type ChartInstance, type ChartOptions, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairPriceActionEvent, type DashPatternOptions, type DrawingDefaults, type DrawingHoverEvent, type DrawingObjectOptions, type DrawingPoint, type DrawingSelectEvent, type DrawingToolType, type GridOptions, type IndicatorInstanceOptions, type IndicatorPane, type IndicatorPaneAxisOptions, type IndicatorPaneGuideLine, type IndicatorPaneRenderInfo, type IndicatorPaneValue, type IndicatorPaneValueLabel, type IndicatorPlugin, type IndicatorRenderContext, type LabelsOptions, type OhlcDataPoint, type OrderActionButton, type OrderActionEvent, type OrderLineOptions, type PriceLineOptions, type TickerLineOptions, type ViewportState, type WatermarkOptions, createChart };
|
package/dist/index.js
CHANGED
|
@@ -940,6 +940,8 @@ function createChart(element, options = {}) {
|
|
|
940
940
|
let drawingSelectHandler = null;
|
|
941
941
|
let drawingHoverHandler = null;
|
|
942
942
|
let lastHoveredDrawingId = null;
|
|
943
|
+
const drawingToolDefaults = /* @__PURE__ */ new Map();
|
|
944
|
+
const getDrawingToolDefaults = (tool) => drawingToolDefaults.get(tool) ?? {};
|
|
943
945
|
const emitDrawingsChange = () => {
|
|
944
946
|
drawingsChangeHandler?.(drawings.map((drawing) => serializeDrawing(drawing)));
|
|
945
947
|
};
|
|
@@ -1997,6 +1999,16 @@ function createChart(element, options = {}) {
|
|
|
1997
1999
|
return chartBottom - (price - yMin) / yRange * chartHeight;
|
|
1998
2000
|
};
|
|
1999
2001
|
const xFromDrawingPoint = (point) => chartLeft + (point.index + 0.5 - xStart) / xSpan * chartWidth;
|
|
2002
|
+
const FIB_LEVELS = [
|
|
2003
|
+
{ ratio: 0, color: "#787b86" },
|
|
2004
|
+
{ ratio: 0.236, color: "#f23645", band: "rgba(242,54,69,0.10)" },
|
|
2005
|
+
{ ratio: 0.382, color: "#ff9800", band: "rgba(255,152,0,0.10)" },
|
|
2006
|
+
{ ratio: 0.5, color: "#4caf50", band: "rgba(76,175,80,0.10)" },
|
|
2007
|
+
{ ratio: 0.618, color: "#089981", band: "rgba(8,153,129,0.10)" },
|
|
2008
|
+
{ ratio: 0.786, color: "#00bcd4", band: "rgba(0,188,212,0.10)" },
|
|
2009
|
+
{ ratio: 1, color: "#787b86", band: "rgba(120,123,134,0.10)" },
|
|
2010
|
+
{ ratio: 1.618, color: "#2962ff", band: "rgba(41,98,255,0.08)" }
|
|
2011
|
+
];
|
|
2000
2012
|
const drawDrawingHandle = (x, y, color) => {
|
|
2001
2013
|
ctx.save();
|
|
2002
2014
|
ctx.setLineDash([]);
|
|
@@ -2073,6 +2085,72 @@ function createChart(element, options = {}) {
|
|
|
2073
2085
|
drawDrawingLabel(drawing.label, midX, midY, drawing.color);
|
|
2074
2086
|
}
|
|
2075
2087
|
}
|
|
2088
|
+
} else if (drawing.type === "fib-retracement") {
|
|
2089
|
+
const first = drawing.points[0];
|
|
2090
|
+
const second = drawing.points[1];
|
|
2091
|
+
if (first && second) {
|
|
2092
|
+
const firstX = xFromDrawingPoint(first);
|
|
2093
|
+
const secondX = xFromDrawingPoint(second);
|
|
2094
|
+
const firstY = yFromPrice(first.price);
|
|
2095
|
+
const secondY = yFromPrice(second.price);
|
|
2096
|
+
const lineLeft = chartLeft;
|
|
2097
|
+
const lineRight = chartRight;
|
|
2098
|
+
const levelLines = FIB_LEVELS.map((level) => {
|
|
2099
|
+
const price = first.price + (second.price - first.price) * (1 - level.ratio);
|
|
2100
|
+
return { ...level, price, y: yFromPrice(price) };
|
|
2101
|
+
});
|
|
2102
|
+
for (let index = 0; index < levelLines.length - 1; index += 1) {
|
|
2103
|
+
const top = levelLines[index];
|
|
2104
|
+
const bottom = levelLines[index + 1];
|
|
2105
|
+
const fillColor = bottom.band ?? top.band;
|
|
2106
|
+
if (!fillColor) continue;
|
|
2107
|
+
const bandTop = Math.min(top.y, bottom.y);
|
|
2108
|
+
const bandBottom = Math.max(top.y, bottom.y);
|
|
2109
|
+
ctx.save();
|
|
2110
|
+
ctx.fillStyle = fillColor;
|
|
2111
|
+
ctx.globalAlpha = draft ? 0.5 : 1;
|
|
2112
|
+
ctx.fillRect(lineLeft, bandTop, lineRight - lineLeft, bandBottom - bandTop);
|
|
2113
|
+
ctx.restore();
|
|
2114
|
+
}
|
|
2115
|
+
ctx.save();
|
|
2116
|
+
ctx.lineWidth = drawing.width;
|
|
2117
|
+
applyDashPattern(drawing.style, dashPatterns.dotted, dashPatterns.dashed);
|
|
2118
|
+
for (const level of levelLines) {
|
|
2119
|
+
ctx.strokeStyle = level.color;
|
|
2120
|
+
ctx.beginPath();
|
|
2121
|
+
ctx.moveTo(crisp(lineLeft), crisp(level.y));
|
|
2122
|
+
ctx.lineTo(crisp(lineRight), crisp(level.y));
|
|
2123
|
+
ctx.stroke();
|
|
2124
|
+
}
|
|
2125
|
+
ctx.restore();
|
|
2126
|
+
ctx.save();
|
|
2127
|
+
ctx.strokeStyle = "rgba(148,163,184,0.7)";
|
|
2128
|
+
ctx.setLineDash([4, 4]);
|
|
2129
|
+
ctx.lineWidth = 1;
|
|
2130
|
+
ctx.beginPath();
|
|
2131
|
+
ctx.moveTo(firstX, firstY);
|
|
2132
|
+
ctx.lineTo(secondX, secondY);
|
|
2133
|
+
ctx.stroke();
|
|
2134
|
+
ctx.restore();
|
|
2135
|
+
drawDrawingHandle(firstX, firstY, drawing.color);
|
|
2136
|
+
drawDrawingHandle(secondX, secondY, drawing.color);
|
|
2137
|
+
const prevFont = ctx.font;
|
|
2138
|
+
ctx.font = `500 11px ${mergedOptions.fontFamily}`;
|
|
2139
|
+
for (const level of levelLines) {
|
|
2140
|
+
const labelText = `${level.ratio} (${formatPrice(level.price)})`;
|
|
2141
|
+
const textWidth = ctx.measureText(labelText).width;
|
|
2142
|
+
const padding = 4;
|
|
2143
|
+
const bgX = lineLeft + 4;
|
|
2144
|
+
const bgY = level.y - 9;
|
|
2145
|
+
ctx.fillStyle = mergedOptions.backgroundColor;
|
|
2146
|
+
fillRoundedRect(bgX, bgY, textWidth + padding * 2, 16, 3);
|
|
2147
|
+
ctx.fillStyle = level.color;
|
|
2148
|
+
ctx.textAlign = "left";
|
|
2149
|
+
ctx.textBaseline = "middle";
|
|
2150
|
+
ctx.fillText(labelText, bgX + padding, bgY + 8);
|
|
2151
|
+
}
|
|
2152
|
+
ctx.font = prevFont;
|
|
2153
|
+
}
|
|
2076
2154
|
}
|
|
2077
2155
|
ctx.restore();
|
|
2078
2156
|
};
|
|
@@ -3159,6 +3237,28 @@ function createChart(element, options = {}) {
|
|
|
3159
3237
|
if (distanceToSegment(x, y, x1, y1, x2, y2) <= 6) {
|
|
3160
3238
|
return { drawing, target: "line" };
|
|
3161
3239
|
}
|
|
3240
|
+
} else if (drawing.type === "fib-retracement") {
|
|
3241
|
+
const first = drawing.points[0];
|
|
3242
|
+
const second = drawing.points[1];
|
|
3243
|
+
if (!first || !second) continue;
|
|
3244
|
+
const x1 = canvasXFromDrawingPoint(first);
|
|
3245
|
+
const y1 = canvasYFromDrawingPrice(first.price);
|
|
3246
|
+
const x2 = canvasXFromDrawingPoint(second);
|
|
3247
|
+
const y2 = canvasYFromDrawingPrice(second.price);
|
|
3248
|
+
if (Math.hypot(x - x1, y - y1) <= 9) {
|
|
3249
|
+
return { drawing, target: "handle", pointIndex: 0 };
|
|
3250
|
+
}
|
|
3251
|
+
if (Math.hypot(x - x2, y - y2) <= 9) {
|
|
3252
|
+
return { drawing, target: "handle", pointIndex: 1 };
|
|
3253
|
+
}
|
|
3254
|
+
const fibRatios = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1, 1.618];
|
|
3255
|
+
for (const ratio of fibRatios) {
|
|
3256
|
+
const price = first.price + (second.price - first.price) * (1 - ratio);
|
|
3257
|
+
const lineY = canvasYFromDrawingPrice(price);
|
|
3258
|
+
if (Math.abs(y - lineY) <= 5) {
|
|
3259
|
+
return { drawing, target: "line" };
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3162
3262
|
}
|
|
3163
3263
|
}
|
|
3164
3264
|
return null;
|
|
@@ -3224,13 +3324,14 @@ function createChart(element, options = {}) {
|
|
|
3224
3324
|
return false;
|
|
3225
3325
|
}
|
|
3226
3326
|
if (activeDrawingTool === "horizontal-line") {
|
|
3327
|
+
const defaults = getDrawingToolDefaults("horizontal-line");
|
|
3227
3328
|
drawings.push(
|
|
3228
3329
|
normalizeDrawingState({
|
|
3229
3330
|
type: "horizontal-line",
|
|
3230
3331
|
points: [point],
|
|
3231
|
-
color: "#38bdf8",
|
|
3232
|
-
style: "
|
|
3233
|
-
width: 1
|
|
3332
|
+
color: defaults.color ?? "#38bdf8",
|
|
3333
|
+
style: defaults.style ?? "solid",
|
|
3334
|
+
width: defaults.width ?? 1
|
|
3234
3335
|
})
|
|
3235
3336
|
);
|
|
3236
3337
|
emitDrawingsChange();
|
|
@@ -3250,18 +3351,50 @@ function createChart(element, options = {}) {
|
|
|
3250
3351
|
draw();
|
|
3251
3352
|
return true;
|
|
3252
3353
|
}
|
|
3354
|
+
const defaults = getDrawingToolDefaults("trendline");
|
|
3253
3355
|
draftDrawing = normalizeDrawingState({
|
|
3254
3356
|
type: "trendline",
|
|
3255
3357
|
points: [point, point],
|
|
3256
|
-
color: "#2563eb",
|
|
3257
|
-
style: "solid",
|
|
3258
|
-
width: 2
|
|
3358
|
+
color: defaults.color ?? "#2563eb",
|
|
3359
|
+
style: defaults.style ?? "solid",
|
|
3360
|
+
width: defaults.width ?? 2
|
|
3361
|
+
});
|
|
3362
|
+
draw();
|
|
3363
|
+
return true;
|
|
3364
|
+
}
|
|
3365
|
+
if (activeDrawingTool === "fib-retracement") {
|
|
3366
|
+
if (draftDrawing?.type === "fib-retracement") {
|
|
3367
|
+
const completed = normalizeDrawingState({
|
|
3368
|
+
...serializeDrawing(draftDrawing),
|
|
3369
|
+
points: [draftDrawing.points[0], point]
|
|
3370
|
+
});
|
|
3371
|
+
drawings.push(completed);
|
|
3372
|
+
draftDrawing = null;
|
|
3373
|
+
activeDrawingTool = null;
|
|
3374
|
+
emitDrawingsChange();
|
|
3375
|
+
draw();
|
|
3376
|
+
return true;
|
|
3377
|
+
}
|
|
3378
|
+
const defaults = getDrawingToolDefaults("fib-retracement");
|
|
3379
|
+
draftDrawing = normalizeDrawingState({
|
|
3380
|
+
type: "fib-retracement",
|
|
3381
|
+
points: [point, point],
|
|
3382
|
+
color: defaults.color ?? "#2563eb",
|
|
3383
|
+
style: defaults.style ?? "solid",
|
|
3384
|
+
width: defaults.width ?? 1
|
|
3259
3385
|
});
|
|
3260
3386
|
draw();
|
|
3261
3387
|
return true;
|
|
3262
3388
|
}
|
|
3263
3389
|
return false;
|
|
3264
3390
|
};
|
|
3391
|
+
const setDrawingDefaults = (tool, defaults) => {
|
|
3392
|
+
if (defaults === null) {
|
|
3393
|
+
drawingToolDefaults.delete(tool);
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
drawingToolDefaults.set(tool, { ...defaults });
|
|
3397
|
+
};
|
|
3265
3398
|
const updateDrawingDrag = (x, y) => {
|
|
3266
3399
|
if (!drawingDragState) {
|
|
3267
3400
|
return false;
|
|
@@ -3495,7 +3628,7 @@ function createChart(element, options = {}) {
|
|
|
3495
3628
|
setCrosshairPoint(null);
|
|
3496
3629
|
return;
|
|
3497
3630
|
}
|
|
3498
|
-
if (draftDrawing && activeDrawingTool === "trendline") {
|
|
3631
|
+
if (draftDrawing && (activeDrawingTool === "trendline" || activeDrawingTool === "fib-retracement")) {
|
|
3499
3632
|
const nextPoint = drawingPointFromCanvas(point.x, point.y);
|
|
3500
3633
|
if (nextPoint) {
|
|
3501
3634
|
draftDrawing = {
|
|
@@ -4110,6 +4243,7 @@ function createChart(element, options = {}) {
|
|
|
4110
4243
|
onDrawingsChange,
|
|
4111
4244
|
onDrawingSelect,
|
|
4112
4245
|
onDrawingHover,
|
|
4246
|
+
setDrawingDefaults,
|
|
4113
4247
|
setDoubleClickEnabled,
|
|
4114
4248
|
setDoubleClickAction,
|
|
4115
4249
|
registerIndicator,
|