fix: Text rendering and settings for horizontal and vertical lines, parallel trendline text
This commit is contained in:
@ -391,7 +391,14 @@ export class DrawingManager {
|
|||||||
color: defs.color,
|
color: defs.color,
|
||||||
width: defs.width,
|
width: defs.width,
|
||||||
style: defs.style,
|
style: defs.style,
|
||||||
opacity: defs.opacity
|
opacity: defs.opacity,
|
||||||
|
text: defs.text,
|
||||||
|
textColor: defs.textColor,
|
||||||
|
fontSize: defs.fontSize,
|
||||||
|
bold: defs.bold,
|
||||||
|
italic: defs.italic,
|
||||||
|
alignVert: defs.alignVert,
|
||||||
|
alignHorz: defs.alignHorz
|
||||||
});
|
});
|
||||||
this.setTool(null);
|
this.setTool(null);
|
||||||
} else if (this.activeTool === 'vertical_line') {
|
} else if (this.activeTool === 'vertical_line') {
|
||||||
@ -402,7 +409,14 @@ export class DrawingManager {
|
|||||||
color: defs.color,
|
color: defs.color,
|
||||||
width: defs.width,
|
width: defs.width,
|
||||||
style: defs.style,
|
style: defs.style,
|
||||||
opacity: defs.opacity
|
opacity: defs.opacity,
|
||||||
|
text: defs.text,
|
||||||
|
textColor: defs.textColor,
|
||||||
|
fontSize: defs.fontSize,
|
||||||
|
bold: defs.bold,
|
||||||
|
italic: defs.italic,
|
||||||
|
alignVert: defs.alignVert,
|
||||||
|
alignHorz: defs.alignHorz
|
||||||
});
|
});
|
||||||
this.setTool(null);
|
this.setTool(null);
|
||||||
} else if (this.activeTool === 'fib_retracement') {
|
} else if (this.activeTool === 'fib_retracement') {
|
||||||
@ -783,13 +797,27 @@ export class DrawingManager {
|
|||||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||||
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
ctx.font = `${fontStyle}${fontSize}px Inter`;
|
||||||
ctx.fillStyle = d.textColor || color;
|
ctx.fillStyle = d.textColor || color;
|
||||||
|
|
||||||
|
let startX = x1, startY = y1, endX = x2, endY = y2;
|
||||||
|
if (x1 > x2 || (x1 === x2 && y1 > y2)) {
|
||||||
|
startX = x2; startY = y2; endX = x1; endY = y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const angle = Math.atan2(endY - startY, endX - startX);
|
||||||
|
const length = Math.hypot(endX - startX, endY - startY);
|
||||||
|
|
||||||
|
ctx.translate(startX, startY);
|
||||||
|
ctx.rotate(angle);
|
||||||
|
|
||||||
ctx.textAlign = d.alignHorz || 'left';
|
ctx.textAlign = d.alignHorz || 'left';
|
||||||
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||||
|
|
||||||
const tx = (x1 + x2) / 2;
|
let tx = 0;
|
||||||
const ty = (y1 + y2) / 2;
|
if (d.alignHorz === 'center') tx = length / 2;
|
||||||
|
else if (d.alignHorz === 'right') tx = length;
|
||||||
|
|
||||||
const offset = 10;
|
const offset = 10;
|
||||||
const finalTy = d.alignVert === 'top' ? ty - offset : (d.alignVert === 'bottom' ? ty + offset : ty);
|
const finalTy = d.alignVert === 'top' ? -offset : (d.alignVert === 'bottom' ? offset : 0);
|
||||||
|
|
||||||
ctx.fillText(d.text, tx, finalTy);
|
ctx.fillText(d.text, tx, finalTy);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
@ -837,41 +865,46 @@ export class DrawingManager {
|
|||||||
ctx.beginPath(); ctx.arc(0, y, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
ctx.beginPath(); ctx.arc(0, y, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store label position for hit detection (before rendering)
|
// Render Text and store label position
|
||||||
let textX = scope.mediaSize.width / 2;
|
|
||||||
let textY = y;
|
|
||||||
let labelPos = null;
|
let labelPos = null;
|
||||||
if (d.text) {
|
if (d.text) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.setLineDash([]);
|
||||||
const fontSize = d.fontSize || 14;
|
const fontSize = d.fontSize || 14;
|
||||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||||
const font = `${fontStyle}${fontSize}px Inter`;
|
const font = `${fontStyle}${fontSize}px Inter`;
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
|
ctx.fillStyle = d.textColor || d.color;
|
||||||
|
|
||||||
|
const alignHorz = d.alignHorz || 'center';
|
||||||
|
ctx.textAlign = alignHorz;
|
||||||
|
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'top' : 'bottom');
|
||||||
|
|
||||||
|
let textX = scope.mediaSize.width / 2;
|
||||||
|
if (alignHorz === 'left') textX = 10;
|
||||||
|
else if (alignHorz === 'right') textX = scope.mediaSize.width - 10;
|
||||||
|
|
||||||
|
const offset = 10;
|
||||||
|
let textY = d.alignVert === 'top' ? y - offset : (d.alignVert === 'bottom' ? y + offset : y);
|
||||||
|
|
||||||
|
ctx.fillText(d.text, textX, textY);
|
||||||
|
|
||||||
const metrics = ctx.measureText(d.text);
|
const metrics = ctx.measureText(d.text);
|
||||||
const labelWidth = metrics.width + 16;
|
const labelWidth = metrics.width + 16;
|
||||||
const labelHeight = 24;
|
const labelHeight = 24;
|
||||||
const defaultLabelX = scope.mediaSize.width / 2 - labelWidth / 2;
|
|
||||||
const offset = 10;
|
let defaultLabelX = scope.mediaSize.width / 2 - labelWidth / 2;
|
||||||
|
if (alignHorz === 'left') defaultLabelX = 10;
|
||||||
|
else if (alignHorz === 'right') defaultLabelX = scope.mediaSize.width - labelWidth - 10;
|
||||||
|
|
||||||
const defaultLabelY = d.alignVert === 'top' ? y - 40 : (d.alignVert === 'bottom' ? y + 20 : y - 12);
|
const defaultLabelY = d.alignVert === 'top' ? y - 40 : (d.alignVert === 'bottom' ? y + 20 : y - 12);
|
||||||
|
|
||||||
labelPos = {
|
labelPos = {
|
||||||
x: defaultLabelX + (d.labelOffset?.x || 0),
|
x: defaultLabelX + (d.labelOffset?.x || 0),
|
||||||
y: defaultLabelY + (d.labelOffset?.y || 0),
|
y: defaultLabelY + (d.labelOffset?.y || 0),
|
||||||
width: labelWidth,
|
width: labelWidth,
|
||||||
height: labelHeight
|
height: labelHeight
|
||||||
};
|
};
|
||||||
textX = scope.mediaSize.width / 2;
|
|
||||||
textY = d.alignVert === 'top' ? y - offset : (d.alignVert === 'bottom' ? y + offset : y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render Text if present
|
|
||||||
if (d.text) {
|
|
||||||
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();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,39 +935,48 @@ export class DrawingManager {
|
|||||||
ctx.beginPath(); ctx.arc(x, 0, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
ctx.beginPath(); ctx.arc(x, 0, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store label position for hit detection (before rendering)
|
// Render Text and store label position
|
||||||
let textX = x;
|
|
||||||
let textY = 0;
|
|
||||||
let labelPos = null;
|
let labelPos = null;
|
||||||
if (d.text) {
|
if (d.text) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.setLineDash([]);
|
||||||
const fontSize = d.fontSize || 14;
|
const fontSize = d.fontSize || 14;
|
||||||
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
const fontStyle = (d.bold ? 'bold ' : '') + (d.italic ? 'italic ' : '');
|
||||||
const font = `${fontStyle}${fontSize}px Inter`;
|
const font = `${fontStyle}${fontSize}px Inter`;
|
||||||
ctx.font = font;
|
ctx.font = font;
|
||||||
|
ctx.fillStyle = d.textColor || d.color;
|
||||||
|
|
||||||
|
const alignHorz = d.alignHorz || 'center';
|
||||||
|
ctx.textAlign = alignHorz;
|
||||||
|
ctx.textBaseline = d.alignVert === 'middle' ? 'middle' : (d.alignVert === 'bottom' ? 'bottom' : 'top');
|
||||||
|
|
||||||
|
let textX = x;
|
||||||
|
const offset = 10;
|
||||||
|
|
||||||
|
let textY = scope.mediaSize.height / 2; // Middle
|
||||||
|
if (d.alignVert === 'top') textY = offset;
|
||||||
|
else if (d.alignVert === 'bottom') textY = scope.mediaSize.height - offset;
|
||||||
|
|
||||||
|
ctx.fillText(d.text, textX, textY);
|
||||||
|
|
||||||
const metrics = ctx.measureText(d.text);
|
const metrics = ctx.measureText(d.text);
|
||||||
const labelWidth = metrics.width + 16;
|
const labelWidth = metrics.width + 16;
|
||||||
const labelHeight = 24;
|
const labelHeight = 24;
|
||||||
const offset = 10;
|
|
||||||
const defaultLabelY = d.alignVert === 'top' ? -50 : (d.alignVert === 'bottom' ? 20 : -12);
|
let defaultLabelY = scope.mediaSize.height / 2 - labelHeight / 2; // Middle
|
||||||
|
if (d.alignVert === 'top') defaultLabelY = offset;
|
||||||
|
else if (d.alignVert === 'bottom') defaultLabelY = scope.mediaSize.height - offset - labelHeight;
|
||||||
|
|
||||||
|
let defaultLabelX = x - labelWidth / 2;
|
||||||
|
if (alignHorz === 'left') defaultLabelX = x - labelWidth;
|
||||||
|
else if (alignHorz === 'right') defaultLabelX = x;
|
||||||
|
|
||||||
labelPos = {
|
labelPos = {
|
||||||
x: x - labelWidth / 2 + (d.labelOffset?.x || 0),
|
x: defaultLabelX + (d.labelOffset?.x || 0),
|
||||||
y: defaultLabelY + (d.labelOffset?.y || 0),
|
y: defaultLabelY + (d.labelOffset?.y || 0),
|
||||||
width: labelWidth,
|
width: labelWidth,
|
||||||
height: labelHeight
|
height: labelHeight
|
||||||
};
|
};
|
||||||
textY = d.alignVert === 'top' ? -offset : (d.alignVert === 'bottom' ? offset : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render Text if present
|
|
||||||
if (d.text) {
|
|
||||||
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();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1374,7 +1416,7 @@ export class DrawingManager {
|
|||||||
applySettings(key, value) {
|
applySettings(key, value) {
|
||||||
if (this.selectedDrawing) {
|
if (this.selectedDrawing) {
|
||||||
if (key === 'bold' || key === 'italic' || key === 'fontSize' || key === 'text' || key === 'textColor' || key === 'alignVert' || key === 'alignHorz') {
|
if (key === 'bold' || key === 'italic' || key === 'fontSize' || key === 'text' || key === 'textColor' || key === 'alignVert' || key === 'alignHorz') {
|
||||||
const isLineWithText = ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type);
|
const isLineWithText = ['trend_line', 'ray', 'rectangle', 'horizontal_line', 'vertical_line'].includes(this.selectedDrawing.type);
|
||||||
if (!isLineWithText) return;
|
if (!isLineWithText) return;
|
||||||
this.selectedDrawing[key] = value;
|
this.selectedDrawing[key] = value;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user