feat: enable free movement of measurement tool label box

This commit is contained in:
DiTus
2026-03-21 14:11:39 +01:00
parent b2a4a6963d
commit a1564c25a7

View File

@ -221,7 +221,8 @@ export class DrawingManager {
type: 'measure', type: 'measure',
p1: { time: pos.time, price: pos.price }, p1: { time: pos.time, price: pos.price },
p2: { time: pos.time, price: pos.price }, p2: { time: pos.time, price: pos.price },
color: '#26a69a' color: '#26a69a',
labelOffset: { x: 0, y: 0 }
}; };
this.update(); this.update();
return; return;
@ -285,11 +286,18 @@ export class DrawingManager {
handleMouseMove(e) { handleMouseMove(e) {
const pos = this.getMousePos(e); const pos = this.getMousePos(e);
// Hover cursor logic
if (!this.isMouseDown && !this.activeTool) { if (!this.isMouseDown && !this.activeTool) {
const hit = this.findHit(pos.x, pos.y); const hit = this.findHit(pos.x, pos.y);
this.container.style.cursor = hit ? 'pointer' : 'default'; if (hit) {
this.container.style.cursor = hit.part === 'label' ? 'move' : 'pointer';
} else {
this.container.style.cursor = 'default';
}
} }
// Track measurement even if mouse is up (Click-Move-Click)
if (this.currentDrawing && this.currentDrawing.type === 'measure') { if (this.currentDrawing && this.currentDrawing.type === 'measure') {
if (pos.time !== null) { if (pos.time !== null) {
this.currentDrawing.p2 = { time: pos.time, price: pos.price }; this.currentDrawing.p2 = { time: pos.time, price: pos.price };
@ -303,6 +311,18 @@ export class DrawingManager {
if (this.selectedDrawing && this.dragMode) { if (this.selectedDrawing && this.dragMode) {
if (pos.time === null || pos.price === null) return; if (pos.time === null || pos.price === null) return;
const d = this.selectedDrawing; const d = this.selectedDrawing;
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;
d.labelOffset.x += dx;
d.labelOffset.y += dy;
this.dragStartPos = pos;
this.update();
return; // Critical: exit here so we don't move measurement points
}
if (this.dragMode === 'p1') { if (this.dragMode === 'p1') {
d.p1 = { time: pos.time, price: pos.price }; d.p1 = { time: pos.time, price: pos.price };
} else if (this.dragMode === 'p2') { } else if (this.dragMode === 'p2') {
@ -361,6 +381,15 @@ export class DrawingManager {
const threshold = 10; const threshold = 10;
for (let i = this.drawings.length - 1; i >= 0; i--) { for (let i = this.drawings.length - 1; i >= 0; i--) {
const d = this.drawings[i]; const d = this.drawings[i];
// Check for label hit first (highest z-order)
if (d.type === 'measure' && d.labelPos) {
if (x >= d.labelPos.x && x <= d.labelPos.x + d.labelPos.width &&
y >= d.labelPos.y && y <= d.labelPos.y + d.labelPos.height) {
return { drawing: d, part: 'label' };
}
}
if (d.p1 && d.p2) { if (d.p1 && d.p2) {
const x1 = this.chart.timeScale().timeToCoordinate(d.p1.time); const x1 = this.chart.timeScale().timeToCoordinate(d.p1.time);
const y1 = this.series.priceToCoordinate(d.p1.price); const y1 = this.series.priceToCoordinate(d.p1.price);
@ -645,8 +674,14 @@ export class DrawingManager {
ctx.font = '500 12px Inter'; ctx.font = '500 12px Inter';
const labelWidth = Math.max(...labelLines.map(l => ctx.measureText(l).width)) + 24; const labelWidth = Math.max(...labelLines.map(l => ctx.measureText(l).width)) + 24;
const labelHeight = 65; const labelHeight = 65;
const labelX = x2 - labelWidth / 2; const defaultLabelX = x2 - labelWidth / 2;
const labelY = isUp ? y2 - labelHeight - 10 : y2 + 10; const defaultLabelY = isUp ? y2 - labelHeight - 10 : y2 + 10;
const labelX = defaultLabelX + (d.labelOffset?.x || 0);
const labelY = defaultLabelY + (d.labelOffset?.y || 0);
// Store label position for hit detection
d.labelPos = { x: labelX, y: labelY, width: labelWidth, height: labelHeight };
// Solid Box // Solid Box
ctx.fillStyle = color; ctx.fillStyle = color;