@pipsend/charts 2.2.1 → 2.3.0

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/typings.d.ts CHANGED
@@ -378,6 +378,8 @@ export declare class DrawingToolsManager {
378
378
  private _pointerDownHandler;
379
379
  private _pointerUpHandler;
380
380
  private _pointerCancelHandler;
381
+ private _lostCaptureHandler;
382
+ private _windowPointerUpHandler;
381
383
  private _pointerId;
382
384
  /** A press that grabbed a tool already selected it; its click must not undo that. */
383
385
  private _gestureHandled;
@@ -529,6 +531,8 @@ export declare class DrawingToolsManager {
529
531
  private _findToolByExternalId;
530
532
  private _handlePointerDown;
531
533
  private _handlePointerUp;
534
+ /** Ends the drag when capture is lost without a pointerup ever arriving. */
535
+ private _handleLostPointerCapture;
532
536
  /**
533
537
  * Pane element of a tool's series. The engine asserts the series has a pane,
534
538
  * so the lookup is guarded.
@@ -1111,6 +1115,89 @@ export declare class PositionCalculator {
1111
1115
  */
1112
1116
  getPipConfig(): PipConfig;
1113
1117
  }
1118
+ /**
1119
+ * A group of trading levels — entry, take profit and stop loss — drawn as one
1120
+ * unit: a line per level, a label carrying size and P&L, and a connector that
1121
+ * ties the three together.
1122
+ *
1123
+ * Input is not handled here. Every trading line on a chart shares a single
1124
+ * TradingLineController, which is what guarantees that one gesture moves one
1125
+ * level, and that a position line and a plain draggable price line on the same
1126
+ * chart do not fight over the pointer.
1127
+ */
1128
+ export declare class PositionLine implements ISeriesPrimitive, ControllableLine {
1129
+ private readonly _chart;
1130
+ private readonly _series;
1131
+ private readonly _id;
1132
+ private readonly _paneView;
1133
+ private readonly _paneViews;
1134
+ private readonly _axisViews;
1135
+ private readonly _colorParser;
1136
+ private _options;
1137
+ private _theme;
1138
+ private _requestUpdate?;
1139
+ private _attached;
1140
+ private _hoveredLevel;
1141
+ private _hoveredPart;
1142
+ private _dragLevel;
1143
+ private _priceBeforeDrag;
1144
+ constructor(chart: IChartApi, series: ISeriesApi<SeriesType>, options: PositionLineOptions);
1145
+ attached(param: SeriesAttachedParameter): void;
1146
+ detached(): void;
1147
+ paneViews(): readonly IPrimitivePaneView[];
1148
+ priceAxisViews(): readonly ISeriesPrimitiveAxisView[];
1149
+ updateAllViews(): void;
1150
+ hitTest(x: number, y: number): PrimitiveHoveredItem | null;
1151
+ id(): string;
1152
+ paneIndex(): number;
1153
+ setHoveredPart(part: string | null): void;
1154
+ setHovered(hovered: boolean): void;
1155
+ isDraggable(): boolean;
1156
+ isClickable(): boolean;
1157
+ priceAt(paneY: number): number | null;
1158
+ beginDrag(): void;
1159
+ dragTo(price: number): void;
1160
+ commitDrag(): void;
1161
+ cancelDrag(): void;
1162
+ click(): void;
1163
+ /**
1164
+ * Updates the group. Any subset of options can be passed; the levels given
1165
+ * are merged into the current ones, and a level set to `undefined` is
1166
+ * removed.
1167
+ */
1168
+ applyOptions(options: PositionLineUpdate): void;
1169
+ /**
1170
+ * Moves one level to a new price, recomputing its text when the level has a
1171
+ * `formatText`.
1172
+ *
1173
+ * Ignored for a level the user is currently dragging — the gesture owns the
1174
+ * price until it reports back through
1175
+ * {@link PositionLineOptions.onDragEnd} or
1176
+ * {@link PositionLineOptions.onDragCancel}.
1177
+ */
1178
+ setPrice(level: PositionLineLevel, price: number): void;
1179
+ /**
1180
+ * Replaces one level's label text. Use this for text that changes on its own
1181
+ * — a ticking P&L on a fixed entry — rather than with the price.
1182
+ */
1183
+ setText(level: PositionLineLevel, text: string): void;
1184
+ /**
1185
+ * The current price of each level that is present.
1186
+ */
1187
+ prices(): Partial<Record<PositionLineLevel, number>>;
1188
+ options(): PositionLineOptions;
1189
+ /**
1190
+ * Removes the group from the chart and releases its share of the input
1191
+ * controller.
1192
+ */
1193
+ remove(): void;
1194
+ requestUpdate(): void;
1195
+ /** Reads back the label the price axis should draw for a level. */
1196
+ private _axisLabel;
1197
+ private _levelOptions;
1198
+ private _applyPrice;
1199
+ private _buildRendererData;
1200
+ }
1114
1201
  /**
1115
1202
  * Gestor de marcadores de posiciones de trading
1116
1203
  */
@@ -2272,6 +2359,26 @@ export declare function createOptionsChart(container: string | HTMLElement, opti
2272
2359
  export declare function createParallelChannelTool(context: DrawingContext, options: ParallelChannelToolOptions): ParallelChannelTool;
2273
2360
  export declare function createPitchforkTool(context: DrawingContext, options: PitchforkToolOptions): PitchforkTool;
2274
2361
  export declare function createPolygonTool(context: DrawingContext, options: PolygonToolOptions): PolygonTool;
2362
+ /**
2363
+ * Creates a position line group: entry, take profit and stop loss drawn as one
2364
+ * interactive unit.
2365
+ *
2366
+ * @param series - The series the levels are priced against.
2367
+ * @param chart - The chart the series belongs to.
2368
+ * @param options - The levels and their style.
2369
+ *
2370
+ * @example
2371
+ * ```js
2372
+ * const position = createPositionLine(candleSeries, chart, {
2373
+ * entry: { price: 4306.79, badge: '1', formatText: () => '+ 2.32 USD' },
2374
+ * takeProfit: { price: 4349.58, badge: '1', text: '+ 42.79 USD' },
2375
+ * stopLoss: { price: 4266.06, badge: '1', text: '- 40.73 USD' },
2376
+ * onClose: (level) => console.log('close', level),
2377
+ * onDragEnd: (level, price) => console.log(level, 'moved to', price),
2378
+ * });
2379
+ * ```
2380
+ */
2381
+ export declare function createPositionLine(series: ISeriesApi<SeriesType>, chart: IChartApi, options: PositionLineOptions): PositionLine;
2275
2382
  /**
2276
2383
  * Crea un gestor de marcadores de posiciones de trading
2277
2384
  *
@@ -3247,6 +3354,12 @@ export interface ControllableLine {
3247
3354
  isDraggable(): boolean;
3248
3355
  isClickable(): boolean;
3249
3356
  setHovered(hovered: boolean): void;
3357
+ /**
3358
+ * Optional. A line whose hit test names sub-parts — a label, a close button —
3359
+ * is told which one the pointer is over, so `isDraggable`, `isClickable` and
3360
+ * `click` can answer for that part rather than for the line as a whole.
3361
+ */
3362
+ setHoveredPart?(part: string | null): void;
3250
3363
  priceAt(paneY: number): number | null;
3251
3364
  beginDrag(): void;
3252
3365
  dragTo(price: number): void;
@@ -6034,6 +6147,189 @@ export interface PolygonVertex {
6034
6147
  time: Time;
6035
6148
  price: number;
6036
6149
  }
6150
+ /**
6151
+ * Configuration for one level (entry, take profit or stop loss) of a position.
6152
+ */
6153
+ export interface PositionLineLevelOptions {
6154
+ /**
6155
+ * The price the level sits at.
6156
+ */
6157
+ price: number;
6158
+ /**
6159
+ * The text inside the label, for example `+ 42.79 USD`.
6160
+ */
6161
+ text?: string;
6162
+ /**
6163
+ * The text of the badge on the left of the label, for example the position
6164
+ * size. Hidden when empty.
6165
+ */
6166
+ badge?: string;
6167
+ /**
6168
+ * Fills the badge with {@link PositionLineLevelOptions.color} instead of
6169
+ * drawing it outlined.
6170
+ *
6171
+ * @defaultValue `true` for the entry, `false` otherwise
6172
+ */
6173
+ badgeFilled?: boolean;
6174
+ /**
6175
+ * The colour of the line, the label's border and its text.
6176
+ */
6177
+ color?: string;
6178
+ /**
6179
+ * @defaultValue `1`
6180
+ */
6181
+ lineWidth?: LineWidth;
6182
+ /**
6183
+ * @defaultValue `LineStyle.Solid` for the entry, `LineStyle.Dashed` otherwise
6184
+ */
6185
+ lineStyle?: LineStyle;
6186
+ /**
6187
+ * Lets the user drag the level to a new price.
6188
+ *
6189
+ * @defaultValue `true`
6190
+ */
6191
+ draggable?: boolean;
6192
+ /**
6193
+ * Shows the close button on the right of the label.
6194
+ *
6195
+ * @defaultValue `true`
6196
+ */
6197
+ closable?: boolean;
6198
+ /**
6199
+ * Shows the price label on the price axis.
6200
+ *
6201
+ * @defaultValue `true`
6202
+ */
6203
+ axisLabelVisible?: boolean;
6204
+ /**
6205
+ * Computes {@link PositionLineLevelOptions.text} from the level's current
6206
+ * price. Called on every price change, which is what keeps a live P&L in
6207
+ * step with a drag.
6208
+ */
6209
+ formatText?: (price: number) => string;
6210
+ }
6211
+ /**
6212
+ * Configuration for a position line group.
6213
+ */
6214
+ export interface PositionLineOptions {
6215
+ /**
6216
+ * The entry level. Always drawn.
6217
+ */
6218
+ entry: PositionLineLevelOptions;
6219
+ /**
6220
+ * The take profit level. Omit for a position without one.
6221
+ */
6222
+ takeProfit?: PositionLineLevelOptions;
6223
+ /**
6224
+ * The stop loss level. Omit for a position without one.
6225
+ */
6226
+ stopLoss?: PositionLineLevelOptions;
6227
+ /**
6228
+ * @defaultValue `true`
6229
+ */
6230
+ visible?: boolean;
6231
+ /**
6232
+ * Draws the vertical line joining the levels, with a handle on each of them.
6233
+ *
6234
+ * @defaultValue `true`
6235
+ */
6236
+ connectorVisible?: boolean;
6237
+ /**
6238
+ * Distance in pixels between the right edge of the pane and the connector.
6239
+ *
6240
+ * @defaultValue `56`
6241
+ */
6242
+ rightOffset?: number;
6243
+ /**
6244
+ * Overrides for the shared visual style.
6245
+ */
6246
+ theme?: Partial<PositionLineTheme>;
6247
+ /**
6248
+ * Fires when the user starts dragging a level.
6249
+ */
6250
+ onDragStart?: (level: PositionLineLevel, price: number) => void;
6251
+ /**
6252
+ * Fires continuously while a level is being dragged.
6253
+ */
6254
+ onDragMove?: (level: PositionLineLevel, price: number) => void;
6255
+ /**
6256
+ * Fires once the drag is released. A drag that was cancelled does not report.
6257
+ */
6258
+ onDragEnd?: (level: PositionLineLevel, price: number) => void;
6259
+ /**
6260
+ * Fires when a drag ends without committing — the pointer left the chart, or
6261
+ * Escape was pressed. Together with {@link PositionLineOptions.onDragEnd} it
6262
+ * guarantees every gesture that started is reported as finished, which is
6263
+ * what callers need to pause work while a level is under the cursor.
6264
+ */
6265
+ onDragCancel?: (level: PositionLineLevel, price: number) => void;
6266
+ /**
6267
+ * Fires when the close button of a level is clicked.
6268
+ */
6269
+ onClose?: (level: PositionLineLevel) => void;
6270
+ /**
6271
+ * Fires on a click on a level's label or line that did not drag.
6272
+ */
6273
+ onClick?: (level: PositionLineLevel, price: number) => void;
6274
+ }
6275
+ /**
6276
+ * Visual style shared by every level of a position line group.
6277
+ */
6278
+ export interface PositionLineTheme {
6279
+ /**
6280
+ * The label's fill. Defaults to the chart's own background, so the label
6281
+ * stays readable on light and dark themes alike.
6282
+ */
6283
+ background?: string;
6284
+ /**
6285
+ * The label's text colour. Defaults to the level's colour.
6286
+ */
6287
+ textColor?: string;
6288
+ /**
6289
+ * The text colour used inside a filled badge.
6290
+ */
6291
+ badgeTextColor: string;
6292
+ /**
6293
+ * Corner radius of the label, in pixels.
6294
+ */
6295
+ borderRadius: number;
6296
+ /**
6297
+ * Border width of the label, in pixels.
6298
+ */
6299
+ borderWidth: number;
6300
+ /**
6301
+ * Horizontal padding inside each cell of the label, in pixels.
6302
+ */
6303
+ paddingX: number;
6304
+ /**
6305
+ * Vertical padding inside the label, in pixels.
6306
+ */
6307
+ paddingY: number;
6308
+ /**
6309
+ * Font size of the label. Defaults to the chart's layout font size.
6310
+ */
6311
+ fontSize?: number;
6312
+ /**
6313
+ * Font family of the label. Defaults to the chart's layout font family.
6314
+ */
6315
+ fontFamily?: string;
6316
+ /**
6317
+ * Opacity applied to the label's fill, between 0 and 1. The default is
6318
+ * opaque: the label carries a price and a P&L, and candles showing through
6319
+ * it make those harder to read.
6320
+ */
6321
+ backgroundOpacity: number;
6322
+ }
6323
+ /**
6324
+ * The shape {@link PositionLine.applyOptions} takes: every field optional, and
6325
+ * a level given as a patch rather than as a whole. A level set to `undefined`
6326
+ * is removed; a level that is not mentioned is left alone.
6327
+ */
6328
+ export interface PositionLineUpdate extends Partial<Omit<PositionLineOptions, "entry" | "takeProfit" | "stopLoss">> {
6329
+ entry?: Partial<PositionLineLevelOptions>;
6330
+ takeProfit?: Partial<PositionLineLevelOptions>;
6331
+ stopLoss?: Partial<PositionLineLevelOptions>;
6332
+ }
6037
6333
  /**
6038
6334
  * Opciones para el gestor de posiciones
6039
6335
  */
@@ -6625,6 +6921,31 @@ export interface SeriesMarkerBase<TimeType> {
6625
6921
  * Required when using {@link SeriesMarkerPricePosition} position type.
6626
6922
  */
6627
6923
  price?: number;
6924
+ /**
6925
+ * The colour of the marker's text.
6926
+ *
6927
+ * For the `tag` shape the text sits on top of {@link SeriesMarkerBase.color},
6928
+ * so this defaults to white. Other shapes draw the text in `color`.
6929
+ */
6930
+ textColor?: string;
6931
+ /**
6932
+ * The colour of the marker's outline. Only used by the `tag` shape.
6933
+ *
6934
+ * @defaultValue no outline
6935
+ */
6936
+ borderColor?: string;
6937
+ /**
6938
+ * The width of the marker's outline in pixels. Only used by the `tag` shape.
6939
+ *
6940
+ * @defaultValue `1` when {@link SeriesMarkerBase.borderColor} is set
6941
+ */
6942
+ borderWidth?: number;
6943
+ /**
6944
+ * The corner radius of the `tag` shape's bubble in pixels.
6945
+ *
6946
+ * @defaultValue `6`
6947
+ */
6948
+ borderRadius?: number;
6628
6949
  }
6629
6950
  export interface SeriesMarkerPrice<TimeType> extends SeriesMarkerBase<TimeType> {
6630
6951
  /**
@@ -7707,6 +8028,14 @@ export type OverlayPriceScaleOptions = Omit<PriceScaleOptions, "visible" | "auto
7707
8028
  */
7708
8029
  export type PercentageFormatterFn = (percentageValue: number) => string;
7709
8030
  export type PitchforkPart = "pivot" | "upper" | "lower" | "body";
8031
+ /**
8032
+ * The three levels a position line group can show.
8033
+ */
8034
+ export type PositionLineLevel = "entry" | "takeProfit" | "stopLoss";
8035
+ /**
8036
+ * The parts of a level that respond to the pointer.
8037
+ */
8038
+ export type PositionLinePart = "line" | "body" | "close";
7710
8039
  /**
7711
8040
  * Tipo de posición de trading
7712
8041
  */
@@ -7775,8 +8104,12 @@ export type SeriesMarkerPosition = SeriesMarkerBarPosition | SeriesMarkerPricePo
7775
8104
  export type SeriesMarkerPricePosition = "atPriceTop" | "atPriceBottom" | "atPriceMiddle";
7776
8105
  /**
7777
8106
  * Represents the shape of a series marker.
8107
+ *
8108
+ * `tag` draws the text inside a rounded bubble with a pointer aimed at the
8109
+ * anchor, which is what trading platforms use for BUY/SELL callouts. The other
8110
+ * shapes draw the text next to the shape instead.
7778
8111
  */
7779
- export type SeriesMarkerShape = "circle" | "square" | "arrowUp" | "arrowDown";
8112
+ export type SeriesMarkerShape = "circle" | "square" | "arrowUp" | "arrowDown" | "tag";
7780
8113
  /**
7781
8114
  * The visual stacking order for the markers within the chart.
7782
8115
  *
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
- "version": "2.2.1",
2
+ "private": false,
3
+ "version": "2.3.0",
3
4
  "name": "@pipsend/charts",
4
5
  "author": "Pipsend",
5
6
  "license": "SEE LICENSE IN LICENSE",
@@ -53,7 +54,88 @@
53
54
  "bollinger-bands",
54
55
  "financial-analysis"
55
56
  ],
57
+ "engines": {
58
+ "node": ">=22.3"
59
+ },
56
60
  "dependencies": {
57
61
  "fancy-canvas": "2.1.0"
62
+ },
63
+ "devDependencies": {
64
+ "@juggle/resize-observer": "3.4.0",
65
+ "@rollup/plugin-node-resolve": "16.0.1",
66
+ "@rollup/plugin-replace": "6.0.2",
67
+ "@rollup/plugin-terser": "0.4.4",
68
+ "@size-limit/file": "11.2.0",
69
+ "@size-limit/webpack": "11.2.0",
70
+ "@types/chai": "5.2.1",
71
+ "@types/express": "5.0.1",
72
+ "@types/glob": "8.1.0",
73
+ "@types/node": "22",
74
+ "@types/pixelmatch": "5.2.6",
75
+ "@types/pngjs": "6.0.5",
76
+ "@typescript-eslint/eslint-plugin": "7.18.0",
77
+ "@typescript-eslint/eslint-plugin-tslint": "7.0.2",
78
+ "@typescript-eslint/parser": "7.18.0",
79
+ "ajv": "7.2.4",
80
+ "bytes": "3.1.2",
81
+ "chai": "5.2.0",
82
+ "chai-exclude": "3.0.1",
83
+ "cross-env": "7.0.3",
84
+ "dts-bundle-generator": "9.5.1",
85
+ "eslint": "8",
86
+ "eslint-formatter-unix": "8.40.0",
87
+ "eslint-plugin-deprecation": "3.0.0",
88
+ "eslint-plugin-import": "2.31.0",
89
+ "eslint-plugin-unicorn": "56.0.1",
90
+ "esno": "4.8.0",
91
+ "glob": "11.0.1",
92
+ "markdown-it": "14.1.0",
93
+ "markdown-it-anchor": "9.2.0",
94
+ "markdownlint-cli": "0.44.0",
95
+ "npm-run-all": "4.1.5",
96
+ "rimraf": "6.0.1",
97
+ "rollup": "4.40.0",
98
+ "size-limit": "11.2.0",
99
+ "ts-node": "10.9.2",
100
+ "ts-patch": "3.3.0",
101
+ "ts-transformer-properties-rename": "0.17.0",
102
+ "ts-transformer-strip-const-enums": "2.0.0",
103
+ "tslib": "2.8.1",
104
+ "tslint": "6.1.3",
105
+ "tslint-eslint-rules": "5.4.0",
106
+ "tslint-microsoft-contrib": "6.2.0",
107
+ "tsx": "4.19.3",
108
+ "typescript": "5.5.4",
109
+ "yargs": "17.7.2"
110
+ },
111
+ "scripts": {
112
+ "prepare": "node scripts/githooks/install.js || true",
113
+ "clean": "rimraf lib/ dist/",
114
+ "bundle-dts": "dts-bundle-generator --config dts-config.json",
115
+ "tsc": "tspc -p tsconfig.prod.json",
116
+ "tsc-watch": "npm run tsc -- --watch --preserveWatchOutput",
117
+ "tsc-verify": "node -e \"const fs=require('fs');const p='website/scripts/generate-versions-dts.js'; if(fs.existsSync(p)){require('child_process').execSync('node '+p,{stdio:'inherit'});} else {console.warn('[tsc-verify] skip: '+p+' not found');}\" && tsc -b tsconfig.composite.json",
118
+ "lint": "npm-run-all -p lint:**",
119
+ "lint:eslint": "eslint --format=unix ./",
120
+ "lint:md": "markdownlint -i \"**/node_modules/**\" -i \"**/website/docs/api/**\" -i \"**/website/versioned_docs/**/api/**\" -i \"**/*.mdx\" \"**/*.md\"",
121
+ "check-dts-docs": "npm-run-all -p check-dts-docs-duplicates check-dts-docs-eslint",
122
+ "check-dts-docs-duplicates": "node ./scripts/check-typings-for-duplicates.js ./dist/typings.d.ts",
123
+ "check-dts-docs-eslint": "eslint --format=unix ./dist/typings.d.ts --no-ignore",
124
+ "check-markdown-links": "node scripts/check-markdown-links.js",
125
+ "rollup": "rollup -c rollup.config.js",
126
+ "rollup-watch": "npm run rollup -- --watch",
127
+ "build": "npm-run-all tsc rollup bundle-dts",
128
+ "build:watch": "npm-run-all tsc -p tsc-watch rollup-watch",
129
+ "build:prod": "cross-env NODE_ENV=production npm run build",
130
+ "build:release": "cross-env BUILD_TAG=release npm run build:prod",
131
+ "prepare-release": "npm-run-all clean build:release && npm run prepare-package-json-for-release",
132
+ "prepare-package-json-for-release": "node ./scripts/clean-package-json.js",
133
+ "size-limit": "size-limit",
134
+ "verify": "npm-run-all clean -p build:prod check-markdown-links -p lint check-dts-docs tsc-verify test size-limit -p type-tests",
135
+ "test": "esno --import ./tests/unittests/setup.units.mjs --test './tests/unittests/**/*.spec.ts'",
136
+ "type-tests": "tsc -b ./src/tsconfig.composite.json && tsc -p ./tests/type-checks/tsconfig.composite.json --noEmit",
137
+ "e2e:coverage": "esno ./tests/e2e/coverage/runner.ts ./dist/pipsend-charts.standalone.development.js",
138
+ "e2e:interactions": "esno ./tests/e2e/interactions/runner.ts ./dist/pipsend-charts.standalone.development.js",
139
+ "e2e:memleaks": "esno ./tests/e2e/memleaks/runner.ts ./dist/pipsend-charts.standalone.development.js"
58
140
  }
59
141
  }