feat: enable free movement of measurement tool label box
This commit is contained in:
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user