annotations work and a re saved
This commit is contained in:
@@ -139,11 +139,27 @@ class ChartManager {
|
||||
annotations: []
|
||||
};
|
||||
|
||||
// Add click handler for annotations
|
||||
// Add click handler for chart
|
||||
plotElement.on('plotly_click', (eventData) => {
|
||||
this.handleChartClick(timeframe, eventData);
|
||||
});
|
||||
|
||||
// Add click handler for annotations
|
||||
plotElement.on('plotly_clickannotation', (eventData) => {
|
||||
const annotationName = eventData.annotation.name;
|
||||
if (annotationName) {
|
||||
const parts = annotationName.split('_');
|
||||
const action = parts[0]; // 'entry', 'exit', or 'delete'
|
||||
const annotationId = parts[1];
|
||||
|
||||
if (action === 'delete') {
|
||||
this.handleAnnotationClick(annotationId, 'delete');
|
||||
} else {
|
||||
this.handleAnnotationClick(annotationId, 'edit');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add hover handler to update info
|
||||
plotElement.on('plotly_hover', (eventData) => {
|
||||
this.updateChartInfo(timeframe, eventData);
|
||||
@@ -159,10 +175,23 @@ class ChartManager {
|
||||
if (!eventData.points || eventData.points.length === 0) return;
|
||||
|
||||
const point = eventData.points[0];
|
||||
|
||||
// Get the actual price from candlestick data
|
||||
let price;
|
||||
if (point.data.type === 'candlestick') {
|
||||
// For candlestick, use close price
|
||||
price = point.data.close[point.pointIndex];
|
||||
} else if (point.data.type === 'bar') {
|
||||
// Skip volume bar clicks
|
||||
return;
|
||||
} else {
|
||||
price = point.y;
|
||||
}
|
||||
|
||||
const clickData = {
|
||||
timeframe: timeframe,
|
||||
timestamp: point.x,
|
||||
price: point.close || point.y,
|
||||
price: price,
|
||||
index: point.pointIndex
|
||||
};
|
||||
|
||||
@@ -255,7 +284,7 @@ class ChartManager {
|
||||
const entryPrice = ann.entry.price;
|
||||
const exitPrice = ann.exit.price;
|
||||
|
||||
// Entry marker
|
||||
// Entry marker (clickable)
|
||||
plotlyAnnotations.push({
|
||||
x: entryTime,
|
||||
y: entryPrice,
|
||||
@@ -266,10 +295,12 @@ class ChartManager {
|
||||
color: ann.direction === 'LONG' ? '#10b981' : '#ef4444'
|
||||
},
|
||||
xanchor: 'center',
|
||||
yanchor: 'bottom'
|
||||
yanchor: 'bottom',
|
||||
captureevents: true,
|
||||
name: `entry_${ann.annotation_id}`
|
||||
});
|
||||
|
||||
// Exit marker
|
||||
// Exit marker (clickable)
|
||||
plotlyAnnotations.push({
|
||||
x: exitTime,
|
||||
y: exitPrice,
|
||||
@@ -280,10 +311,12 @@ class ChartManager {
|
||||
color: ann.direction === 'LONG' ? '#10b981' : '#ef4444'
|
||||
},
|
||||
xanchor: 'center',
|
||||
yanchor: 'top'
|
||||
yanchor: 'top',
|
||||
captureevents: true,
|
||||
name: `exit_${ann.annotation_id}`
|
||||
});
|
||||
|
||||
// P&L label
|
||||
// P&L label with delete button
|
||||
const midTime = new Date((new Date(entryTime).getTime() + new Date(exitTime).getTime()) / 2);
|
||||
const midPrice = (entryPrice + exitPrice) / 2;
|
||||
const pnlColor = ann.profit_loss_pct >= 0 ? '#10b981' : '#ef4444';
|
||||
@@ -291,7 +324,7 @@ class ChartManager {
|
||||
plotlyAnnotations.push({
|
||||
x: midTime,
|
||||
y: midPrice,
|
||||
text: `${ann.profit_loss_pct >= 0 ? '+' : ''}${ann.profit_loss_pct.toFixed(2)}%`,
|
||||
text: `${ann.profit_loss_pct >= 0 ? '+' : ''}${ann.profit_loss_pct.toFixed(2)}% 🗑️`,
|
||||
showarrow: true,
|
||||
arrowhead: 0,
|
||||
ax: 0,
|
||||
@@ -304,10 +337,12 @@ class ChartManager {
|
||||
bgcolor: '#1f2937',
|
||||
bordercolor: pnlColor,
|
||||
borderwidth: 1,
|
||||
borderpad: 4
|
||||
borderpad: 4,
|
||||
captureevents: true,
|
||||
name: `delete_${ann.annotation_id}`
|
||||
});
|
||||
|
||||
// Connecting line
|
||||
// Connecting line (clickable for selection)
|
||||
plotlyShapes.push({
|
||||
type: 'line',
|
||||
x0: entryTime,
|
||||
@@ -318,7 +353,8 @@ class ChartManager {
|
||||
color: ann.direction === 'LONG' ? '#10b981' : '#ef4444',
|
||||
width: 2,
|
||||
dash: 'dash'
|
||||
}
|
||||
},
|
||||
name: `line_${ann.annotation_id}`
|
||||
});
|
||||
});
|
||||
|
||||
@@ -331,6 +367,25 @@ class ChartManager {
|
||||
console.log(`Updated ${timeframeAnnotations.length} annotations for ${timeframe}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle annotation click for editing/deleting
|
||||
*/
|
||||
handleAnnotationClick(annotationId, action) {
|
||||
console.log(`Annotation ${action}:`, annotationId);
|
||||
|
||||
if (action === 'delete') {
|
||||
if (confirm('Delete this annotation?')) {
|
||||
if (window.deleteAnnotation) {
|
||||
window.deleteAnnotation(annotationId);
|
||||
}
|
||||
}
|
||||
} else if (action === 'edit') {
|
||||
if (window.appState && window.appState.chartManager) {
|
||||
window.appState.chartManager.editAnnotation(annotationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight annotation
|
||||
*/
|
||||
@@ -366,27 +421,88 @@ class ChartManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit annotation
|
||||
* Edit annotation - allows moving entry/exit points
|
||||
*/
|
||||
editAnnotation(annotationId) {
|
||||
const annotation = this.annotations[annotationId];
|
||||
if (!annotation) return;
|
||||
|
||||
// Remove from charts
|
||||
this.removeAnnotation(annotationId);
|
||||
// Show edit dialog
|
||||
const action = prompt(
|
||||
'Edit annotation:\n' +
|
||||
'1 - Move entry point\n' +
|
||||
'2 - Move exit point\n' +
|
||||
'3 - Delete annotation\n' +
|
||||
'Enter choice (1-3):',
|
||||
'1'
|
||||
);
|
||||
|
||||
// Set as pending annotation for editing
|
||||
if (window.appState && window.appState.annotationManager) {
|
||||
window.appState.annotationManager.pendingAnnotation = {
|
||||
annotation_id: annotationId,
|
||||
symbol: annotation.symbol,
|
||||
timeframe: annotation.timeframe,
|
||||
entry: annotation.entry,
|
||||
isEditing: true
|
||||
};
|
||||
if (action === '1') {
|
||||
// Move entry point
|
||||
window.showSuccess('Click on chart to set new entry point');
|
||||
|
||||
document.getElementById('pending-annotation-status').style.display = 'block';
|
||||
// Store annotation for editing
|
||||
if (window.appState && window.appState.annotationManager) {
|
||||
window.appState.annotationManager.editingAnnotation = {
|
||||
annotation_id: annotationId,
|
||||
original: annotation,
|
||||
editMode: 'entry'
|
||||
};
|
||||
|
||||
// Remove current annotation from display
|
||||
this.removeAnnotation(annotationId);
|
||||
|
||||
// Show exit marker as reference
|
||||
const chart = this.charts[annotation.timeframe];
|
||||
if (chart) {
|
||||
Plotly.relayout(chart.plotId, {
|
||||
annotations: [{
|
||||
x: annotation.exit.timestamp,
|
||||
y: annotation.exit.price,
|
||||
text: '▼ (exit)',
|
||||
showarrow: true,
|
||||
arrowhead: 2,
|
||||
ax: 0,
|
||||
ay: 40,
|
||||
font: {size: 14, color: '#9ca3af'}
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (action === '2') {
|
||||
// Move exit point
|
||||
window.showSuccess('Click on chart to set new exit point');
|
||||
|
||||
if (window.appState && window.appState.annotationManager) {
|
||||
window.appState.annotationManager.editingAnnotation = {
|
||||
annotation_id: annotationId,
|
||||
original: annotation,
|
||||
editMode: 'exit'
|
||||
};
|
||||
|
||||
// Remove current annotation from display
|
||||
this.removeAnnotation(annotationId);
|
||||
|
||||
// Show entry marker as reference
|
||||
const chart = this.charts[annotation.timeframe];
|
||||
if (chart) {
|
||||
Plotly.relayout(chart.plotId, {
|
||||
annotations: [{
|
||||
x: annotation.entry.timestamp,
|
||||
y: annotation.entry.price,
|
||||
text: '▲ (entry)',
|
||||
showarrow: true,
|
||||
arrowhead: 2,
|
||||
ax: 0,
|
||||
ay: -40,
|
||||
font: {size: 14, color: '#9ca3af'}
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (action === '3') {
|
||||
// Delete
|
||||
this.handleAnnotationClick(annotationId, 'delete');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user