hyperprop-charting-library 0.1.17 → 0.1.18

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.
@@ -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: 20,
58
- priceActionButtonGap: 6,
59
- priceActionButtonBackgroundColor: "#1f2937",
60
- priceActionButtonTextColor: "#e2e8f0",
61
- priceActionButtonBorderColor: "#475569",
62
- priceActionButtonBorderWidth: 1,
58
+ priceActionButtonSize: 16,
59
+ priceActionButtonGap: 4,
63
60
  priceActionButtonRounded: true,
64
- priceActionButtonBorderRadius: 3
61
+ priceActionButtonBorderRadius: 8
65
62
  };
66
63
  var DEFAULT_WATERMARK_OPTIONS = {
67
64
  visible: false,
@@ -1151,35 +1148,79 @@ function createChart(element, options = {}) {
1151
1148
  strokeCrosshairLabel(priceX, priceY, priceWidth);
1152
1149
  drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
1153
1150
  if (crosshair.showPriceActionButton) {
1154
- const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, 30);
1151
+ const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
1155
1152
  const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
1156
- const buttonX = priceX - buttonGap - buttonSize;
1153
+ const containerPaddingX = 5;
1154
+ const containerWidth = buttonSize + containerPaddingX * 2;
1155
+ const containerX = priceX - buttonGap - containerWidth;
1156
+ const containerY = priceY;
1157
+ const buttonX = containerX + containerPaddingX;
1157
1158
  const buttonY = priceY + (labelHeight - buttonSize) / 2;
1158
1159
  const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
1159
- const buttonBorderWidth = Math.max(0, Math.round(crosshair.priceActionButtonBorderWidth));
1160
- ctx.fillStyle = crosshair.priceActionButtonBackgroundColor;
1161
- fillRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1160
+ const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
1161
+ const buttonCenterX = buttonX + buttonSize / 2;
1162
+ const buttonCenterY = buttonY + buttonSize / 2;
1163
+ const containerRadius = labelRadius;
1164
+ ctx.fillStyle = labelBackground;
1165
+ fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1166
+ if (labelBorderWidth > 0) {
1167
+ ctx.save();
1168
+ ctx.strokeStyle = labelBorderColor;
1169
+ ctx.lineWidth = labelBorderWidth;
1170
+ ctx.setLineDash([]);
1171
+ strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1172
+ ctx.restore();
1173
+ }
1162
1174
  if (buttonBorderWidth > 0) {
1163
1175
  ctx.save();
1164
- ctx.strokeStyle = crosshair.priceActionButtonBorderColor;
1176
+ ctx.strokeStyle = labelBorderColor;
1165
1177
  ctx.lineWidth = buttonBorderWidth;
1166
1178
  ctx.setLineDash([]);
1167
- strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1179
+ if (crosshair.priceActionButtonRounded) {
1180
+ ctx.beginPath();
1181
+ ctx.arc(
1182
+ buttonCenterX,
1183
+ buttonCenterY,
1184
+ Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
1185
+ 0,
1186
+ Math.PI * 2
1187
+ );
1188
+ ctx.stroke();
1189
+ } else {
1190
+ strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1191
+ }
1192
+ ctx.restore();
1193
+ }
1194
+ if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
1195
+ const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
1196
+ const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
1197
+ ctx.save();
1198
+ ctx.strokeStyle = labelTextColor;
1199
+ ctx.lineWidth = plusThickness;
1200
+ ctx.lineCap = "round";
1201
+ ctx.setLineDash([]);
1202
+ ctx.beginPath();
1203
+ ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
1204
+ ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
1205
+ ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
1206
+ ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
1207
+ ctx.stroke();
1168
1208
  ctx.restore();
1209
+ } else {
1210
+ drawText(
1211
+ crosshair.priceActionButtonText,
1212
+ buttonCenterX,
1213
+ buttonCenterY,
1214
+ "center",
1215
+ "middle",
1216
+ labelTextColor
1217
+ );
1169
1218
  }
1170
- drawText(
1171
- crosshair.priceActionButtonText,
1172
- buttonX + buttonSize / 2,
1173
- buttonY + buttonSize / 2,
1174
- "center",
1175
- "middle",
1176
- crosshair.priceActionButtonTextColor
1177
- );
1178
1219
  crosshairPriceActionRegion = {
1179
- x: buttonX,
1180
- y: buttonY,
1181
- width: buttonSize,
1182
- height: buttonSize,
1220
+ x: containerX,
1221
+ y: containerY,
1222
+ width: containerWidth,
1223
+ height: labelHeight,
1183
1224
  price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
1184
1225
  };
1185
1226
  }
@@ -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
  }
@@ -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: 20,
34
- priceActionButtonGap: 6,
35
- priceActionButtonBackgroundColor: "#1f2937",
36
- priceActionButtonTextColor: "#e2e8f0",
37
- priceActionButtonBorderColor: "#475569",
38
- priceActionButtonBorderWidth: 1,
34
+ priceActionButtonSize: 16,
35
+ priceActionButtonGap: 4,
39
36
  priceActionButtonRounded: true,
40
- priceActionButtonBorderRadius: 3
37
+ priceActionButtonBorderRadius: 8
41
38
  };
42
39
  var DEFAULT_WATERMARK_OPTIONS = {
43
40
  visible: false,
@@ -1127,35 +1124,79 @@ function createChart(element, options = {}) {
1127
1124
  strokeCrosshairLabel(priceX, priceY, priceWidth);
1128
1125
  drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
1129
1126
  if (crosshair.showPriceActionButton) {
1130
- const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, 30);
1127
+ const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
1131
1128
  const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
1132
- const buttonX = priceX - buttonGap - buttonSize;
1129
+ const containerPaddingX = 5;
1130
+ const containerWidth = buttonSize + containerPaddingX * 2;
1131
+ const containerX = priceX - buttonGap - containerWidth;
1132
+ const containerY = priceY;
1133
+ const buttonX = containerX + containerPaddingX;
1133
1134
  const buttonY = priceY + (labelHeight - buttonSize) / 2;
1134
1135
  const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
1135
- const buttonBorderWidth = Math.max(0, Math.round(crosshair.priceActionButtonBorderWidth));
1136
- ctx.fillStyle = crosshair.priceActionButtonBackgroundColor;
1137
- fillRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1136
+ const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
1137
+ const buttonCenterX = buttonX + buttonSize / 2;
1138
+ const buttonCenterY = buttonY + buttonSize / 2;
1139
+ const containerRadius = labelRadius;
1140
+ ctx.fillStyle = labelBackground;
1141
+ fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1142
+ if (labelBorderWidth > 0) {
1143
+ ctx.save();
1144
+ ctx.strokeStyle = labelBorderColor;
1145
+ ctx.lineWidth = labelBorderWidth;
1146
+ ctx.setLineDash([]);
1147
+ strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1148
+ ctx.restore();
1149
+ }
1138
1150
  if (buttonBorderWidth > 0) {
1139
1151
  ctx.save();
1140
- ctx.strokeStyle = crosshair.priceActionButtonBorderColor;
1152
+ ctx.strokeStyle = labelBorderColor;
1141
1153
  ctx.lineWidth = buttonBorderWidth;
1142
1154
  ctx.setLineDash([]);
1143
- strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1155
+ if (crosshair.priceActionButtonRounded) {
1156
+ ctx.beginPath();
1157
+ ctx.arc(
1158
+ buttonCenterX,
1159
+ buttonCenterY,
1160
+ Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
1161
+ 0,
1162
+ Math.PI * 2
1163
+ );
1164
+ ctx.stroke();
1165
+ } else {
1166
+ strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1167
+ }
1168
+ ctx.restore();
1169
+ }
1170
+ if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
1171
+ const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
1172
+ const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
1173
+ ctx.save();
1174
+ ctx.strokeStyle = labelTextColor;
1175
+ ctx.lineWidth = plusThickness;
1176
+ ctx.lineCap = "round";
1177
+ ctx.setLineDash([]);
1178
+ ctx.beginPath();
1179
+ ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
1180
+ ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
1181
+ ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
1182
+ ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
1183
+ ctx.stroke();
1144
1184
  ctx.restore();
1185
+ } else {
1186
+ drawText(
1187
+ crosshair.priceActionButtonText,
1188
+ buttonCenterX,
1189
+ buttonCenterY,
1190
+ "center",
1191
+ "middle",
1192
+ labelTextColor
1193
+ );
1145
1194
  }
1146
- drawText(
1147
- crosshair.priceActionButtonText,
1148
- buttonX + buttonSize / 2,
1149
- buttonY + buttonSize / 2,
1150
- "center",
1151
- "middle",
1152
- crosshair.priceActionButtonTextColor
1153
- );
1154
1195
  crosshairPriceActionRegion = {
1155
- x: buttonX,
1156
- y: buttonY,
1157
- width: buttonSize,
1158
- height: buttonSize,
1196
+ x: containerX,
1197
+ y: containerY,
1198
+ width: containerWidth,
1199
+ height: labelHeight,
1159
1200
  price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
1160
1201
  };
1161
1202
  }
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: 20,
58
- priceActionButtonGap: 6,
59
- priceActionButtonBackgroundColor: "#1f2937",
60
- priceActionButtonTextColor: "#e2e8f0",
61
- priceActionButtonBorderColor: "#475569",
62
- priceActionButtonBorderWidth: 1,
58
+ priceActionButtonSize: 16,
59
+ priceActionButtonGap: 4,
63
60
  priceActionButtonRounded: true,
64
- priceActionButtonBorderRadius: 3
61
+ priceActionButtonBorderRadius: 8
65
62
  };
66
63
  var DEFAULT_WATERMARK_OPTIONS = {
67
64
  visible: false,
@@ -1151,35 +1148,79 @@ function createChart(element, options = {}) {
1151
1148
  strokeCrosshairLabel(priceX, priceY, priceWidth);
1152
1149
  drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
1153
1150
  if (crosshair.showPriceActionButton) {
1154
- const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, 30);
1151
+ const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
1155
1152
  const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
1156
- const buttonX = priceX - buttonGap - buttonSize;
1153
+ const containerPaddingX = 5;
1154
+ const containerWidth = buttonSize + containerPaddingX * 2;
1155
+ const containerX = priceX - buttonGap - containerWidth;
1156
+ const containerY = priceY;
1157
+ const buttonX = containerX + containerPaddingX;
1157
1158
  const buttonY = priceY + (labelHeight - buttonSize) / 2;
1158
1159
  const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
1159
- const buttonBorderWidth = Math.max(0, Math.round(crosshair.priceActionButtonBorderWidth));
1160
- ctx.fillStyle = crosshair.priceActionButtonBackgroundColor;
1161
- fillRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1160
+ const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
1161
+ const buttonCenterX = buttonX + buttonSize / 2;
1162
+ const buttonCenterY = buttonY + buttonSize / 2;
1163
+ const containerRadius = labelRadius;
1164
+ ctx.fillStyle = labelBackground;
1165
+ fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1166
+ if (labelBorderWidth > 0) {
1167
+ ctx.save();
1168
+ ctx.strokeStyle = labelBorderColor;
1169
+ ctx.lineWidth = labelBorderWidth;
1170
+ ctx.setLineDash([]);
1171
+ strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1172
+ ctx.restore();
1173
+ }
1162
1174
  if (buttonBorderWidth > 0) {
1163
1175
  ctx.save();
1164
- ctx.strokeStyle = crosshair.priceActionButtonBorderColor;
1176
+ ctx.strokeStyle = labelBorderColor;
1165
1177
  ctx.lineWidth = buttonBorderWidth;
1166
1178
  ctx.setLineDash([]);
1167
- strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1179
+ if (crosshair.priceActionButtonRounded) {
1180
+ ctx.beginPath();
1181
+ ctx.arc(
1182
+ buttonCenterX,
1183
+ buttonCenterY,
1184
+ Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
1185
+ 0,
1186
+ Math.PI * 2
1187
+ );
1188
+ ctx.stroke();
1189
+ } else {
1190
+ strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1191
+ }
1192
+ ctx.restore();
1193
+ }
1194
+ if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
1195
+ const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
1196
+ const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
1197
+ ctx.save();
1198
+ ctx.strokeStyle = labelTextColor;
1199
+ ctx.lineWidth = plusThickness;
1200
+ ctx.lineCap = "round";
1201
+ ctx.setLineDash([]);
1202
+ ctx.beginPath();
1203
+ ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
1204
+ ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
1205
+ ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
1206
+ ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
1207
+ ctx.stroke();
1168
1208
  ctx.restore();
1209
+ } else {
1210
+ drawText(
1211
+ crosshair.priceActionButtonText,
1212
+ buttonCenterX,
1213
+ buttonCenterY,
1214
+ "center",
1215
+ "middle",
1216
+ labelTextColor
1217
+ );
1169
1218
  }
1170
- drawText(
1171
- crosshair.priceActionButtonText,
1172
- buttonX + buttonSize / 2,
1173
- buttonY + buttonSize / 2,
1174
- "center",
1175
- "middle",
1176
- crosshair.priceActionButtonTextColor
1177
- );
1178
1219
  crosshairPriceActionRegion = {
1179
- x: buttonX,
1180
- y: buttonY,
1181
- width: buttonSize,
1182
- height: buttonSize,
1220
+ x: containerX,
1221
+ y: containerY,
1222
+ width: containerWidth,
1223
+ height: labelHeight,
1183
1224
  price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
1184
1225
  };
1185
1226
  }
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
  }
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
  }
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: 20,
34
- priceActionButtonGap: 6,
35
- priceActionButtonBackgroundColor: "#1f2937",
36
- priceActionButtonTextColor: "#e2e8f0",
37
- priceActionButtonBorderColor: "#475569",
38
- priceActionButtonBorderWidth: 1,
34
+ priceActionButtonSize: 16,
35
+ priceActionButtonGap: 4,
39
36
  priceActionButtonRounded: true,
40
- priceActionButtonBorderRadius: 3
37
+ priceActionButtonBorderRadius: 8
41
38
  };
42
39
  var DEFAULT_WATERMARK_OPTIONS = {
43
40
  visible: false,
@@ -1127,35 +1124,79 @@ function createChart(element, options = {}) {
1127
1124
  strokeCrosshairLabel(priceX, priceY, priceWidth);
1128
1125
  drawText(priceText, priceX + labelPaddingX, priceY + labelHeight / 2, "left", "middle", labelTextColor);
1129
1126
  if (crosshair.showPriceActionButton) {
1130
- const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, 30);
1127
+ const buttonSize = clamp(Math.round(crosshair.priceActionButtonSize), 12, Math.max(12, labelHeight - 4));
1131
1128
  const buttonGap = Math.max(0, Math.round(crosshair.priceActionButtonGap));
1132
- const buttonX = priceX - buttonGap - buttonSize;
1129
+ const containerPaddingX = 5;
1130
+ const containerWidth = buttonSize + containerPaddingX * 2;
1131
+ const containerX = priceX - buttonGap - containerWidth;
1132
+ const containerY = priceY;
1133
+ const buttonX = containerX + containerPaddingX;
1133
1134
  const buttonY = priceY + (labelHeight - buttonSize) / 2;
1134
1135
  const buttonRadius = crosshair.priceActionButtonRounded ? clamp(Math.round(crosshair.priceActionButtonBorderRadius), 0, buttonSize / 2) : 0;
1135
- const buttonBorderWidth = Math.max(0, Math.round(crosshair.priceActionButtonBorderWidth));
1136
- ctx.fillStyle = crosshair.priceActionButtonBackgroundColor;
1137
- fillRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1136
+ const buttonBorderWidth = Math.max(1, Math.round(labelBorderWidth || 1));
1137
+ const buttonCenterX = buttonX + buttonSize / 2;
1138
+ const buttonCenterY = buttonY + buttonSize / 2;
1139
+ const containerRadius = labelRadius;
1140
+ ctx.fillStyle = labelBackground;
1141
+ fillRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1142
+ if (labelBorderWidth > 0) {
1143
+ ctx.save();
1144
+ ctx.strokeStyle = labelBorderColor;
1145
+ ctx.lineWidth = labelBorderWidth;
1146
+ ctx.setLineDash([]);
1147
+ strokeRoundedRect(Math.round(containerX), Math.round(containerY), containerWidth, labelHeight, containerRadius);
1148
+ ctx.restore();
1149
+ }
1138
1150
  if (buttonBorderWidth > 0) {
1139
1151
  ctx.save();
1140
- ctx.strokeStyle = crosshair.priceActionButtonBorderColor;
1152
+ ctx.strokeStyle = labelBorderColor;
1141
1153
  ctx.lineWidth = buttonBorderWidth;
1142
1154
  ctx.setLineDash([]);
1143
- strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1155
+ if (crosshair.priceActionButtonRounded) {
1156
+ ctx.beginPath();
1157
+ ctx.arc(
1158
+ buttonCenterX,
1159
+ buttonCenterY,
1160
+ Math.max(1, buttonSize / 2 - buttonBorderWidth / 2),
1161
+ 0,
1162
+ Math.PI * 2
1163
+ );
1164
+ ctx.stroke();
1165
+ } else {
1166
+ strokeRoundedRect(Math.round(buttonX), Math.round(buttonY), buttonSize, buttonSize, buttonRadius);
1167
+ }
1168
+ ctx.restore();
1169
+ }
1170
+ if (crosshair.priceActionButtonIcon !== "text" && crosshair.priceActionButtonText === "+") {
1171
+ const plusHalf = Math.max(3, Math.round(buttonSize * 0.22));
1172
+ const plusThickness = crosshair.priceActionButtonIcon === "plusThin" ? Math.max(1, Math.round(buttonSize * 0.07)) : Math.max(1, Math.round(buttonSize * 0.1));
1173
+ ctx.save();
1174
+ ctx.strokeStyle = labelTextColor;
1175
+ ctx.lineWidth = plusThickness;
1176
+ ctx.lineCap = "round";
1177
+ ctx.setLineDash([]);
1178
+ ctx.beginPath();
1179
+ ctx.moveTo(buttonCenterX - plusHalf, buttonCenterY);
1180
+ ctx.lineTo(buttonCenterX + plusHalf, buttonCenterY);
1181
+ ctx.moveTo(buttonCenterX, buttonCenterY - plusHalf);
1182
+ ctx.lineTo(buttonCenterX, buttonCenterY + plusHalf);
1183
+ ctx.stroke();
1144
1184
  ctx.restore();
1185
+ } else {
1186
+ drawText(
1187
+ crosshair.priceActionButtonText,
1188
+ buttonCenterX,
1189
+ buttonCenterY,
1190
+ "center",
1191
+ "middle",
1192
+ labelTextColor
1193
+ );
1145
1194
  }
1146
- drawText(
1147
- crosshair.priceActionButtonText,
1148
- buttonX + buttonSize / 2,
1149
- buttonY + buttonSize / 2,
1150
- "center",
1151
- "middle",
1152
- crosshair.priceActionButtonTextColor
1153
- );
1154
1195
  crosshairPriceActionRegion = {
1155
- x: buttonX,
1156
- y: buttonY,
1157
- width: buttonSize,
1158
- height: buttonSize,
1196
+ x: containerX,
1197
+ y: containerY,
1198
+ width: containerWidth,
1199
+ height: labelHeight,
1159
1200
  price: Number(hoverPrice.toFixed(mergedOptions.priceDecimals))
1160
1201
  };
1161
1202
  }
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 `20`)
100
- - `priceActionButtonGap` (default `6`)
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 `3`)
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
 
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: 6
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
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperprop-charting-library",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "Lightweight TypeScript charting core",
5
5
  "type": "module",
6
6
  "main": "./dist/hyperprop-charting-library.cjs",