fix: Ensure horizontal/vertical line text is visible on screen
- Add bounds checking to only render text when line is on screen - Fix text positioning to be consistent with line position
This commit is contained in:
@ -819,7 +819,7 @@ export class DrawingManager {
|
||||
}
|
||||
} else if (d.type === 'horizontal_line') {
|
||||
const y = series.priceToCoordinate(d.price);
|
||||
if (y !== null) {
|
||||
if (y !== null && y >= 0 && y <= scope.mediaSize.height) {
|
||||
ctx.save();
|
||||
ctx.strokeStyle = d.opacity !== undefined ? this.hexToRgba(d.color, d.opacity) : d.color;
|
||||
ctx.lineWidth = d.width || 2;
|
||||
@ -837,51 +837,72 @@ export class DrawingManager {
|
||||
ctx.beginPath(); ctx.arc(0, y, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
||||
}
|
||||
|
||||
// Render Text if present
|
||||
// Store label position for hit detection (before rendering)
|
||||
let textX = scope.mediaSize.width / 2;
|
||||
let textY = y;
|
||||
let labelPos = null;
|
||||
if (d.text) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
const fontSize = d.fontSize || 14;
|
||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||
ctx.fillStyle = d.textColor || d.color;
|
||||
const tx = scope.mediaSize.width / 2;
|
||||
const ty = y;
|
||||
const offset = 10;
|
||||
const finalTy = d.alignVert === 'top' ? ty - offset : (d.alignVert === 'bottom' ? ty + offset : ty);
|
||||
|
||||
ctx.textAlign = d.alignHorz || 'center';
|
||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||
ctx.fillText(d.text, tx, finalTy);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Store label position for hit detection
|
||||
if (d.text) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
const fontSize = d.fontSize || 14;
|
||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||
const font = `${fontStyle}${fontSize}px Inter`;
|
||||
ctx.font = font;
|
||||
const metrics = ctx.measureText(d.text);
|
||||
const labelWidth = metrics.width + 16;
|
||||
const labelHeight = 24;
|
||||
const defaultLabelX = scope.mediaSize.width / 2 - labelWidth / 2;
|
||||
const offset = 10;
|
||||
const defaultLabelY = d.alignVert === 'top' ? y - 40 : (d.alignVert === 'bottom' ? y + 20 : y - 12);
|
||||
d.labelPos = {
|
||||
labelPos = {
|
||||
x: defaultLabelX + (d.labelOffset?.x || 0),
|
||||
y: defaultLabelY + (d.labelOffset?.y || 0),
|
||||
width: labelWidth,
|
||||
height: labelHeight
|
||||
};
|
||||
textX = scope.mediaSize.width / 2;
|
||||
textY = d.alignVert === 'top' ? y - offset : (d.alignVert === 'bottom' ? y + offset : y);
|
||||
}
|
||||
|
||||
// Render Text if present and visible on screen
|
||||
if (d.text && labelPos && labelPos.y >= 0 && labelPos.y <= scope.mediaSize.height) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
ctx.font = font;
|
||||
ctx.fillStyle = d.textColor || d.color;
|
||||
|
||||
ctx.textAlign = d.alignHorz || 'center';
|
||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||
ctx.fillText(d.text, textX, textY);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Store label position for hit detection
|
||||
if (labelPos) {
|
||||
d.labelPos = labelPos;
|
||||
}
|
||||
|
||||
// Render Text if present
|
||||
if (d.text) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||
ctx.fillStyle = d.textColor || d.color;
|
||||
|
||||
ctx.textAlign = d.alignHorz || 'center';
|
||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||
ctx.fillText(d.text, textX, textY);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Store label position for hit detection
|
||||
if (labelPos) {
|
||||
d.labelPos = labelPos;
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
} else if (d.type === 'vertical_line') {
|
||||
const x = this.timeToX(d.time);
|
||||
if (x !== null) {
|
||||
if (x !== null && x >= 0 && x <= scope.mediaSize.width) {
|
||||
ctx.save();
|
||||
ctx.strokeStyle = d.opacity !== undefined ? this.hexToRgba(d.color, d.opacity) : d.color;
|
||||
ctx.lineWidth = d.width || 2;
|
||||
@ -899,46 +920,47 @@ export class DrawingManager {
|
||||
ctx.beginPath(); ctx.arc(x, 0, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
||||
}
|
||||
|
||||
// Render Text if present
|
||||
// Store label position for hit detection (before rendering)
|
||||
let textX = x;
|
||||
let textY = 0;
|
||||
let labelPos = null;
|
||||
if (d.text) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
const fontSize = d.fontSize || 14;
|
||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||
ctx.fillStyle = d.textColor || d.color;
|
||||
const tx = x;
|
||||
const ty = 0;
|
||||
const offset = 10;
|
||||
const finalTy = d.alignVert === 'top' ? ty - offset : (d.alignVert === 'bottom' ? ty + offset : ty);
|
||||
|
||||
ctx.textAlign = d.alignHorz || 'center';
|
||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||
ctx.fillText(d.text, tx, finalTy);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Store label position for hit detection
|
||||
if (d.text) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
const fontSize = d.fontSize || 14;
|
||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||
const font = `${fontStyle}${fontSize}px Inter`;
|
||||
ctx.font = font;
|
||||
const metrics = ctx.measureText(d.text);
|
||||
const labelWidth = metrics.width + 16;
|
||||
const labelHeight = 24;
|
||||
const defaultLabelX = x - labelWidth / 2;
|
||||
const offset = 10;
|
||||
const defaultLabelY = d.alignVert === 'top' ? -50 : (d.alignVert === 'bottom' ? 20 : -12);
|
||||
d.labelPos = {
|
||||
x: defaultLabelX + (d.labelOffset?.x || 0),
|
||||
labelPos = {
|
||||
x: x - labelWidth / 2 + (d.labelOffset?.x || 0),
|
||||
y: defaultLabelY + (d.labelOffset?.y || 0),
|
||||
width: labelWidth,
|
||||
height: labelHeight
|
||||
};
|
||||
textY = d.alignVert === 'top' ? -offset : (d.alignVert === 'bottom' ? offset : 0);
|
||||
}
|
||||
|
||||
// Render Text if present and visible on screen
|
||||
if (d.text && labelPos && labelPos.y >= 0 && labelPos.y <= scope.mediaSize.height) {
|
||||
ctx.save();
|
||||
ctx.setLineDash([]);
|
||||
ctx.font = font;
|
||||
ctx.fillStyle = d.textColor || d.color;
|
||||
|
||||
ctx.textAlign = d.alignHorz || 'center';
|
||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||
ctx.fillText(d.text, textX, textY);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Store label position for hit detection
|
||||
if (labelPos) {
|
||||
d.labelPos = labelPos;
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
} else if (d.type === 'fib_retracement') {
|
||||
|
||||
Reference in New Issue
Block a user