@pipsend/charts 2.3.0 → 2.3.2
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/pipsend-charts.development.mjs +243 -18
- package/dist/pipsend-charts.production.mjs +2 -2
- package/dist/pipsend-charts.standalone.development.js +243 -18
- package/dist/pipsend-charts.standalone.development.mjs +243 -18
- package/dist/pipsend-charts.standalone.production.js +2 -2
- package/dist/pipsend-charts.standalone.production.mjs +2 -2
- package/dist/typings.d.ts +26 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @license
|
|
3
|
-
* Pipsend Charts v2.3.
|
|
3
|
+
* Pipsend Charts v2.3.2
|
|
4
4
|
* Copyright (c) 2026 Pipsend
|
|
5
5
|
* Licensed under MIT License
|
|
6
6
|
* Built on TradingView Lightweight Charts™ (Apache 2.0)
|
|
@@ -19351,6 +19351,8 @@ class TradingLineController {
|
|
|
19351
19351
|
this._private__pointerId = null;
|
|
19352
19352
|
this._private__pressOrigin = null;
|
|
19353
19353
|
this._private__pressedLine = null;
|
|
19354
|
+
/** Distance from the pointer to the dragged line when the press landed. */
|
|
19355
|
+
this._private__grabOffset = 0;
|
|
19354
19356
|
/** Latest pointer position in pane coordinates, or null when off the panes. */
|
|
19355
19357
|
this._private__point = null;
|
|
19356
19358
|
this._private__paneIndex = undefined;
|
|
@@ -19428,6 +19430,7 @@ class TradingLineController {
|
|
|
19428
19430
|
this._private__pointerId = event.pointerId;
|
|
19429
19431
|
this._private__element.setPointerCapture(event.pointerId);
|
|
19430
19432
|
line.beginDrag();
|
|
19433
|
+
this._private__grabOffset = this._private__measureGrabOffset(line, event);
|
|
19431
19434
|
this._private__applyCursor();
|
|
19432
19435
|
event.preventDefault();
|
|
19433
19436
|
event.stopPropagation();
|
|
@@ -19462,6 +19465,7 @@ class TradingLineController {
|
|
|
19462
19465
|
Math.abs(event.clientY - origin._internal_y) > CLICK_TOLERANCE_PX);
|
|
19463
19466
|
if (dragged !== null) {
|
|
19464
19467
|
this._private__dragging = null;
|
|
19468
|
+
this._private__grabOffset = 0;
|
|
19465
19469
|
if (moved) {
|
|
19466
19470
|
dragged.commitDrag();
|
|
19467
19471
|
}
|
|
@@ -19489,6 +19493,7 @@ class TradingLineController {
|
|
|
19489
19493
|
}
|
|
19490
19494
|
const line = this._private__dragging;
|
|
19491
19495
|
this._private__dragging = null;
|
|
19496
|
+
this._private__grabOffset = 0;
|
|
19492
19497
|
this._private__releasePointer();
|
|
19493
19498
|
line.cancelDrag();
|
|
19494
19499
|
this._private__applyCursor();
|
|
@@ -19518,16 +19523,38 @@ class TradingLineController {
|
|
|
19518
19523
|
// as the pointer leaves the pane canvas — over the price axis, past the
|
|
19519
19524
|
// chart's edge — and a drag driven from it freezes there while the user
|
|
19520
19525
|
// is still moving.
|
|
19526
|
+
const paneY = this._private__paneY(line, event);
|
|
19527
|
+
return paneY === null ? null : line.priceAt(paneY - this._private__grabOffset);
|
|
19528
|
+
}
|
|
19529
|
+
/** The pointer's position inside the line's pane, in pane coordinates. */
|
|
19530
|
+
_private__paneY(line, event) {
|
|
19521
19531
|
const pane = this._private__chart.panes()[line.paneIndex()];
|
|
19522
19532
|
const paneElement = pane ? pane.getHTMLElement() : null;
|
|
19523
19533
|
if (paneElement) {
|
|
19524
|
-
return
|
|
19534
|
+
return event.clientY - paneElement.getBoundingClientRect().top;
|
|
19525
19535
|
}
|
|
19526
19536
|
if (this._private__point !== null && this._private__paneIndex === line.paneIndex()) {
|
|
19527
|
-
return
|
|
19537
|
+
return this._private__point._internal_y;
|
|
19528
19538
|
}
|
|
19529
19539
|
return null;
|
|
19530
19540
|
}
|
|
19541
|
+
/**
|
|
19542
|
+
* Keeps the grab point: a line picked up by the edge of its label moves with
|
|
19543
|
+
* the pointer rather than centring itself on it. Ignored past a sane
|
|
19544
|
+
* distance, so a bad reading cannot send the line off on the first move.
|
|
19545
|
+
*/
|
|
19546
|
+
_private__measureGrabOffset(line, event) {
|
|
19547
|
+
if (!line.dragAnchorY) {
|
|
19548
|
+
return 0;
|
|
19549
|
+
}
|
|
19550
|
+
const anchor = line.dragAnchorY();
|
|
19551
|
+
const paneY = this._private__paneY(line, event);
|
|
19552
|
+
if (anchor === null || paneY === null) {
|
|
19553
|
+
return 0;
|
|
19554
|
+
}
|
|
19555
|
+
const offset = paneY - anchor;
|
|
19556
|
+
return Math.abs(offset) > 40 /* Constants.MaxGrabOffsetPx */ ? 0 : offset;
|
|
19557
|
+
}
|
|
19531
19558
|
/**
|
|
19532
19559
|
* Hit ids are either a bare line id or `id#part`, which is how a line with
|
|
19533
19560
|
* several targets reports which one was hit.
|
|
@@ -20083,6 +20110,126 @@ function createInteractiveLineManager(chart, series) {
|
|
|
20083
20110
|
return new InteractiveLineManager(chart, series);
|
|
20084
20111
|
}
|
|
20085
20112
|
|
|
20113
|
+
/**
|
|
20114
|
+
* Fans out labels that land on top of each other.
|
|
20115
|
+
*
|
|
20116
|
+
* Every position line on a chart shares one of these. Two positions opened at
|
|
20117
|
+
* the same price draw their labels at the same coordinate, and the one behind
|
|
20118
|
+
* becomes unreachable — the engine resolves the hit to whichever primitive it
|
|
20119
|
+
* reaches first, and that is always the same one. Nudging each collision down
|
|
20120
|
+
* leaves every label a strip of its own to be grabbed by.
|
|
20121
|
+
*
|
|
20122
|
+
* The line itself never moves: it stays at the price it belongs to, and only
|
|
20123
|
+
* the label is offset.
|
|
20124
|
+
*/
|
|
20125
|
+
class PositionLineLabelLayout {
|
|
20126
|
+
constructor() {
|
|
20127
|
+
/** Registration order. It is what keeps the fan from reshuffling per frame. */
|
|
20128
|
+
this._private__order = [];
|
|
20129
|
+
this._private__claims = new Map();
|
|
20130
|
+
this._private__offsets = new Map();
|
|
20131
|
+
this._private__invalidated = true;
|
|
20132
|
+
}
|
|
20133
|
+
_internal_register(ownerId) {
|
|
20134
|
+
if (!this._private__claims.has(ownerId)) {
|
|
20135
|
+
this._private__order.push(ownerId);
|
|
20136
|
+
this._private__claims.set(ownerId, []);
|
|
20137
|
+
this._private__invalidated = true;
|
|
20138
|
+
}
|
|
20139
|
+
}
|
|
20140
|
+
_internal_unregister(ownerId) {
|
|
20141
|
+
const index = this._private__order.indexOf(ownerId);
|
|
20142
|
+
if (index !== -1) {
|
|
20143
|
+
this._private__order.splice(index, 1);
|
|
20144
|
+
}
|
|
20145
|
+
this._private__claims.delete(ownerId);
|
|
20146
|
+
this._private__invalidated = true;
|
|
20147
|
+
}
|
|
20148
|
+
_internal_isEmpty() {
|
|
20149
|
+
return this._private__order.length === 0;
|
|
20150
|
+
}
|
|
20151
|
+
/**
|
|
20152
|
+
* Publishes where an owner's labels want to sit. Called while each line
|
|
20153
|
+
* rebuilds its renderer data, so a fan can be one frame behind while prices
|
|
20154
|
+
* move — which is invisible, and cheaper than forcing a second pass.
|
|
20155
|
+
*/
|
|
20156
|
+
_internal_setClaims(ownerId, claims) {
|
|
20157
|
+
this._private__claims.set(ownerId, claims);
|
|
20158
|
+
this._private__invalidated = true;
|
|
20159
|
+
}
|
|
20160
|
+
/** How far down a label has to move to clear the ones already placed. */
|
|
20161
|
+
_internal_offsetFor(ownerId, level) {
|
|
20162
|
+
if (this._private__invalidated) {
|
|
20163
|
+
this._private__recalculate();
|
|
20164
|
+
}
|
|
20165
|
+
return this._private__offsets.get(key(ownerId, level)) ?? 0;
|
|
20166
|
+
}
|
|
20167
|
+
_private__recalculate() {
|
|
20168
|
+
const offsets = new Map();
|
|
20169
|
+
const placed = [];
|
|
20170
|
+
for (const ownerId of this._private__order) {
|
|
20171
|
+
for (const claim of this._private__claims.get(ownerId) ?? []) {
|
|
20172
|
+
const gap = minGap(claim._internal_height);
|
|
20173
|
+
const maxOffset = claim._internal_height;
|
|
20174
|
+
// Moved down to the first coordinate that clears everything already
|
|
20175
|
+
// placed, and no further. Two levels whose own prices nearly part
|
|
20176
|
+
// them only need the few pixels they are short of — stepping by a
|
|
20177
|
+
// full gap each time is what made the fan look flung open.
|
|
20178
|
+
let y = claim._internal_y;
|
|
20179
|
+
for (const other of [...placed].sort(byY)) {
|
|
20180
|
+
if (Math.abs(y - other._internal_y) < gap) {
|
|
20181
|
+
y = other._internal_y + gap;
|
|
20182
|
+
}
|
|
20183
|
+
}
|
|
20184
|
+
let offset = y - claim._internal_y;
|
|
20185
|
+
if (offset > maxOffset) {
|
|
20186
|
+
// More labels than there is room to fan. The rest stack, which is
|
|
20187
|
+
// no worse than before and keeps the pile from running off.
|
|
20188
|
+
offset = 0;
|
|
20189
|
+
}
|
|
20190
|
+
placed.push({ _internal_y: claim._internal_y + offset, _internal_height: claim._internal_height });
|
|
20191
|
+
offsets.set(key(ownerId, claim._internal_level), offset);
|
|
20192
|
+
}
|
|
20193
|
+
}
|
|
20194
|
+
this._private__offsets = offsets;
|
|
20195
|
+
this._private__invalidated = false;
|
|
20196
|
+
}
|
|
20197
|
+
}
|
|
20198
|
+
function key(ownerId, level) {
|
|
20199
|
+
return `${ownerId}:${level}`;
|
|
20200
|
+
}
|
|
20201
|
+
/**
|
|
20202
|
+
* The strip a label keeps to itself. Comfortably clickable, and no wider —
|
|
20203
|
+
* every pixel here is a pixel the label sits away from its own line.
|
|
20204
|
+
*/
|
|
20205
|
+
function minGap(height) {
|
|
20206
|
+
return Math.max(9, Math.round(height * 0.4));
|
|
20207
|
+
}
|
|
20208
|
+
function byY(a, b) {
|
|
20209
|
+
return a._internal_y - b._internal_y;
|
|
20210
|
+
}
|
|
20211
|
+
const layouts = new WeakMap();
|
|
20212
|
+
/** The layout is shared by every position line on the same chart. */
|
|
20213
|
+
function acquireLabelLayout(chart, ownerId) {
|
|
20214
|
+
let layout = layouts.get(chart);
|
|
20215
|
+
if (!layout) {
|
|
20216
|
+
layout = new PositionLineLabelLayout();
|
|
20217
|
+
layouts.set(chart, layout);
|
|
20218
|
+
}
|
|
20219
|
+
layout._internal_register(ownerId);
|
|
20220
|
+
return layout;
|
|
20221
|
+
}
|
|
20222
|
+
function releaseLabelLayout(chart, ownerId) {
|
|
20223
|
+
const layout = layouts.get(chart);
|
|
20224
|
+
if (!layout) {
|
|
20225
|
+
return;
|
|
20226
|
+
}
|
|
20227
|
+
layout._internal_unregister(ownerId);
|
|
20228
|
+
if (layout._internal_isEmpty()) {
|
|
20229
|
+
layouts.delete(chart);
|
|
20230
|
+
}
|
|
20231
|
+
}
|
|
20232
|
+
|
|
20086
20233
|
const positionLineDefaultColors = {
|
|
20087
20234
|
entry: '#2962FF',
|
|
20088
20235
|
takeProfit: '#26A17B',
|
|
@@ -20115,12 +20262,12 @@ class PositionLineRenderer {
|
|
|
20115
20262
|
// line, so the narrowest target is tested first.
|
|
20116
20263
|
for (const layout of this._private__layouts) {
|
|
20117
20264
|
if (layout._internal_closable && x >= layout._internal_closeLeft && x <= layout._internal_closeRight &&
|
|
20118
|
-
Math.abs(y - layout.
|
|
20265
|
+
Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
|
|
20119
20266
|
return { _internal_level: layout._internal_level, _internal_part: 'close' };
|
|
20120
20267
|
}
|
|
20121
20268
|
}
|
|
20122
20269
|
for (const layout of this._private__layouts) {
|
|
20123
|
-
if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight && Math.abs(y - layout.
|
|
20270
|
+
if (x >= layout._internal_pillLeft && x <= layout._internal_pillRight && Math.abs(y - layout._internal_labelY) <= layout._internal_height / 2) {
|
|
20124
20271
|
return { _internal_level: layout._internal_level, _internal_part: 'body' };
|
|
20125
20272
|
}
|
|
20126
20273
|
}
|
|
@@ -20170,7 +20317,8 @@ class PositionLineRenderer {
|
|
|
20170
20317
|
const pillWidth = badgeWidth + labelWidth + closeWidth;
|
|
20171
20318
|
const pillRight = Math.max(pillWidth, lineEnd - 8 /* Constants.LabelGap */);
|
|
20172
20319
|
const pillLeft = pillRight - pillWidth;
|
|
20173
|
-
const
|
|
20320
|
+
const labelY = level._internal_y + level._internal_labelOffsetY;
|
|
20321
|
+
const top = labelY - height / 2;
|
|
20174
20322
|
this._private__drawLineSegments(scope, level, pillLeft, pillRight, lineEnd);
|
|
20175
20323
|
this._private__drawPill(scope, data, level, { _internal_left: pillLeft, _internal_top: top, _internal_width: pillWidth, _internal_height: height });
|
|
20176
20324
|
let cellLeft = pillLeft;
|
|
@@ -20183,7 +20331,7 @@ class PositionLineRenderer {
|
|
|
20183
20331
|
ctx.scale(hpr, vpr);
|
|
20184
20332
|
ctx.textAlign = 'center';
|
|
20185
20333
|
ctx.fillStyle = data._internal_textColor ?? level._internal_color;
|
|
20186
|
-
ctx.fillText(level._internal_text, cellLeft + labelWidth / 2,
|
|
20334
|
+
ctx.fillText(level._internal_text, cellLeft + labelWidth / 2, labelY);
|
|
20187
20335
|
ctx.restore();
|
|
20188
20336
|
cellLeft += labelWidth;
|
|
20189
20337
|
if (level._internal_closable) {
|
|
@@ -20193,6 +20341,7 @@ class PositionLineRenderer {
|
|
|
20193
20341
|
return {
|
|
20194
20342
|
_internal_level: level._internal_level,
|
|
20195
20343
|
_internal_y: level._internal_y,
|
|
20344
|
+
_internal_labelY: labelY,
|
|
20196
20345
|
_internal_height: height,
|
|
20197
20346
|
_internal_pillLeft: pillLeft,
|
|
20198
20347
|
_internal_pillRight: pillRight,
|
|
@@ -20211,12 +20360,20 @@ class PositionLineRenderer {
|
|
|
20211
20360
|
ctx.lineWidth = lineWidth;
|
|
20212
20361
|
setLineStyle(ctx, level._internal_lineStyle);
|
|
20213
20362
|
ctx.beginPath();
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
ctx.moveTo(
|
|
20363
|
+
if (level._internal_labelOffsetY !== 0) {
|
|
20364
|
+
// The label has been fanned off its line, so breaking the line for it
|
|
20365
|
+
// would leave a gap with nothing in it.
|
|
20366
|
+
ctx.moveTo(0, y);
|
|
20218
20367
|
ctx.lineTo(Math.round(lineEnd * hpr), y);
|
|
20219
20368
|
}
|
|
20369
|
+
else {
|
|
20370
|
+
ctx.moveTo(0, y);
|
|
20371
|
+
ctx.lineTo(Math.round(Math.max(0, pillLeft - 8 /* Constants.LabelGap */) * hpr), y);
|
|
20372
|
+
if (lineEnd > pillRight + 8 /* Constants.LabelGap */) {
|
|
20373
|
+
ctx.moveTo(Math.round((pillRight + 8 /* Constants.LabelGap */) * hpr), y);
|
|
20374
|
+
ctx.lineTo(Math.round(lineEnd * hpr), y);
|
|
20375
|
+
}
|
|
20376
|
+
}
|
|
20220
20377
|
ctx.stroke();
|
|
20221
20378
|
ctx.restore();
|
|
20222
20379
|
}
|
|
@@ -20411,6 +20568,7 @@ class PositionLine {
|
|
|
20411
20568
|
this._private__theme = { ...positionLineThemeDefaults, ...options.theme };
|
|
20412
20569
|
this._private__paneViews = [this._private__paneView];
|
|
20413
20570
|
this._private__axisViews = positionLineLevels.map((level) => new PositionLineAxisView(() => this._private__axisLabel(level)));
|
|
20571
|
+
this._private__labelLayout = acquireLabelLayout(this._private__chart, this._private__id);
|
|
20414
20572
|
this._private__series.attachPrimitive(this);
|
|
20415
20573
|
acquireController(this._private__chart)?._internal_register(this);
|
|
20416
20574
|
}
|
|
@@ -20497,6 +20655,23 @@ class PositionLine {
|
|
|
20497
20655
|
const price = this._private__series.coordinateToPrice(paneY);
|
|
20498
20656
|
return price === null ? null : price;
|
|
20499
20657
|
}
|
|
20658
|
+
/**
|
|
20659
|
+
* Where the level being dragged actually sits. The controller measures the
|
|
20660
|
+
* pointer against it so the level moves by what the pointer moved, instead
|
|
20661
|
+
* of jumping to sit under it — which matters most when the label has been
|
|
20662
|
+
* fanned away from its own line.
|
|
20663
|
+
*/
|
|
20664
|
+
dragAnchorY() {
|
|
20665
|
+
if (this._private__dragLevel === null) {
|
|
20666
|
+
return null;
|
|
20667
|
+
}
|
|
20668
|
+
const price = this._private__levelOptions(this._private__dragLevel)?.price;
|
|
20669
|
+
if (price === undefined || !isFinite(price)) {
|
|
20670
|
+
return null;
|
|
20671
|
+
}
|
|
20672
|
+
const y = this._private__series.priceToCoordinate(price);
|
|
20673
|
+
return y === null ? null : y;
|
|
20674
|
+
}
|
|
20500
20675
|
beginDrag() {
|
|
20501
20676
|
this._private__dragLevel = this._private__hoveredLevel;
|
|
20502
20677
|
if (this._private__dragLevel === null) {
|
|
@@ -20645,6 +20820,7 @@ class PositionLine {
|
|
|
20645
20820
|
*/
|
|
20646
20821
|
remove() {
|
|
20647
20822
|
releaseController(this._private__chart, this);
|
|
20823
|
+
releaseLabelLayout(this._private__chart, this._private__id);
|
|
20648
20824
|
this._private__series.detachPrimitive(this);
|
|
20649
20825
|
}
|
|
20650
20826
|
requestUpdate() {
|
|
@@ -20690,7 +20866,11 @@ class PositionLine {
|
|
|
20690
20866
|
if (!this._private__attached || this._private__options.visible === false) {
|
|
20691
20867
|
return null;
|
|
20692
20868
|
}
|
|
20869
|
+
const layout = this._private__chart.options()['layout'];
|
|
20870
|
+
const fontSize = this._private__theme.fontSize ?? layout.fontSize;
|
|
20871
|
+
const labelHeight = fontSize + this._private__theme.paddingY * 2;
|
|
20693
20872
|
const levels = [];
|
|
20873
|
+
const claims = [];
|
|
20694
20874
|
for (const level of positionLineLevels) {
|
|
20695
20875
|
const options = this._private__levelOptions(level);
|
|
20696
20876
|
// A level added through a patch can be missing its price until the
|
|
@@ -20703,9 +20883,11 @@ class PositionLine {
|
|
|
20703
20883
|
continue;
|
|
20704
20884
|
}
|
|
20705
20885
|
const isEntry = level === 'entry';
|
|
20886
|
+
claims.push({ _internal_level: level, _internal_y: y, _internal_height: labelHeight });
|
|
20706
20887
|
levels.push({
|
|
20707
20888
|
_internal_level: level,
|
|
20708
20889
|
_internal_y: y,
|
|
20890
|
+
_internal_labelOffsetY: 0,
|
|
20709
20891
|
_internal_color: options.color ?? positionLineDefaultColors[level],
|
|
20710
20892
|
_internal_text: options.formatText ? options.formatText(options.price) : options.text ?? '',
|
|
20711
20893
|
_internal_badge: options.badge ?? '',
|
|
@@ -20717,10 +20899,15 @@ class PositionLine {
|
|
|
20717
20899
|
});
|
|
20718
20900
|
}
|
|
20719
20901
|
if (levels.length === 0) {
|
|
20902
|
+
this._private__labelLayout._internal_setClaims(this._private__id, []);
|
|
20720
20903
|
return null;
|
|
20721
20904
|
}
|
|
20722
|
-
|
|
20723
|
-
|
|
20905
|
+
// Published before the offsets are read so every line on the chart —
|
|
20906
|
+
// positions, pending orders, alerts — is fanned against the same set.
|
|
20907
|
+
this._private__labelLayout._internal_setClaims(this._private__id, claims);
|
|
20908
|
+
for (const level of levels) {
|
|
20909
|
+
level._internal_labelOffsetY = this._private__labelLayout._internal_offsetFor(this._private__id, level._internal_level);
|
|
20910
|
+
}
|
|
20724
20911
|
return {
|
|
20725
20912
|
_internal_levels: levels,
|
|
20726
20913
|
_internal_background: this._private__theme.background ?? resolveBackgroundColor(layout.background),
|
|
@@ -27003,7 +27190,7 @@ class BrushTool extends DrawingToolBase {
|
|
|
27003
27190
|
if (this._private__isOverAnotherDrawing()) {
|
|
27004
27191
|
return;
|
|
27005
27192
|
}
|
|
27006
|
-
const point = this._private__toPanePoint(event);
|
|
27193
|
+
const point = this._private__toPanePoint(event, false);
|
|
27007
27194
|
if (point === null) {
|
|
27008
27195
|
return;
|
|
27009
27196
|
}
|
|
@@ -27022,7 +27209,7 @@ class BrushTool extends DrawingToolBase {
|
|
|
27022
27209
|
if (!this._private__isDrawing) {
|
|
27023
27210
|
return;
|
|
27024
27211
|
}
|
|
27025
|
-
const point = this._private__toPanePoint(event);
|
|
27212
|
+
const point = this._private__toPanePoint(event, true);
|
|
27026
27213
|
if (point === null) {
|
|
27027
27214
|
return;
|
|
27028
27215
|
}
|
|
@@ -27093,13 +27280,51 @@ class BrushTool extends DrawingToolBase {
|
|
|
27093
27280
|
}
|
|
27094
27281
|
this._private__pointerId = null;
|
|
27095
27282
|
}
|
|
27096
|
-
|
|
27283
|
+
/**
|
|
27284
|
+
* Where a press lands relative to the drawing area, or null if it lands
|
|
27285
|
+
* outside it. `clamp` pins the point to the edge instead, for a stroke that
|
|
27286
|
+
* is already under way.
|
|
27287
|
+
*/
|
|
27288
|
+
_private__toPanePoint(event, clamp) {
|
|
27289
|
+
const area = this._private__drawArea();
|
|
27290
|
+
if (area === null) {
|
|
27291
|
+
return null;
|
|
27292
|
+
}
|
|
27293
|
+
const x = event.clientX - area._internal_left;
|
|
27294
|
+
const y = event.clientY - area._internal_top;
|
|
27295
|
+
if (clamp) {
|
|
27296
|
+
return {
|
|
27297
|
+
_internal_x: Math.max(0, Math.min(area._internal_width, x)),
|
|
27298
|
+
_internal_y: Math.max(0, Math.min(area._internal_height, y)),
|
|
27299
|
+
};
|
|
27300
|
+
}
|
|
27301
|
+
if (x < 0 || x > area._internal_width || y < 0 || y > area._internal_height) {
|
|
27302
|
+
return null;
|
|
27303
|
+
}
|
|
27304
|
+
return { _internal_x: x, _internal_y: y };
|
|
27305
|
+
}
|
|
27306
|
+
/**
|
|
27307
|
+
* The pane's element is the whole row, price axis cells included, so its
|
|
27308
|
+
* bounds are not the drawing area's. Taking them for it is what let a press
|
|
27309
|
+
* on an axis start a stroke — and be swallowed, leaving the chart unable to
|
|
27310
|
+
* be stretched while the brush was armed.
|
|
27311
|
+
*/
|
|
27312
|
+
_private__drawArea() {
|
|
27097
27313
|
const paneElement = this._private__paneElement();
|
|
27098
27314
|
if (paneElement === null) {
|
|
27099
27315
|
return null;
|
|
27100
27316
|
}
|
|
27101
27317
|
const rect = paneElement.getBoundingClientRect();
|
|
27102
|
-
|
|
27318
|
+
let left = 0;
|
|
27319
|
+
let width = rect.width;
|
|
27320
|
+
// The time scale measures the drawing area; the left axis, when shown, is
|
|
27321
|
+
// what stands between it and the row's edge.
|
|
27322
|
+
const paneWidth = this._chart.timeScale().width();
|
|
27323
|
+
if (paneWidth > 0) {
|
|
27324
|
+
left = this._chart.priceScale('left').width();
|
|
27325
|
+
width = paneWidth;
|
|
27326
|
+
}
|
|
27327
|
+
return { _internal_left: rect.left + left, _internal_top: rect.top, _internal_width: width, _internal_height: rect.height };
|
|
27103
27328
|
}
|
|
27104
27329
|
_private__paneElement() {
|
|
27105
27330
|
try {
|
|
@@ -30458,7 +30683,7 @@ const customSeriesDefaultOptions = {
|
|
|
30458
30683
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
30459
30684
|
*/
|
|
30460
30685
|
function version() {
|
|
30461
|
-
return "2.3.
|
|
30686
|
+
return "2.3.2";
|
|
30462
30687
|
}
|
|
30463
30688
|
|
|
30464
30689
|
export { areaSeries as AreaSeries, ArrowTool, barSeries as BarSeries, baselineSeries as BaselineSeries, BrushTool, candlestickSeries as CandlestickSeries, CircleTool, ColorType, CrossLineTool, CrosshairMode, DEFAULT_SESSIONS, DraggablePriceLine, DrawingToolsManager, EXTENDED_FIBONACCI_RATIOS, FibonacciCalculator, FibonacciExtensionTool, FibonacciFanTool, FibonacciTool, GanttTool, histogramSeries as HistogramSeries, HorizontalLineTool, InteractiveLineManager, LastPriceAnimationMode, lineSeries as LineSeries, LineStyle, LineType, MismatchDirection, ParallelChannelTool, PitchforkTool, PolygonTool, PositionCalculator, PositionLine, PositionMarkersManager, PositionTool, PriceLineSource, PriceScaleMode, RectangleTool, RulerCalculator, RulerTool, STANDARD_FIBONACCI_RATIOS, TextTool, TickMarkType, TrackingModeExitMode, TradingSessionsIndicator, TrendLineTool, VerticalLineTool, VolumeProfileIndicator, applyADX, applyATR, applyBollingerBands, applyCCI, applyDonchianChannels, applyEMA, applyHeikinAshi, applyIchimoku, applyKeltnerChannels, applyMACD, applyMFI, applyOBV, applyParabolicSAR, applyPivotPoints, applyRSI, applySMA, applyStochastic, applySuperTrend, applyVWAP, applyVolume, applyWMA, applyWilliamsR, calculateHeikinAshi, calculatePipConfig, coordinateFromTime, createArrowTool, createBrushTool, createChart, createChartEx, createCircleTool, createCrossLineTool, createFibonacciExtensionTool, createFibonacciFanTool, createFibonacciTool, createGanttTool, createHorizontalLineTool, createImageWatermark, createInteractiveLineManager, createOptionsChart, createParallelChannelTool, createPitchforkTool, createPolygonTool, createPositionLine, createPositionMarkers, createPositionTool, createRectangleTool, createRulerTool, createSeriesMarkers, createTextTool, createTextWatermark, createTradingLine, createTradingSessionsIndicator, createTrendLineTool, createUpDownMarkers, createVerticalLineTool, createVolumeProfileIndicator, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, getPipConfig, hideSeriesPaint, isBusinessDay, isUTCTimestamp, setSeriesVolumes, setVolumeProfileData, timeFromCoordinate, version };
|