From cdfe8f1a39c64672b1eb6becdc7d644ce1fb09ac Mon Sep 17 00:00:00 2001 From: DiTus Date: Sat, 21 Mar 2026 21:57:28 +0100 Subject: [PATCH] fix: improve timeframe-independent dragging and prevent undefined dragStartPos error --- js/ui/drawing-tools.js | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/js/ui/drawing-tools.js b/js/ui/drawing-tools.js index db4baa3..d6eb959 100644 --- a/js/ui/drawing-tools.js +++ b/js/ui/drawing-tools.js @@ -312,10 +312,17 @@ export class DrawingManager { if (pos.time === null || pos.price === null) return; const d = this.selectedDrawing; + // Safety check for dragStartPos + if (!this.dragStartPos) { + this.dragStartPos = pos; + return; + } + if (this.dragMode === 'label') { // Free movement of ONLY the label field const dx = pos.x - this.dragStartPos.x; const dy = pos.y - this.dragStartPos.y; + if (!d.labelOffset) d.labelOffset = { x: 0, y: 0 }; d.labelOffset.x += dx; d.labelOffset.y += dy; this.dragStartPos = pos; @@ -328,20 +335,34 @@ export class DrawingManager { } else if (this.dragMode === 'p2') { d.p2 = { time: pos.time, price: pos.price }; } else if (this.dragMode === 'all') { - const timeDiff = pos.time - this.dragStartPos.time; + let timeDiff = pos.time - this.dragStartPos.time; const priceDiff = pos.price - this.dragStartPos.price; - if (d.p1 && d.p2) { - d.p1.time = this.startP1.time + timeDiff; - d.p1.price = this.startP1.price + priceDiff; - d.p2.time = this.startP2.time + timeDiff; - d.p2.price = this.startP2.price + priceDiff; - } else if (d.time !== undefined && d.price !== undefined) { - d.time = this.startTime + timeDiff; - d.price = this.startPrice + priceDiff; - } else if (d.price !== undefined) { - d.price = this.startPrice + priceDiff; - } else if (d.time !== undefined) { - d.time = this.startTime + timeDiff; + + // If timeDiff is NaN (e.g., dragged into whitespace on high TF), estimate it + if (isNaN(timeDiff) || pos.time === null) { + const timeScale = this.chart.timeScale(); + const startLogical = timeScale.coordinateToLogical(this.dragStartPos.x); + const currentLogical = timeScale.coordinateToLogical(pos.x); + if (startLogical !== null && currentLogical !== null) { + const logicalDiff = currentLogical - startLogical; + timeDiff = logicalDiff * this.getIntervalSeconds(); + } + } + + if (!isNaN(timeDiff) && !isNaN(priceDiff)) { + if (d.p1 && d.p2) { + d.p1.time = this.startP1.time + timeDiff; + d.p1.price = this.startP1.price + priceDiff; + d.p2.time = this.startP2.time + timeDiff; + d.p2.price = this.startP2.price + priceDiff; + } else if (d.time !== undefined && d.price !== undefined) { + d.time = this.startTime + timeDiff; + d.price = this.startPrice + priceDiff; + } else if (d.price !== undefined) { + d.price = this.startPrice + priceDiff; + } else if (d.time !== undefined) { + d.time = this.startTime + timeDiff; + } } } else if (this.dragMode === 'price') { d.price = pos.price; @@ -391,11 +412,13 @@ export class DrawingManager { } if (d.p1 && d.p2) { - const x1 = this.chart.timeScale().timeToCoordinate(d.p1.time); + const x1 = this.chart.timeScale().timeToCoordinate(this.snapToNearestTime(d.p1.time)); const y1 = this.series.priceToCoordinate(d.p1.price); - const x2 = this.chart.timeScale().timeToCoordinate(d.p2.time); + const x2 = this.chart.timeScale().timeToCoordinate(this.snapToNearestTime(d.p2.time)); const y2 = this.series.priceToCoordinate(d.p2.price); + if (x1 === null || y1 === null || x2 === null || y2 === null) continue; + if (Math.hypot(x - x1, y - y1) < threshold) return { drawing: d, part: 'p1' }; if (Math.hypot(x - x2, y - y2) < threshold) return { drawing: d, part: 'p2' }; @@ -409,10 +432,10 @@ export class DrawingManager { const dy = this.series.priceToCoordinate(d.price); if (Math.abs(y - dy) < threshold) return { drawing: d, part: 'price' }; } else if (d.time !== undefined && d.type === 'vertical_line') { - const dx = this.chart.timeScale().timeToCoordinate(d.time); + const dx = this.chart.timeScale().timeToCoordinate(this.snapToNearestTime(d.time)); if (Math.abs(x - dx) < threshold) return { drawing: d, part: 'time' }; } else if (d.time !== undefined && d.price !== undefined) { - const dx = this.chart.timeScale().timeToCoordinate(d.time); + const dx = this.chart.timeScale().timeToCoordinate(this.snapToNearestTime(d.time)); const dy = this.series.priceToCoordinate(d.price); if (Math.hypot(x - dx, y - dy) < threshold) return { drawing: d, part: 'all' }; }