hyperprop-charting-library 0.1.17 → 0.1.19
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 +78 -27
- package/dist/hyperprop-charting-library.d.ts +2 -4
- package/dist/hyperprop-charting-library.js +78 -27
- package/dist/index.cjs +78 -27
- package/dist/index.d.cts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +78 -27
- package/docs/API.md +7 -7
- package/docs/RECIPES.md +2 -3
- package/package.json +1 -1
|
@@ -53,15 +53,12 @@ var DEFAULT_CROSSHAIR_OPTIONS = {
|
|
|
53
53
|
labelBorderWidth: 1,
|
|
54
54
|
labelBorderStyle: "solid",
|
|
55
55
|
showPriceActionButton: false,
|
|
56
|
+
priceActionButtonIcon: "plusThin",
|
|
56
57
|
priceActionButtonText: "+",
|
|
57
|
-
priceActionButtonSize:
|
|
58
|
-
priceActionButtonGap:
|
|
59
|
-
priceActionButtonBackgroundColor: "#1f2937",
|
|
60
|
-
priceActionButtonTextColor: "#e2e8f0",
|
|
61
|
-
priceActionButtonBorderColor: "#475569",
|
|
62
|
-
priceActionButtonBorderWidth: 1,
|
|
58
|
+
priceActionButtonSize: 16,
|
|
59
|
+
priceActionButtonGap: 4,
|
|
63
60
|
priceActionButtonRounded: true,
|
|
64
|
-
priceActionButtonBorderRadius:
|
|
61
|
+
priceActionButtonBorderRadius: 8
|
|
65
62
|
};
|
|
66
63
|
var DEFAULT_WATERMARK_OPTIONS = {
|
|
67
64
|
visible: false,
|
|
@@ -107,6 +104,7 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
|
|
|
107
104
|
labelBorderRadius: 3,
|
|
108
105
|
showCloseButton: true,
|
|
109
106
|
widgetPosition: "left",
|
|
107
|
+
widgetPaddingRight: 10,
|
|
110
108
|
draggable: false,
|
|
111
109
|
actionButtonAction: "execute",
|
|
112
110
|
actionButtonTextColor: "#dbeafe",
|
|
@@ -633,7 +631,16 @@ function createChart(element, options = {}) {
|
|
|
633
631
|
const closeWidth = showCloseButton ? 24 : 0;
|
|
634
632
|
const mainWidgetWidth = qtyWidth + centerWidth + closeWidth;
|
|
635
633
|
const totalWidth = mainWidgetWidth + actionButtonsGap + actionButtonsTotalWidth;
|
|
636
|
-
const
|
|
634
|
+
const crosshair = { ...DEFAULT_CROSSHAIR_OPTIONS, ...mergedOptions.crosshair ?? {} };
|
|
635
|
+
const crosshairActionInset = crosshair.visible && crosshair.showPriceLabel && crosshair.showPriceActionButton ? Math.max(
|
|
636
|
+
0,
|
|
637
|
+
Math.round(crosshair.priceActionButtonGap) + (clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4)) + 10) - 4
|
|
638
|
+
) + 6 : 0;
|
|
639
|
+
const rightMarginInsideChart = Math.max(
|
|
640
|
+
0,
|
|
641
|
+
mergedLine.widgetPaddingRight,
|
|
642
|
+
crosshairActionInset
|
|
643
|
+
);
|
|
637
644
|
const maxWidgetX = chartRight - totalWidth - rightMarginInsideChart;
|
|
638
645
|
const leftWidgetXBase = chartLeft + 8;
|
|
639
646
|
let leftWidgetX = leftWidgetXBase;
|
|
@@ -1151,35 +1158,79 @@ function createChart(element, options = {}) {
|
|
|
1151
1158
|
strokeCrosshairLabel(priceX, priceY, priceWidth);
|
|
1152
1159
|
drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
|
|
1153
1160
|
if (crosshair.showPriceActionButton) {
|
|
1154
|
-
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12,
|
|
1161
|
+
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
|
|
1155
1162
|
const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
|
|
1156
|
-
const
|
|
1163
|
+
const containerPaddingX = 5;
|
|
1164
|
+
const containerWidth = buttonSize + containerPaddingX * 2;
|
|
1165
|
+
const containerX = priceX - buttonGap - containerWidth;
|
|
1166
|
+
const containerY = priceY;
|
|
1167
|
+
const buttonX = containerX + containerPaddingX;
|
|
1157
1168
|
const buttonY = priceY + (labelHeight - buttonSize) / 2;
|
|
1158
1169
|
const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
|
|
1159
|
-
const buttonBorderWidth = Math.max(
|
|
1160
|
-
|
|
1161
|
-
|
|
1170
|
+
const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
|
|
1171
|
+
const buttonCenterX = buttonX + buttonSize / 2;
|
|
1172
|
+
const buttonCenterY = buttonY + buttonSize / 2;
|
|
1173
|
+
const containerRadius = labelRadius;
|
|
1174
|
+
ctx.fillStyle = labelBackground;
|
|
1175
|
+
fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1176
|
+
if (labelBorderWidth > 0) {
|
|
1177
|
+
ctx.save();
|
|
1178
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1179
|
+
ctx.lineWidth = labelBorderWidth;
|
|
1180
|
+
ctx.setLineDash([]);
|
|
1181
|
+
strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1182
|
+
ctx.restore();
|
|
1183
|
+
}
|
|
1162
1184
|
if (buttonBorderWidth > 0) {
|
|
1163
1185
|
ctx.save();
|
|
1164
|
-
ctx.strokeStyle =
|
|
1186
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1165
1187
|
ctx.lineWidth = buttonBorderWidth;
|
|
1166
1188
|
ctx.setLineDash([]);
|
|
1167
|
-
|
|
1189
|
+
if (crosshair.priceActionButtonRounded) {
|
|
1190
|
+
ctx.beginPath();
|
|
1191
|
+
ctx.arc(
|
|
1192
|
+
buttonCenterX,
|
|
1193
|
+
buttonCenterY,
|
|
1194
|
+
Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
|
|
1195
|
+
0,
|
|
1196
|
+
Math.PI * 2
|
|
1197
|
+
);
|
|
1198
|
+
ctx.stroke();
|
|
1199
|
+
} else {
|
|
1200
|
+
strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
|
|
1201
|
+
}
|
|
1202
|
+
ctx.restore();
|
|
1203
|
+
}
|
|
1204
|
+
if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
|
|
1205
|
+
const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
|
|
1206
|
+
const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
|
|
1207
|
+
ctx.save();
|
|
1208
|
+
ctx.strokeStyle = labelTextColor;
|
|
1209
|
+
ctx.lineWidth = plusThickness;
|
|
1210
|
+
ctx.lineCap = "round";
|
|
1211
|
+
ctx.setLineDash([]);
|
|
1212
|
+
ctx.beginPath();
|
|
1213
|
+
ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
|
|
1214
|
+
ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
|
|
1215
|
+
ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
|
|
1216
|
+
ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
|
|
1217
|
+
ctx.stroke();
|
|
1168
1218
|
ctx.restore();
|
|
1219
|
+
} else {
|
|
1220
|
+
drawText(
|
|
1221
|
+
crosshair.priceActionButtonText,
|
|
1222
|
+
buttonCenterX,
|
|
1223
|
+
buttonCenterY,
|
|
1224
|
+
"center",
|
|
1225
|
+
"middle",
|
|
1226
|
+
labelTextColor
|
|
1227
|
+
);
|
|
1169
1228
|
}
|
|
1170
|
-
drawText(
|
|
1171
|
-
crosshair.priceActionButtonText,
|
|
1172
|
-
buttonX + buttonSize / 2,
|
|
1173
|
-
buttonY + buttonSize / 2,
|
|
1174
|
-
"center",
|
|
1175
|
-
"middle",
|
|
1176
|
-
crosshair.priceActionButtonTextColor
|
|
1177
|
-
);
|
|
1178
1229
|
crosshairPriceActionRegion = {
|
|
1179
|
-
x:
|
|
1180
|
-
y:
|
|
1181
|
-
width:
|
|
1182
|
-
height:
|
|
1230
|
+
x: containerX,
|
|
1231
|
+
y: containerY,
|
|
1232
|
+
width: containerWidth,
|
|
1233
|
+
height: labelHeight,
|
|
1183
1234
|
price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
|
|
1184
1235
|
};
|
|
1185
1236
|
}
|
|
@@ -72,13 +72,10 @@ interface CrosshairOptions {
|
|
|
72
72
|
labelBorderWidth?: number;
|
|
73
73
|
labelBorderStyle?: "solid" | "dotted" | "dashed";
|
|
74
74
|
showPriceActionButton?: boolean;
|
|
75
|
+
priceActionButtonIcon?: "plus" | "plusThin" | "text";
|
|
75
76
|
priceActionButtonText?: string;
|
|
76
77
|
priceActionButtonSize?: number;
|
|
77
78
|
priceActionButtonGap?: number;
|
|
78
|
-
priceActionButtonBackgroundColor?: string;
|
|
79
|
-
priceActionButtonTextColor?: string;
|
|
80
|
-
priceActionButtonBorderColor?: string;
|
|
81
|
-
priceActionButtonBorderWidth?: number;
|
|
82
79
|
priceActionButtonRounded?: boolean;
|
|
83
80
|
priceActionButtonBorderRadius?: number;
|
|
84
81
|
}
|
|
@@ -129,6 +126,7 @@ interface OrderLineOptions {
|
|
|
129
126
|
labelBorderRadius?: number;
|
|
130
127
|
showCloseButton?: boolean;
|
|
131
128
|
widgetPosition?: "left" | "center" | "right";
|
|
129
|
+
widgetPaddingRight?: number;
|
|
132
130
|
draggable?: boolean;
|
|
133
131
|
actionButtonText?: string;
|
|
134
132
|
actionButtonAction?: "execute" | "cancel" | "close" | string;
|
|
@@ -29,15 +29,12 @@ var DEFAULT_CROSSHAIR_OPTIONS = {
|
|
|
29
29
|
labelBorderWidth: 1,
|
|
30
30
|
labelBorderStyle: "solid",
|
|
31
31
|
showPriceActionButton: false,
|
|
32
|
+
priceActionButtonIcon: "plusThin",
|
|
32
33
|
priceActionButtonText: "+",
|
|
33
|
-
priceActionButtonSize:
|
|
34
|
-
priceActionButtonGap:
|
|
35
|
-
priceActionButtonBackgroundColor: "#1f2937",
|
|
36
|
-
priceActionButtonTextColor: "#e2e8f0",
|
|
37
|
-
priceActionButtonBorderColor: "#475569",
|
|
38
|
-
priceActionButtonBorderWidth: 1,
|
|
34
|
+
priceActionButtonSize: 16,
|
|
35
|
+
priceActionButtonGap: 4,
|
|
39
36
|
priceActionButtonRounded: true,
|
|
40
|
-
priceActionButtonBorderRadius:
|
|
37
|
+
priceActionButtonBorderRadius: 8
|
|
41
38
|
};
|
|
42
39
|
var DEFAULT_WATERMARK_OPTIONS = {
|
|
43
40
|
visible: false,
|
|
@@ -83,6 +80,7 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
|
|
|
83
80
|
labelBorderRadius: 3,
|
|
84
81
|
showCloseButton: true,
|
|
85
82
|
widgetPosition: "left",
|
|
83
|
+
widgetPaddingRight: 10,
|
|
86
84
|
draggable: false,
|
|
87
85
|
actionButtonAction: "execute",
|
|
88
86
|
actionButtonTextColor: "#dbeafe",
|
|
@@ -609,7 +607,16 @@ function createChart(element, options = {}) {
|
|
|
609
607
|
const closeWidth = showCloseButton ? 24 : 0;
|
|
610
608
|
const mainWidgetWidth = qtyWidth + centerWidth + closeWidth;
|
|
611
609
|
const totalWidth = mainWidgetWidth + actionButtonsGap + actionButtonsTotalWidth;
|
|
612
|
-
const
|
|
610
|
+
const crosshair = { ...DEFAULT_CROSSHAIR_OPTIONS, ...mergedOptions.crosshair ?? {} };
|
|
611
|
+
const crosshairActionInset = crosshair.visible && crosshair.showPriceLabel && crosshair.showPriceActionButton ? Math.max(
|
|
612
|
+
0,
|
|
613
|
+
Math.round(crosshair.priceActionButtonGap) + (clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4)) + 10) - 4
|
|
614
|
+
) + 6 : 0;
|
|
615
|
+
const rightMarginInsideChart = Math.max(
|
|
616
|
+
0,
|
|
617
|
+
mergedLine.widgetPaddingRight,
|
|
618
|
+
crosshairActionInset
|
|
619
|
+
);
|
|
613
620
|
const maxWidgetX = chartRight - totalWidth - rightMarginInsideChart;
|
|
614
621
|
const leftWidgetXBase = chartLeft + 8;
|
|
615
622
|
let leftWidgetX = leftWidgetXBase;
|
|
@@ -1127,35 +1134,79 @@ function createChart(element, options = {}) {
|
|
|
1127
1134
|
strokeCrosshairLabel(priceX, priceY, priceWidth);
|
|
1128
1135
|
drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
|
|
1129
1136
|
if (crosshair.showPriceActionButton) {
|
|
1130
|
-
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12,
|
|
1137
|
+
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
|
|
1131
1138
|
const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
|
|
1132
|
-
const
|
|
1139
|
+
const containerPaddingX = 5;
|
|
1140
|
+
const containerWidth = buttonSize + containerPaddingX * 2;
|
|
1141
|
+
const containerX = priceX - buttonGap - containerWidth;
|
|
1142
|
+
const containerY = priceY;
|
|
1143
|
+
const buttonX = containerX + containerPaddingX;
|
|
1133
1144
|
const buttonY = priceY + (labelHeight - buttonSize) / 2;
|
|
1134
1145
|
const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
|
|
1135
|
-
const buttonBorderWidth = Math.max(
|
|
1136
|
-
|
|
1137
|
-
|
|
1146
|
+
const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
|
|
1147
|
+
const buttonCenterX = buttonX + buttonSize / 2;
|
|
1148
|
+
const buttonCenterY = buttonY + buttonSize / 2;
|
|
1149
|
+
const containerRadius = labelRadius;
|
|
1150
|
+
ctx.fillStyle = labelBackground;
|
|
1151
|
+
fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1152
|
+
if (labelBorderWidth > 0) {
|
|
1153
|
+
ctx.save();
|
|
1154
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1155
|
+
ctx.lineWidth = labelBorderWidth;
|
|
1156
|
+
ctx.setLineDash([]);
|
|
1157
|
+
strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1158
|
+
ctx.restore();
|
|
1159
|
+
}
|
|
1138
1160
|
if (buttonBorderWidth > 0) {
|
|
1139
1161
|
ctx.save();
|
|
1140
|
-
ctx.strokeStyle =
|
|
1162
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1141
1163
|
ctx.lineWidth = buttonBorderWidth;
|
|
1142
1164
|
ctx.setLineDash([]);
|
|
1143
|
-
|
|
1165
|
+
if (crosshair.priceActionButtonRounded) {
|
|
1166
|
+
ctx.beginPath();
|
|
1167
|
+
ctx.arc(
|
|
1168
|
+
buttonCenterX,
|
|
1169
|
+
buttonCenterY,
|
|
1170
|
+
Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
|
|
1171
|
+
0,
|
|
1172
|
+
Math.PI * 2
|
|
1173
|
+
);
|
|
1174
|
+
ctx.stroke();
|
|
1175
|
+
} else {
|
|
1176
|
+
strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
|
|
1177
|
+
}
|
|
1178
|
+
ctx.restore();
|
|
1179
|
+
}
|
|
1180
|
+
if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
|
|
1181
|
+
const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
|
|
1182
|
+
const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
|
|
1183
|
+
ctx.save();
|
|
1184
|
+
ctx.strokeStyle = labelTextColor;
|
|
1185
|
+
ctx.lineWidth = plusThickness;
|
|
1186
|
+
ctx.lineCap = "round";
|
|
1187
|
+
ctx.setLineDash([]);
|
|
1188
|
+
ctx.beginPath();
|
|
1189
|
+
ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
|
|
1190
|
+
ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
|
|
1191
|
+
ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
|
|
1192
|
+
ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
|
|
1193
|
+
ctx.stroke();
|
|
1144
1194
|
ctx.restore();
|
|
1195
|
+
} else {
|
|
1196
|
+
drawText(
|
|
1197
|
+
crosshair.priceActionButtonText,
|
|
1198
|
+
buttonCenterX,
|
|
1199
|
+
buttonCenterY,
|
|
1200
|
+
"center",
|
|
1201
|
+
"middle",
|
|
1202
|
+
labelTextColor
|
|
1203
|
+
);
|
|
1145
1204
|
}
|
|
1146
|
-
drawText(
|
|
1147
|
-
crosshair.priceActionButtonText,
|
|
1148
|
-
buttonX + buttonSize / 2,
|
|
1149
|
-
buttonY + buttonSize / 2,
|
|
1150
|
-
"center",
|
|
1151
|
-
"middle",
|
|
1152
|
-
crosshair.priceActionButtonTextColor
|
|
1153
|
-
);
|
|
1154
1205
|
crosshairPriceActionRegion = {
|
|
1155
|
-
x:
|
|
1156
|
-
y:
|
|
1157
|
-
width:
|
|
1158
|
-
height:
|
|
1206
|
+
x: containerX,
|
|
1207
|
+
y: containerY,
|
|
1208
|
+
width: containerWidth,
|
|
1209
|
+
height: labelHeight,
|
|
1159
1210
|
price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
|
|
1160
1211
|
};
|
|
1161
1212
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -53,15 +53,12 @@ var DEFAULT_CROSSHAIR_OPTIONS = {
|
|
|
53
53
|
labelBorderWidth: 1,
|
|
54
54
|
labelBorderStyle: "solid",
|
|
55
55
|
showPriceActionButton: false,
|
|
56
|
+
priceActionButtonIcon: "plusThin",
|
|
56
57
|
priceActionButtonText: "+",
|
|
57
|
-
priceActionButtonSize:
|
|
58
|
-
priceActionButtonGap:
|
|
59
|
-
priceActionButtonBackgroundColor: "#1f2937",
|
|
60
|
-
priceActionButtonTextColor: "#e2e8f0",
|
|
61
|
-
priceActionButtonBorderColor: "#475569",
|
|
62
|
-
priceActionButtonBorderWidth: 1,
|
|
58
|
+
priceActionButtonSize: 16,
|
|
59
|
+
priceActionButtonGap: 4,
|
|
63
60
|
priceActionButtonRounded: true,
|
|
64
|
-
priceActionButtonBorderRadius:
|
|
61
|
+
priceActionButtonBorderRadius: 8
|
|
65
62
|
};
|
|
66
63
|
var DEFAULT_WATERMARK_OPTIONS = {
|
|
67
64
|
visible: false,
|
|
@@ -107,6 +104,7 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
|
|
|
107
104
|
labelBorderRadius: 3,
|
|
108
105
|
showCloseButton: true,
|
|
109
106
|
widgetPosition: "left",
|
|
107
|
+
widgetPaddingRight: 10,
|
|
110
108
|
draggable: false,
|
|
111
109
|
actionButtonAction: "execute",
|
|
112
110
|
actionButtonTextColor: "#dbeafe",
|
|
@@ -633,7 +631,16 @@ function createChart(element, options = {}) {
|
|
|
633
631
|
const closeWidth = showCloseButton ? 24 : 0;
|
|
634
632
|
const mainWidgetWidth = qtyWidth + centerWidth + closeWidth;
|
|
635
633
|
const totalWidth = mainWidgetWidth + actionButtonsGap + actionButtonsTotalWidth;
|
|
636
|
-
const
|
|
634
|
+
const crosshair = { ...DEFAULT_CROSSHAIR_OPTIONS, ...mergedOptions.crosshair ?? {} };
|
|
635
|
+
const crosshairActionInset = crosshair.visible && crosshair.showPriceLabel && crosshair.showPriceActionButton ? Math.max(
|
|
636
|
+
0,
|
|
637
|
+
Math.round(crosshair.priceActionButtonGap) + (clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4)) + 10) - 4
|
|
638
|
+
) + 6 : 0;
|
|
639
|
+
const rightMarginInsideChart = Math.max(
|
|
640
|
+
0,
|
|
641
|
+
mergedLine.widgetPaddingRight,
|
|
642
|
+
crosshairActionInset
|
|
643
|
+
);
|
|
637
644
|
const maxWidgetX = chartRight - totalWidth - rightMarginInsideChart;
|
|
638
645
|
const leftWidgetXBase = chartLeft + 8;
|
|
639
646
|
let leftWidgetX = leftWidgetXBase;
|
|
@@ -1151,35 +1158,79 @@ function createChart(element, options = {}) {
|
|
|
1151
1158
|
strokeCrosshairLabel(priceX, priceY, priceWidth);
|
|
1152
1159
|
drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
|
|
1153
1160
|
if (crosshair.showPriceActionButton) {
|
|
1154
|
-
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12,
|
|
1161
|
+
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
|
|
1155
1162
|
const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
|
|
1156
|
-
const
|
|
1163
|
+
const containerPaddingX = 5;
|
|
1164
|
+
const containerWidth = buttonSize + containerPaddingX * 2;
|
|
1165
|
+
const containerX = priceX - buttonGap - containerWidth;
|
|
1166
|
+
const containerY = priceY;
|
|
1167
|
+
const buttonX = containerX + containerPaddingX;
|
|
1157
1168
|
const buttonY = priceY + (labelHeight - buttonSize) / 2;
|
|
1158
1169
|
const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
|
|
1159
|
-
const buttonBorderWidth = Math.max(
|
|
1160
|
-
|
|
1161
|
-
|
|
1170
|
+
const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
|
|
1171
|
+
const buttonCenterX = buttonX + buttonSize / 2;
|
|
1172
|
+
const buttonCenterY = buttonY + buttonSize / 2;
|
|
1173
|
+
const containerRadius = labelRadius;
|
|
1174
|
+
ctx.fillStyle = labelBackground;
|
|
1175
|
+
fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1176
|
+
if (labelBorderWidth > 0) {
|
|
1177
|
+
ctx.save();
|
|
1178
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1179
|
+
ctx.lineWidth = labelBorderWidth;
|
|
1180
|
+
ctx.setLineDash([]);
|
|
1181
|
+
strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1182
|
+
ctx.restore();
|
|
1183
|
+
}
|
|
1162
1184
|
if (buttonBorderWidth > 0) {
|
|
1163
1185
|
ctx.save();
|
|
1164
|
-
ctx.strokeStyle =
|
|
1186
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1165
1187
|
ctx.lineWidth = buttonBorderWidth;
|
|
1166
1188
|
ctx.setLineDash([]);
|
|
1167
|
-
|
|
1189
|
+
if (crosshair.priceActionButtonRounded) {
|
|
1190
|
+
ctx.beginPath();
|
|
1191
|
+
ctx.arc(
|
|
1192
|
+
buttonCenterX,
|
|
1193
|
+
buttonCenterY,
|
|
1194
|
+
Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
|
|
1195
|
+
0,
|
|
1196
|
+
Math.PI * 2
|
|
1197
|
+
);
|
|
1198
|
+
ctx.stroke();
|
|
1199
|
+
} else {
|
|
1200
|
+
strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
|
|
1201
|
+
}
|
|
1202
|
+
ctx.restore();
|
|
1203
|
+
}
|
|
1204
|
+
if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
|
|
1205
|
+
const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
|
|
1206
|
+
const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
|
|
1207
|
+
ctx.save();
|
|
1208
|
+
ctx.strokeStyle = labelTextColor;
|
|
1209
|
+
ctx.lineWidth = plusThickness;
|
|
1210
|
+
ctx.lineCap = "round";
|
|
1211
|
+
ctx.setLineDash([]);
|
|
1212
|
+
ctx.beginPath();
|
|
1213
|
+
ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
|
|
1214
|
+
ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
|
|
1215
|
+
ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
|
|
1216
|
+
ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
|
|
1217
|
+
ctx.stroke();
|
|
1168
1218
|
ctx.restore();
|
|
1219
|
+
} else {
|
|
1220
|
+
drawText(
|
|
1221
|
+
crosshair.priceActionButtonText,
|
|
1222
|
+
buttonCenterX,
|
|
1223
|
+
buttonCenterY,
|
|
1224
|
+
"center",
|
|
1225
|
+
"middle",
|
|
1226
|
+
labelTextColor
|
|
1227
|
+
);
|
|
1169
1228
|
}
|
|
1170
|
-
drawText(
|
|
1171
|
-
crosshair.priceActionButtonText,
|
|
1172
|
-
buttonX + buttonSize / 2,
|
|
1173
|
-
buttonY + buttonSize / 2,
|
|
1174
|
-
"center",
|
|
1175
|
-
"middle",
|
|
1176
|
-
crosshair.priceActionButtonTextColor
|
|
1177
|
-
);
|
|
1178
1229
|
crosshairPriceActionRegion = {
|
|
1179
|
-
x:
|
|
1180
|
-
y:
|
|
1181
|
-
width:
|
|
1182
|
-
height:
|
|
1230
|
+
x: containerX,
|
|
1231
|
+
y: containerY,
|
|
1232
|
+
width: containerWidth,
|
|
1233
|
+
height: labelHeight,
|
|
1183
1234
|
price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
|
|
1184
1235
|
};
|
|
1185
1236
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -72,13 +72,10 @@ interface CrosshairOptions {
|
|
|
72
72
|
labelBorderWidth?: number;
|
|
73
73
|
labelBorderStyle?: "solid" | "dotted" | "dashed";
|
|
74
74
|
showPriceActionButton?: boolean;
|
|
75
|
+
priceActionButtonIcon?: "plus" | "plusThin" | "text";
|
|
75
76
|
priceActionButtonText?: string;
|
|
76
77
|
priceActionButtonSize?: number;
|
|
77
78
|
priceActionButtonGap?: number;
|
|
78
|
-
priceActionButtonBackgroundColor?: string;
|
|
79
|
-
priceActionButtonTextColor?: string;
|
|
80
|
-
priceActionButtonBorderColor?: string;
|
|
81
|
-
priceActionButtonBorderWidth?: number;
|
|
82
79
|
priceActionButtonRounded?: boolean;
|
|
83
80
|
priceActionButtonBorderRadius?: number;
|
|
84
81
|
}
|
|
@@ -129,6 +126,7 @@ interface OrderLineOptions {
|
|
|
129
126
|
labelBorderRadius?: number;
|
|
130
127
|
showCloseButton?: boolean;
|
|
131
128
|
widgetPosition?: "left" | "center" | "right";
|
|
129
|
+
widgetPaddingRight?: number;
|
|
132
130
|
draggable?: boolean;
|
|
133
131
|
actionButtonText?: string;
|
|
134
132
|
actionButtonAction?: "execute" | "cancel" | "close" | string;
|
package/dist/index.d.ts
CHANGED
|
@@ -72,13 +72,10 @@ interface CrosshairOptions {
|
|
|
72
72
|
labelBorderWidth?: number;
|
|
73
73
|
labelBorderStyle?: "solid" | "dotted" | "dashed";
|
|
74
74
|
showPriceActionButton?: boolean;
|
|
75
|
+
priceActionButtonIcon?: "plus" | "plusThin" | "text";
|
|
75
76
|
priceActionButtonText?: string;
|
|
76
77
|
priceActionButtonSize?: number;
|
|
77
78
|
priceActionButtonGap?: number;
|
|
78
|
-
priceActionButtonBackgroundColor?: string;
|
|
79
|
-
priceActionButtonTextColor?: string;
|
|
80
|
-
priceActionButtonBorderColor?: string;
|
|
81
|
-
priceActionButtonBorderWidth?: number;
|
|
82
79
|
priceActionButtonRounded?: boolean;
|
|
83
80
|
priceActionButtonBorderRadius?: number;
|
|
84
81
|
}
|
|
@@ -129,6 +126,7 @@ interface OrderLineOptions {
|
|
|
129
126
|
labelBorderRadius?: number;
|
|
130
127
|
showCloseButton?: boolean;
|
|
131
128
|
widgetPosition?: "left" | "center" | "right";
|
|
129
|
+
widgetPaddingRight?: number;
|
|
132
130
|
draggable?: boolean;
|
|
133
131
|
actionButtonText?: string;
|
|
134
132
|
actionButtonAction?: "execute" | "cancel" | "close" | string;
|
package/dist/index.js
CHANGED
|
@@ -29,15 +29,12 @@ var DEFAULT_CROSSHAIR_OPTIONS = {
|
|
|
29
29
|
labelBorderWidth: 1,
|
|
30
30
|
labelBorderStyle: "solid",
|
|
31
31
|
showPriceActionButton: false,
|
|
32
|
+
priceActionButtonIcon: "plusThin",
|
|
32
33
|
priceActionButtonText: "+",
|
|
33
|
-
priceActionButtonSize:
|
|
34
|
-
priceActionButtonGap:
|
|
35
|
-
priceActionButtonBackgroundColor: "#1f2937",
|
|
36
|
-
priceActionButtonTextColor: "#e2e8f0",
|
|
37
|
-
priceActionButtonBorderColor: "#475569",
|
|
38
|
-
priceActionButtonBorderWidth: 1,
|
|
34
|
+
priceActionButtonSize: 16,
|
|
35
|
+
priceActionButtonGap: 4,
|
|
39
36
|
priceActionButtonRounded: true,
|
|
40
|
-
priceActionButtonBorderRadius:
|
|
37
|
+
priceActionButtonBorderRadius: 8
|
|
41
38
|
};
|
|
42
39
|
var DEFAULT_WATERMARK_OPTIONS = {
|
|
43
40
|
visible: false,
|
|
@@ -83,6 +80,7 @@ var DEFAULT_ORDER_LINE_OPTIONS = {
|
|
|
83
80
|
labelBorderRadius: 3,
|
|
84
81
|
showCloseButton: true,
|
|
85
82
|
widgetPosition: "left",
|
|
83
|
+
widgetPaddingRight: 10,
|
|
86
84
|
draggable: false,
|
|
87
85
|
actionButtonAction: "execute",
|
|
88
86
|
actionButtonTextColor: "#dbeafe",
|
|
@@ -609,7 +607,16 @@ function createChart(element, options = {}) {
|
|
|
609
607
|
const closeWidth = showCloseButton ? 24 : 0;
|
|
610
608
|
const mainWidgetWidth = qtyWidth + centerWidth + closeWidth;
|
|
611
609
|
const totalWidth = mainWidgetWidth + actionButtonsGap + actionButtonsTotalWidth;
|
|
612
|
-
const
|
|
610
|
+
const crosshair = { ...DEFAULT_CROSSHAIR_OPTIONS, ...mergedOptions.crosshair ?? {} };
|
|
611
|
+
const crosshairActionInset = crosshair.visible && crosshair.showPriceLabel && crosshair.showPriceActionButton ? Math.max(
|
|
612
|
+
0,
|
|
613
|
+
Math.round(crosshair.priceActionButtonGap) + (clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4)) + 10) - 4
|
|
614
|
+
) + 6 : 0;
|
|
615
|
+
const rightMarginInsideChart = Math.max(
|
|
616
|
+
0,
|
|
617
|
+
mergedLine.widgetPaddingRight,
|
|
618
|
+
crosshairActionInset
|
|
619
|
+
);
|
|
613
620
|
const maxWidgetX = chartRight - totalWidth - rightMarginInsideChart;
|
|
614
621
|
const leftWidgetXBase = chartLeft + 8;
|
|
615
622
|
let leftWidgetX = leftWidgetXBase;
|
|
@@ -1127,35 +1134,79 @@ function createChart(element, options = {}) {
|
|
|
1127
1134
|
strokeCrosshairLabel(priceX, priceY, priceWidth);
|
|
1128
1135
|
drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
|
|
1129
1136
|
if (crosshair.showPriceActionButton) {
|
|
1130
|
-
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12,
|
|
1137
|
+
const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
|
|
1131
1138
|
const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
|
|
1132
|
-
const
|
|
1139
|
+
const containerPaddingX = 5;
|
|
1140
|
+
const containerWidth = buttonSize + containerPaddingX * 2;
|
|
1141
|
+
const containerX = priceX - buttonGap - containerWidth;
|
|
1142
|
+
const containerY = priceY;
|
|
1143
|
+
const buttonX = containerX + containerPaddingX;
|
|
1133
1144
|
const buttonY = priceY + (labelHeight - buttonSize) / 2;
|
|
1134
1145
|
const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
|
|
1135
|
-
const buttonBorderWidth = Math.max(
|
|
1136
|
-
|
|
1137
|
-
|
|
1146
|
+
const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
|
|
1147
|
+
const buttonCenterX = buttonX + buttonSize / 2;
|
|
1148
|
+
const buttonCenterY = buttonY + buttonSize / 2;
|
|
1149
|
+
const containerRadius = labelRadius;
|
|
1150
|
+
ctx.fillStyle = labelBackground;
|
|
1151
|
+
fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1152
|
+
if (labelBorderWidth > 0) {
|
|
1153
|
+
ctx.save();
|
|
1154
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1155
|
+
ctx.lineWidth = labelBorderWidth;
|
|
1156
|
+
ctx.setLineDash([]);
|
|
1157
|
+
strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
|
|
1158
|
+
ctx.restore();
|
|
1159
|
+
}
|
|
1138
1160
|
if (buttonBorderWidth > 0) {
|
|
1139
1161
|
ctx.save();
|
|
1140
|
-
ctx.strokeStyle =
|
|
1162
|
+
ctx.strokeStyle = labelBorderColor;
|
|
1141
1163
|
ctx.lineWidth = buttonBorderWidth;
|
|
1142
1164
|
ctx.setLineDash([]);
|
|
1143
|
-
|
|
1165
|
+
if (crosshair.priceActionButtonRounded) {
|
|
1166
|
+
ctx.beginPath();
|
|
1167
|
+
ctx.arc(
|
|
1168
|
+
buttonCenterX,
|
|
1169
|
+
buttonCenterY,
|
|
1170
|
+
Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
|
|
1171
|
+
0,
|
|
1172
|
+
Math.PI * 2
|
|
1173
|
+
);
|
|
1174
|
+
ctx.stroke();
|
|
1175
|
+
} else {
|
|
1176
|
+
strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
|
|
1177
|
+
}
|
|
1178
|
+
ctx.restore();
|
|
1179
|
+
}
|
|
1180
|
+
if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
|
|
1181
|
+
const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
|
|
1182
|
+
const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
|
|
1183
|
+
ctx.save();
|
|
1184
|
+
ctx.strokeStyle = labelTextColor;
|
|
1185
|
+
ctx.lineWidth = plusThickness;
|
|
1186
|
+
ctx.lineCap = "round";
|
|
1187
|
+
ctx.setLineDash([]);
|
|
1188
|
+
ctx.beginPath();
|
|
1189
|
+
ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
|
|
1190
|
+
ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
|
|
1191
|
+
ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
|
|
1192
|
+
ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
|
|
1193
|
+
ctx.stroke();
|
|
1144
1194
|
ctx.restore();
|
|
1195
|
+
} else {
|
|
1196
|
+
drawText(
|
|
1197
|
+
crosshair.priceActionButtonText,
|
|
1198
|
+
buttonCenterX,
|
|
1199
|
+
buttonCenterY,
|
|
1200
|
+
"center",
|
|
1201
|
+
"middle",
|
|
1202
|
+
labelTextColor
|
|
1203
|
+
);
|
|
1145
1204
|
}
|
|
1146
|
-
drawText(
|
|
1147
|
-
crosshair.priceActionButtonText,
|
|
1148
|
-
buttonX + buttonSize / 2,
|
|
1149
|
-
buttonY + buttonSize / 2,
|
|
1150
|
-
"center",
|
|
1151
|
-
"middle",
|
|
1152
|
-
crosshair.priceActionButtonTextColor
|
|
1153
|
-
);
|
|
1154
1205
|
crosshairPriceActionRegion = {
|
|
1155
|
-
x:
|
|
1156
|
-
y:
|
|
1157
|
-
width:
|
|
1158
|
-
height:
|
|
1206
|
+
x: containerX,
|
|
1207
|
+
y: containerY,
|
|
1208
|
+
width: containerWidth,
|
|
1209
|
+
height: labelHeight,
|
|
1159
1210
|
price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
|
|
1160
1211
|
};
|
|
1161
1212
|
}
|
package/docs/API.md
CHANGED
|
@@ -95,15 +95,14 @@ Top-level options:
|
|
|
95
95
|
- `labelBorderWidth` (default `1`)
|
|
96
96
|
- `labelBorderStyle` (`"solid" | "dotted" | "dashed"`, default `"solid"`)
|
|
97
97
|
- `showPriceActionButton` (default `false`)
|
|
98
|
+
- `priceActionButtonIcon` (`"plus" | "plusThin" | "text"`, default `"plusThin"`)
|
|
98
99
|
- `priceActionButtonText` (default `"+"`)
|
|
99
|
-
- `priceActionButtonSize` (default `
|
|
100
|
-
- `priceActionButtonGap` (default `
|
|
101
|
-
- `priceActionButtonBackgroundColor` (default `#1f2937`)
|
|
102
|
-
- `priceActionButtonTextColor` (default `#e2e8f0`)
|
|
103
|
-
- `priceActionButtonBorderColor` (default `#475569`)
|
|
104
|
-
- `priceActionButtonBorderWidth` (default `1`)
|
|
100
|
+
- `priceActionButtonSize` (default `16`)
|
|
101
|
+
- `priceActionButtonGap` (default `4`)
|
|
105
102
|
- `priceActionButtonRounded` (default `true`; set `false` for square corners)
|
|
106
|
-
- `priceActionButtonBorderRadius` (default `
|
|
103
|
+
- `priceActionButtonBorderRadius` (default `8`)
|
|
104
|
+
|
|
105
|
+
Note: the button and its container automatically inherit crosshair label colors/border for a consistent `[button-box][label]` look.
|
|
107
106
|
|
|
108
107
|
### `WatermarkOptions`
|
|
109
108
|
|
|
@@ -206,6 +205,7 @@ Common optional fields:
|
|
|
206
205
|
- `labelBorderRadius?: number` (default `3`)
|
|
207
206
|
- `showCloseButton?: boolean` (default `true`)
|
|
208
207
|
- `widgetPosition?: "left" | "center" | "right"` (default `"left"`)
|
|
208
|
+
- `widgetPaddingRight?: number` (default `10`, extra right margin when `widgetPosition` is `"right"`)
|
|
209
209
|
- `draggable?: boolean` (default `false`)
|
|
210
210
|
|
|
211
211
|
Legacy single action button:
|
package/docs/RECIPES.md
CHANGED
|
@@ -70,7 +70,7 @@ const chart = createChart(root, {
|
|
|
70
70
|
crosshair: {
|
|
71
71
|
showPriceActionButton: true,
|
|
72
72
|
priceActionButtonText: "+",
|
|
73
|
-
priceActionButtonGap:
|
|
73
|
+
priceActionButtonGap: 4
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -86,8 +86,7 @@ Square style example:
|
|
|
86
86
|
const chart = createChart(root, {
|
|
87
87
|
crosshair: {
|
|
88
88
|
showPriceActionButton: true,
|
|
89
|
-
priceActionButtonRounded: false
|
|
90
|
-
priceActionButtonBorderRadius: 0
|
|
89
|
+
priceActionButtonRounded: false
|
|
91
90
|
}
|
|
92
91
|
});
|
|
93
92
|
```
|