diff --git a/index.html b/index.html
index d888172..adae0ba 100644
--- a/index.html
+++ b/index.html
@@ -151,7 +151,7 @@
-
+
diff --git a/js/ui/drawing-tools.js b/js/ui/drawing-tools.js
index 1e74bda..f347206 100644
--- a/js/ui/drawing-tools.js
+++ b/js/ui/drawing-tools.js
@@ -30,6 +30,18 @@ export class DrawingManager {
italic: false,
alignVert: 'top',
alignHorz: 'left'
+ },
+ horizontal_line: {
+ color: '#2962ff',
+ width: 2,
+ style: 0,
+ opacity: 100
+ },
+ vertical_line: {
+ color: '#2962ff',
+ width: 2,
+ style: 0,
+ opacity: 100
}
};
@@ -55,7 +67,7 @@ export class DrawingManager {
if (hit) {
this.selectedDrawing = hit.drawing;
// Only open panel for supported types
- if (['trend_line', 'ray', 'rectangle'].includes(hit.drawing.type)) {
+ if (['trend_line', 'ray', 'rectangle', 'horizontal_line', 'vertical_line'].includes(hit.drawing.type)) {
this.toggleSettingsPanel(true);
}
this.update();
@@ -337,11 +349,11 @@ export class DrawingManager {
return;
}
- const defs = this.defaults.trend_line;
- const color = defs.color;
+ const color = this.defaults.trend_line.color;
const p1 = { time: pos.time, price: pos.price };
const p2 = { time: pos.time, price: pos.price };
+ const defs = this.defaults.trend_line;
if (this.activeTool === 'trend_line' || this.activeTool === 'ray' || this.activeTool === 'rectangle') {
this.currentDrawing = {
type: this.activeTool, p1, p2,
@@ -358,10 +370,26 @@ export class DrawingManager {
alignHorz: defs.alignHorz
};
} else if (this.activeTool === 'horizontal_line') {
- this.drawings.push({ type: 'horizontal_line', price: pos.price, color });
+ const defs = this.defaults.horizontal_line;
+ this.drawings.push({
+ type: 'horizontal_line',
+ price: pos.price,
+ color: defs.color,
+ width: defs.width,
+ style: defs.style,
+ opacity: defs.opacity
+ });
this.setTool(null);
} else if (this.activeTool === 'vertical_line') {
- this.drawings.push({ type: 'vertical_line', time: pos.time, color });
+ const defs = this.defaults.vertical_line;
+ this.drawings.push({
+ type: 'vertical_line',
+ time: pos.time,
+ color: defs.color,
+ width: defs.width,
+ style: defs.style,
+ opacity: defs.opacity
+ });
this.setTool(null);
} else if (this.activeTool === 'fib_retracement') {
this.currentDrawing = { type: 'fib_retracement', p1, p2, color: '#fb8c00' };
@@ -526,10 +554,10 @@ export class DrawingManager {
}
} else if (d.price !== undefined && d.type === 'horizontal_line') {
const dy = this.series.priceToCoordinate(d.price);
- if (dy !== null && Math.abs(y - dy) < threshold) return { drawing: d, part: 'price' };
+ if (dy !== null && Math.abs(y - dy) < threshold) return { drawing: d, part: 'all' };
} else if (d.time !== undefined && d.type === 'vertical_line') {
const dx = this.timeToX(d.time);
- if (dx !== null && Math.abs(x - dx) < threshold) return { drawing: d, part: 'time' };
+ if (dx !== null && Math.abs(x - dx) < threshold) return { drawing: d, part: 'all' };
} else if (d.time !== undefined && d.price !== undefined) {
const dx = this.timeToX(d.time);
const dy = this.series.priceToCoordinate(d.price);
@@ -752,18 +780,44 @@ export class DrawingManager {
} else if (d.type === 'horizontal_line') {
const y = series.priceToCoordinate(d.price);
if (y !== null) {
+ ctx.save();
+ ctx.strokeStyle = d.opacity !== undefined ? this.hexToRgba(d.color, d.opacity) : d.color;
+ ctx.lineWidth = d.width || 2;
+ if (d.style === 1) ctx.setLineDash([10, 5]);
+ else if (d.style === 2) ctx.setLineDash([2, 2]);
+ else ctx.setLineDash([]);
+ if (isSelected) { ctx.shadowBlur = 5; ctx.shadowColor = d.color; }
ctx.beginPath();
ctx.moveTo(-1000, y);
ctx.lineTo(scope.mediaSize.width + 1000, y);
ctx.stroke();
+ if (isSelected) {
+ ctx.setLineDash([]);
+ ctx.fillStyle = '#ffffff';
+ ctx.beginPath(); ctx.arc(0, y, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
+ }
+ ctx.restore();
}
} else if (d.type === 'vertical_line') {
const x = this.timeToX(d.time);
if (x !== null) {
+ ctx.save();
+ ctx.strokeStyle = d.opacity !== undefined ? this.hexToRgba(d.color, d.opacity) : d.color;
+ ctx.lineWidth = d.width || 2;
+ if (d.style === 1) ctx.setLineDash([10, 5]);
+ else if (d.style === 2) ctx.setLineDash([2, 2]);
+ else ctx.setLineDash([]);
+ if (isSelected) { ctx.shadowBlur = 5; ctx.shadowColor = d.color; }
ctx.beginPath();
ctx.moveTo(x, -1000);
ctx.lineTo(x, scope.mediaSize.height + 1000);
ctx.stroke();
+ if (isSelected) {
+ ctx.setLineDash([]);
+ ctx.fillStyle = '#ffffff';
+ ctx.beginPath(); ctx.arc(x, 0, 5, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
+ }
+ ctx.restore();
}
} else if (d.type === 'fib_retracement') {
const x1 = this.timeToX(d.p1.time);
@@ -1017,8 +1071,17 @@ export class DrawingManager {
window.switchTLTab = (tab) => {
this.activeTLTab = tab;
+ const isLineWithText = this.selectedDrawing && ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type);
+
document.getElementById('tlTabStyle').className = tab === 'style' ? 'flex-1 py-2 text-center text-blue-500 border-b-2 border-blue-500 font-medium' : 'flex-1 py-2 text-center text-gray-400 hover:text-white';
- document.getElementById('tlTabText').className = tab === 'text' ? 'flex-1 py-2 text-center text-blue-500 border-b-2 border-blue-500 font-medium' : 'flex-1 py-2 text-center text-gray-400 hover:text-white';
+
+ const textTab = document.getElementById('tlTabText');
+ if (isLineWithText) {
+ textTab.className = tab === 'text' ? 'flex-1 py-2 text-center text-blue-500 border-b-2 border-blue-500 font-medium' : 'flex-1 py-2 text-center text-gray-400 hover:text-white';
+ textTab.style.display = 'block';
+ } else {
+ textTab.style.display = 'none';
+ }
document.getElementById('tlContentStyle').className = tab === 'style' ? 'block' : 'hidden';
document.getElementById('tlContentText').className = tab === 'text' ? 'block' : 'hidden';
@@ -1032,11 +1095,11 @@ export class DrawingManager {
window.setTLThickness = (width) => this.applySettings('width', width);
window.setTLStyle = (style) => this.applySettings('style', style);
window.toggleTLBold = () => {
- const current = this.selectedDrawing ? this.selectedDrawing.bold : this.defaults.trend_line.bold;
+ const current = this.selectedDrawing && ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type) ? this.selectedDrawing.bold : this.defaults.trend_line.bold;
this.applySettings('bold', !current);
};
window.toggleTLItalic = () => {
- const current = this.selectedDrawing ? this.selectedDrawing.italic : this.defaults.trend_line.italic;
+ const current = this.selectedDrawing && ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type) ? this.selectedDrawing.italic : this.defaults.trend_line.italic;
this.applySettings('italic', !current);
};
@@ -1129,6 +1192,14 @@ export class DrawingManager {
if (show) {
panel.classList.remove('hidden');
+ const isLineWithText = this.selectedDrawing && ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type);
+ if (!isLineWithText) {
+ this.activeTLTab = 'style';
+ document.getElementById('tlTabStyle').className = 'flex-1 py-2 text-center text-blue-500 border-b-2 border-blue-500 font-medium';
+ document.getElementById('tlTabText').className = 'flex-1 py-2 text-center text-gray-400 hover:text-white';
+ document.getElementById('tlContentStyle').className = 'block';
+ document.getElementById('tlContentText').className = 'hidden';
+ }
this.updateSettingsPanelUI();
} else {
panel.classList.add('hidden');
@@ -1136,7 +1207,7 @@ export class DrawingManager {
}
updateSettingsPanelUI() {
- const settings = this.selectedDrawing || this.defaults.trend_line;
+ const settings = this.selectedDrawing || this.defaults[this.selectedDrawing ? this.selectedDrawing.type : 'trend_line'];
document.querySelectorAll('#tlColorGrid .color-swatch').forEach(el => {
if (el.style.backgroundColor === settings.color) el.classList.add('active');
@@ -1154,28 +1225,60 @@ export class DrawingManager {
btn.setAttribute('data-active', parseInt(btn.dataset.style) === settings.style);
});
- document.querySelectorAll('#tlTextColorGrid .color-swatch').forEach(el => {
- if (el.style.backgroundColor === settings.textColor) el.classList.add('active');
- else el.classList.remove('active');
- });
-
- if (document.getElementById('tlTextColorBtn')) {
- document.getElementById('tlTextColorBtn').style.backgroundColor = settings.textColor || settings.color;
+ const isLineWithText = this.selectedDrawing && ['trend_line', 'ray', 'rectangle'].includes(this.selectedDrawing.type);
+
+ const textColorBtn = document.getElementById('tlTextColorBtn');
+ const textPicker = document.getElementById('tlTextColorPicker');
+ const fontInput = document.getElementById('tlFontSize');
+ const textInput = document.getElementById('tlTextInput');
+ const alignVert = document.getElementById('tlAlignVert');
+ const alignHorz = document.getElementById('tlAlignHorz');
+ const boldBtn = document.getElementById('tlBoldBtn');
+ const italicBtn = document.getElementById('tlItalicBtn');
+
+ if (isLineWithText) {
+ if (textColorBtn && textPicker) {
+ textColorBtn.style.backgroundColor = settings.textColor || settings.color;
+ textPicker.classList.remove('hidden');
+ }
+ fontInput.value = settings.fontSize || 14;
+ textInput.value = settings.text || '';
+ boldBtn.setAttribute('data-active', !!settings.bold);
+ italicBtn.setAttribute('data-active', !!settings.italic);
+ alignVert.value = settings.alignVert || 'top';
+ alignHorz.value = settings.alignHorz || 'left';
+ } else {
+ if (textPicker) textPicker.classList.add('hidden');
}
- document.getElementById('tlFontSize').value = settings.fontSize || 14;
- document.getElementById('tlTextInput').value = settings.text || '';
- document.getElementById('tlBoldBtn').setAttribute('data-active', !!settings.bold);
- document.getElementById('tlItalicBtn').setAttribute('data-active', !!settings.italic);
- document.getElementById('tlAlignVert').value = settings.alignVert || 'top';
- document.getElementById('tlAlignHorz').value = settings.alignHorz || 'left';
}
applySettings(key, value) {
if (this.selectedDrawing) {
- this.selectedDrawing[key] = value;
+ 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);
+ if (!isLineWithText) return;
+ this.selectedDrawing[key] = value;
+ } else {
+ this.selectedDrawing[key] = value;
+ }
this.update();
} else {
- this.defaults.trend_line[key] = value;
+ const drawingType = this.selectedDrawing ? this.selectedDrawing.type : 'trend_line';
+ if (key === 'bold' || key === 'italic' || key === 'fontSize' || key === 'text' || key === 'textColor' || key === 'alignVert' || key === 'alignHorz') {
+ if (drawingType === 'trend_line' || drawingType === 'ray' || drawingType === 'rectangle') {
+ this.defaults.trend_line[key] = value;
+ }
+ } else {
+ if (drawingType === 'trend_line' || drawingType === 'ray' || drawingType === 'rectangle') {
+ this.defaults.trend_line[key] = value;
+ } else if (drawingType === 'horizontal_line') {
+ this.defaults.horizontal_line[key] = value;
+ } else if (drawingType === 'vertical_line') {
+ this.defaults.vertical_line[key] = value;
+ } else {
+ this.defaults.trend_line[key] = value;
+ }
+ }
}
this.updateSettingsPanelUI();
}