@pipsend/charts 0.0.8 → 0.0.10
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/README.md +3 -1
- package/dist/pipsend-charts.development.mjs +116 -110
- package/dist/pipsend-charts.production.mjs +2 -2
- package/dist/pipsend-charts.standalone.development.js +116 -110
- package/dist/pipsend-charts.standalone.development.mjs +116 -110
- package/dist/pipsend-charts.standalone.production.js +2 -2
- package/dist/pipsend-charts.standalone.production.mjs +2 -2
- package/dist/typings.d.ts +17 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @license
|
|
3
|
-
* Pipsend Charts v0.0.
|
|
3
|
+
* Pipsend Charts v0.0.10-dev+202510282321
|
|
4
4
|
* Copyright (c) 2025 Pipsend
|
|
5
5
|
* Licensed under MIT License
|
|
6
6
|
* Built on TradingView Lightweight Charts™ (Apache 2.0)
|
|
@@ -6415,7 +6415,12 @@ class ChartModel {
|
|
|
6415
6415
|
series._internal_destroy();
|
|
6416
6416
|
}
|
|
6417
6417
|
this._private__timeScale._internal_recalculateIndicesWithData();
|
|
6418
|
+
const paneCountBefore = this._private__panes.length;
|
|
6418
6419
|
this._private__cleanupIfPaneIsEmpty(paneImpl);
|
|
6420
|
+
// If a pane was removed, trigger full update to refresh the layout
|
|
6421
|
+
if (this._private__panes.length < paneCountBefore) {
|
|
6422
|
+
this._internal_fullUpdate();
|
|
6423
|
+
}
|
|
6419
6424
|
}
|
|
6420
6425
|
_internal_moveSeriesToScale(series, targetScaleId) {
|
|
6421
6426
|
const pane = ensureNotNull(this._internal_paneForSource(series));
|
|
@@ -16537,6 +16542,8 @@ class DraggablePriceLine {
|
|
|
16537
16542
|
this._private__isDragging = false;
|
|
16538
16543
|
this._private__container = null;
|
|
16539
16544
|
this._private__unsubscribeHandlers = [];
|
|
16545
|
+
this._private__isHovering = false;
|
|
16546
|
+
this._private__originalColor = '';
|
|
16540
16547
|
this._private__chart = chart;
|
|
16541
16548
|
this._private__series = series;
|
|
16542
16549
|
this._private__options = {
|
|
@@ -16552,6 +16559,7 @@ class DraggablePriceLine {
|
|
|
16552
16559
|
}
|
|
16553
16560
|
}
|
|
16554
16561
|
_private__createPriceLine() {
|
|
16562
|
+
this._private__originalColor = this._private__options.color;
|
|
16555
16563
|
this._private__priceLine = this._private__series.createPriceLine({
|
|
16556
16564
|
price: this._private__options.price,
|
|
16557
16565
|
color: this._private__options.color,
|
|
@@ -16567,8 +16575,12 @@ class DraggablePriceLine {
|
|
|
16567
16575
|
return;
|
|
16568
16576
|
this._private__container = chartElement;
|
|
16569
16577
|
const handleMouseDown = (e) => {
|
|
16578
|
+
// Solo permitir drag desde el área del gráfico (no desde el price axis)
|
|
16579
|
+
if (!this._private__isInChartArea(e)) {
|
|
16580
|
+
return;
|
|
16581
|
+
}
|
|
16570
16582
|
const price = this._private__getPriceFromY(e.clientY);
|
|
16571
|
-
if (this.
|
|
16583
|
+
if (this._private__isOnLine(e, price)) {
|
|
16572
16584
|
this._private__isDragging = true;
|
|
16573
16585
|
this._private__container.style.cursor = 'ns-resize';
|
|
16574
16586
|
if (this._private__options.onDragStart) {
|
|
@@ -16585,15 +16597,24 @@ class DraggablePriceLine {
|
|
|
16585
16597
|
if (this._private__options.onDragMove) {
|
|
16586
16598
|
this._private__options.onDragMove(newPrice);
|
|
16587
16599
|
}
|
|
16600
|
+
// Prevenir que el gráfico se mueva mientras arrastramos la línea
|
|
16601
|
+
e.preventDefault();
|
|
16602
|
+
e.stopPropagation();
|
|
16588
16603
|
}
|
|
16589
16604
|
else {
|
|
16590
|
-
//
|
|
16605
|
+
// Solo mostrar hover si está en el área del gráfico
|
|
16606
|
+
if (!this._private__isInChartArea(e)) {
|
|
16607
|
+
this._private__setHoverState(false);
|
|
16608
|
+
return;
|
|
16609
|
+
}
|
|
16591
16610
|
const price = this._private__getPriceFromY(e.clientY);
|
|
16592
|
-
if (this.
|
|
16611
|
+
if (this._private__isOnLine(e, price)) {
|
|
16593
16612
|
this._private__container.style.cursor = 'ns-resize';
|
|
16613
|
+
this._private__setHoverState(true);
|
|
16594
16614
|
}
|
|
16595
16615
|
else {
|
|
16596
16616
|
this._private__container.style.cursor = 'default';
|
|
16617
|
+
this._private__setHoverState(false);
|
|
16597
16618
|
}
|
|
16598
16619
|
}
|
|
16599
16620
|
};
|
|
@@ -16601,69 +16622,50 @@ class DraggablePriceLine {
|
|
|
16601
16622
|
if (this._private__isDragging) {
|
|
16602
16623
|
this._private__isDragging = false;
|
|
16603
16624
|
this._private__container.style.cursor = 'default';
|
|
16625
|
+
this._private__setHoverState(false);
|
|
16604
16626
|
if (this._private__options.onDragEnd) {
|
|
16605
16627
|
this._private__options.onDragEnd(this._private__options.price);
|
|
16606
16628
|
}
|
|
16607
16629
|
}
|
|
16608
16630
|
};
|
|
16631
|
+
const handleMouseLeave = (e) => {
|
|
16632
|
+
if (this._private__isDragging) {
|
|
16633
|
+
this._private__isDragging = false;
|
|
16634
|
+
this._private__setHoverState(false);
|
|
16635
|
+
if (this._private__options.onDragEnd) {
|
|
16636
|
+
this._private__options.onDragEnd(this._private__options.price);
|
|
16637
|
+
}
|
|
16638
|
+
}
|
|
16639
|
+
else {
|
|
16640
|
+
this._private__setHoverState(false);
|
|
16641
|
+
}
|
|
16642
|
+
};
|
|
16609
16643
|
this._private__container.addEventListener('mousedown', handleMouseDown);
|
|
16610
16644
|
this._private__container.addEventListener('mousemove', handleMouseMove);
|
|
16611
16645
|
this._private__container.addEventListener('mouseup', handleMouseUp);
|
|
16612
|
-
this._private__container.addEventListener('mouseleave',
|
|
16646
|
+
this._private__container.addEventListener('mouseleave', handleMouseLeave);
|
|
16613
16647
|
// Store unsubscribe handlers
|
|
16614
16648
|
this._private__unsubscribeHandlers.push(() => {
|
|
16615
16649
|
this._private__container?.removeEventListener('mousedown', handleMouseDown);
|
|
16616
16650
|
this._private__container?.removeEventListener('mousemove', handleMouseMove);
|
|
16617
16651
|
this._private__container?.removeEventListener('mouseup', handleMouseUp);
|
|
16618
|
-
this._private__container?.removeEventListener('mouseleave',
|
|
16652
|
+
this._private__container?.removeEventListener('mouseleave', handleMouseLeave);
|
|
16619
16653
|
});
|
|
16620
16654
|
}
|
|
16621
16655
|
_private__getPriceFromY(clientY) {
|
|
16622
16656
|
try {
|
|
16623
|
-
//
|
|
16657
|
+
// Usar la API del chart para convertir coordenada Y a precio
|
|
16658
|
+
// Esto garantiza que usamos exactamente la misma escala que el chart
|
|
16624
16659
|
const chartElement = this._private__chart.chartElement?.() || document.querySelector('.tv-lightweight-charts');
|
|
16625
16660
|
if (!chartElement)
|
|
16626
16661
|
return this._private__options.price;
|
|
16627
16662
|
const rect = chartElement.getBoundingClientRect();
|
|
16628
16663
|
const relativeY = clientY - rect.top;
|
|
16629
|
-
//
|
|
16630
|
-
const
|
|
16631
|
-
|
|
16632
|
-
if (!visibleRange)
|
|
16664
|
+
// Usar coordinateToPrice() - método oficial del chart
|
|
16665
|
+
const price = this._private__series.coordinateToPrice(relativeY);
|
|
16666
|
+
if (price === null) {
|
|
16633
16667
|
return this._private__options.price;
|
|
16634
|
-
// Get series data
|
|
16635
|
-
const seriesData = this._private__series.data();
|
|
16636
|
-
if (!seriesData || seriesData.length === 0)
|
|
16637
|
-
return this._private__options.price;
|
|
16638
|
-
// Calculate min/max price in visible range
|
|
16639
|
-
const startIndex = Math.max(0, Math.floor(visibleRange.from));
|
|
16640
|
-
const endIndex = Math.min(seriesData.length - 1, Math.ceil(visibleRange.to));
|
|
16641
|
-
let minPrice = Infinity;
|
|
16642
|
-
let maxPrice = -Infinity;
|
|
16643
|
-
for (let i = startIndex; i <= endIndex; i++) {
|
|
16644
|
-
const d = seriesData[i];
|
|
16645
|
-
if ('high' in d && 'low' in d) {
|
|
16646
|
-
minPrice = Math.min(minPrice, d.low);
|
|
16647
|
-
maxPrice = Math.max(maxPrice, d.high);
|
|
16648
|
-
}
|
|
16649
|
-
else if ('close' in d) {
|
|
16650
|
-
minPrice = Math.min(minPrice, d.close);
|
|
16651
|
-
maxPrice = Math.max(maxPrice, d.close);
|
|
16652
|
-
}
|
|
16653
|
-
else if ('value' in d) {
|
|
16654
|
-
minPrice = Math.min(minPrice, d.value);
|
|
16655
|
-
maxPrice = Math.max(maxPrice, d.value);
|
|
16656
|
-
}
|
|
16657
16668
|
}
|
|
16658
|
-
// Add 10% padding
|
|
16659
|
-
const padding = (maxPrice - minPrice) * 0.1;
|
|
16660
|
-
minPrice -= padding;
|
|
16661
|
-
maxPrice += padding;
|
|
16662
|
-
// Calculate price from Y position
|
|
16663
|
-
const priceRange = maxPrice - minPrice;
|
|
16664
|
-
const chartHeight = rect.height;
|
|
16665
|
-
const pricePerPixel = priceRange / chartHeight;
|
|
16666
|
-
const price = maxPrice - (relativeY * pricePerPixel);
|
|
16667
16669
|
return price;
|
|
16668
16670
|
}
|
|
16669
16671
|
catch (error) {
|
|
@@ -16671,37 +16673,61 @@ class DraggablePriceLine {
|
|
|
16671
16673
|
return this._private__options.price;
|
|
16672
16674
|
}
|
|
16673
16675
|
}
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
+
/**
|
|
16677
|
+
* Verifica si el mouse está EN la línea (no cerca, sino exactamente sobre ella)
|
|
16678
|
+
* Usa la API de coordenadas del chart para precisión consistente
|
|
16679
|
+
* @param e - Mouse event
|
|
16680
|
+
* @param price - Precio calculado desde la posición Y
|
|
16681
|
+
*/
|
|
16682
|
+
_private__isOnLine(e, price) {
|
|
16676
16683
|
const chartElement = this._private__chart.chartElement?.() || document.querySelector('.tv-lightweight-charts');
|
|
16677
16684
|
if (!chartElement)
|
|
16678
16685
|
return false;
|
|
16686
|
+
// Usar la API del chart para convertir precio a coordenada Y
|
|
16687
|
+
const lineCoordinate = this._private__series.priceToCoordinate(this._private__options.price);
|
|
16688
|
+
if (lineCoordinate === null)
|
|
16689
|
+
return false;
|
|
16690
|
+
// Obtener la coordenada Y del mouse relativa al chart
|
|
16679
16691
|
const rect = chartElement.getBoundingClientRect();
|
|
16680
|
-
const
|
|
16681
|
-
|
|
16692
|
+
const mouseY = e.clientY - rect.top;
|
|
16693
|
+
// Threshold FIJO en píxeles (muy preciso y consistente)
|
|
16694
|
+
const pixelThreshold = 5; // 5 píxeles - siempre igual sin importar el zoom
|
|
16695
|
+
// Comparar directamente en píxeles (más preciso)
|
|
16696
|
+
return Math.abs(mouseY - lineCoordinate) <= pixelThreshold;
|
|
16697
|
+
}
|
|
16698
|
+
/**
|
|
16699
|
+
* Verifica si el mouse está en el área del gráfico (no en el price axis)
|
|
16700
|
+
*/
|
|
16701
|
+
_private__isInChartArea(e) {
|
|
16702
|
+
if (!this._private__container)
|
|
16682
16703
|
return false;
|
|
16683
|
-
//
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
|
|
16692
|
-
|
|
16693
|
-
|
|
16694
|
-
|
|
16695
|
-
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16704
|
+
// Obtener el ancho del price axis (usualmente ~60-80px desde la derecha)
|
|
16705
|
+
const rect = this._private__container.getBoundingClientRect();
|
|
16706
|
+
const priceAxisWidth = 80; // Ancho aproximado del eje de precios
|
|
16707
|
+
// El mouse debe estar ANTES del price axis (área del gráfico)
|
|
16708
|
+
const mouseX = e.clientX - rect.left;
|
|
16709
|
+
const chartAreaWidth = rect.width - priceAxisWidth;
|
|
16710
|
+
return mouseX < chartAreaWidth;
|
|
16711
|
+
}
|
|
16712
|
+
/**
|
|
16713
|
+
* Activa/desactiva el estado de hover (línea negra)
|
|
16714
|
+
*/
|
|
16715
|
+
_private__setHoverState(isHovering) {
|
|
16716
|
+
if (this._private__isHovering === isHovering || !this._private__priceLine)
|
|
16717
|
+
return;
|
|
16718
|
+
this._private__isHovering = isHovering;
|
|
16719
|
+
if (isHovering) {
|
|
16720
|
+
// Cambiar a negro cuando está en hover
|
|
16721
|
+
this._private__priceLine.applyOptions({
|
|
16722
|
+
color: '#000000'
|
|
16723
|
+
});
|
|
16724
|
+
}
|
|
16725
|
+
else {
|
|
16726
|
+
// Restaurar color original
|
|
16727
|
+
this._private__priceLine.applyOptions({
|
|
16728
|
+
color: this._private__originalColor
|
|
16729
|
+
});
|
|
16700
16730
|
}
|
|
16701
|
-
const priceRange = maxPrice - minPrice;
|
|
16702
|
-
const pixelThreshold = 15; // 15 pixels
|
|
16703
|
-
const priceThreshold = (priceRange / rect.height) * pixelThreshold;
|
|
16704
|
-
return Math.abs(price - this._private__options.price) < priceThreshold;
|
|
16705
16731
|
}
|
|
16706
16732
|
_private__updatePrice(newPrice) {
|
|
16707
16733
|
this._private__options.price = newPrice;
|
|
@@ -16714,6 +16740,10 @@ class DraggablePriceLine {
|
|
|
16714
16740
|
*/
|
|
16715
16741
|
applyOptions(options) {
|
|
16716
16742
|
this._private__options = { ...this._private__options, ...options };
|
|
16743
|
+
// Actualizar color original si se proporciona
|
|
16744
|
+
if (options.color) {
|
|
16745
|
+
this._private__originalColor = options.color;
|
|
16746
|
+
}
|
|
16717
16747
|
if (this._private__priceLine && options.price !== undefined) {
|
|
16718
16748
|
this._private__priceLine.applyOptions({
|
|
16719
16749
|
price: options.price,
|
|
@@ -16743,6 +16773,8 @@ class DraggablePriceLine {
|
|
|
16743
16773
|
// Cleanup event listeners
|
|
16744
16774
|
this._private__unsubscribeHandlers.forEach(handler => handler());
|
|
16745
16775
|
this._private__unsubscribeHandlers = [];
|
|
16776
|
+
// Remove hover state
|
|
16777
|
+
this._private__setHoverState(false);
|
|
16746
16778
|
// Remove price line
|
|
16747
16779
|
if (this._private__priceLine) {
|
|
16748
16780
|
this._private__series.removePriceLine(this._private__priceLine);
|
|
@@ -16875,49 +16907,23 @@ class InteractiveLineManager {
|
|
|
16875
16907
|
}
|
|
16876
16908
|
}
|
|
16877
16909
|
_private__getPriceFromMouseEvent(e) {
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
const seriesData = this._private__series.data();
|
|
16889
|
-
if (!seriesData || seriesData.length === 0)
|
|
16890
|
-
return 0;
|
|
16891
|
-
// Calculate min/max price in visible range
|
|
16892
|
-
const startIndex = Math.max(0, Math.floor(visibleRange.from));
|
|
16893
|
-
const endIndex = Math.min(seriesData.length - 1, Math.ceil(visibleRange.to));
|
|
16894
|
-
let minPrice = Infinity;
|
|
16895
|
-
let maxPrice = -Infinity;
|
|
16896
|
-
for (let i = startIndex; i <= endIndex; i++) {
|
|
16897
|
-
const d = seriesData[i];
|
|
16898
|
-
if ('high' in d && 'low' in d) {
|
|
16899
|
-
minPrice = Math.min(minPrice, d.low);
|
|
16900
|
-
maxPrice = Math.max(maxPrice, d.high);
|
|
16901
|
-
}
|
|
16902
|
-
else if ('close' in d) {
|
|
16903
|
-
minPrice = Math.min(minPrice, d.close);
|
|
16904
|
-
maxPrice = Math.max(maxPrice, d.close);
|
|
16905
|
-
}
|
|
16906
|
-
else if ('value' in d) {
|
|
16907
|
-
minPrice = Math.min(minPrice, d.value);
|
|
16908
|
-
maxPrice = Math.max(maxPrice, d.value);
|
|
16910
|
+
try {
|
|
16911
|
+
if (!this._private__container)
|
|
16912
|
+
return 0;
|
|
16913
|
+
// Usar la misma API que usa el dragging para consistencia perfecta
|
|
16914
|
+
const rect = this._private__container.getBoundingClientRect();
|
|
16915
|
+
const relativeY = e.clientY - rect.top;
|
|
16916
|
+
// Usar coordinateToPrice() - método oficial del chart
|
|
16917
|
+
const price = this._private__series.coordinateToPrice(relativeY);
|
|
16918
|
+
if (price === null) {
|
|
16919
|
+
return 0;
|
|
16909
16920
|
}
|
|
16921
|
+
return price;
|
|
16922
|
+
}
|
|
16923
|
+
catch (error) {
|
|
16924
|
+
console.error('Error getting price from mouse event:', error);
|
|
16925
|
+
return 0;
|
|
16910
16926
|
}
|
|
16911
|
-
// Add 10% padding
|
|
16912
|
-
const padding = (maxPrice - minPrice) * 0.1;
|
|
16913
|
-
minPrice -= padding;
|
|
16914
|
-
maxPrice += padding;
|
|
16915
|
-
// Calculate price from Y position
|
|
16916
|
-
const priceRange = maxPrice - minPrice;
|
|
16917
|
-
const chartHeight = rect.height;
|
|
16918
|
-
const pricePerPixel = priceRange / chartHeight;
|
|
16919
|
-
const price = maxPrice - (relativeY * pricePerPixel);
|
|
16920
|
-
return price;
|
|
16921
16927
|
}
|
|
16922
16928
|
/**
|
|
16923
16929
|
* Activa el modo de creación de líneas por clic
|
|
@@ -17078,7 +17084,7 @@ const customSeriesDefaultOptions = {
|
|
|
17078
17084
|
* Returns the current version as a string. For example `'1.0.0'`.
|
|
17079
17085
|
*/
|
|
17080
17086
|
function version() {
|
|
17081
|
-
return "0.0.
|
|
17087
|
+
return "0.0.10-dev+202510282321";
|
|
17082
17088
|
}
|
|
17083
17089
|
|
|
17084
17090
|
export { areaSeries as AreaSeries, barSeries as BarSeries, baselineSeries as BaselineSeries, candlestickSeries as CandlestickSeries, ColorType, CrosshairMode, DraggablePriceLine, histogramSeries as HistogramSeries, InteractiveLineManager, LastPriceAnimationMode, lineSeries as LineSeries, LineStyle, LineType, MismatchDirection, PriceLineSource, PriceScaleMode, TickMarkType, TrackingModeExitMode, applyATR, applyBollingerBands, applyEMA, applyMACD, applyOBV, applyRSI, applySMA, applyStochastic, applyVolume, applyWMA, createChart, createChartEx, createImageWatermark, createInteractiveLineManager, createOptionsChart, createSeriesMarkers, createTextWatermark, createTradingLine, createUpDownMarkers, createYieldCurveChart, customSeriesDefaultOptions, defaultHorzScaleBehavior, isBusinessDay, isUTCTimestamp, setOBVVolumeData, setVolumeData, version };
|