annotations work and a re saved
This commit is contained in:
@@ -43,7 +43,7 @@
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
// Initialize application state
|
||||
const appState = {
|
||||
window.appState = {
|
||||
currentSymbol: '{{ current_symbol }}',
|
||||
currentTimeframes: {{ timeframes | tojson }},
|
||||
annotations: {{ annotations | tojson }},
|
||||
@@ -54,26 +54,29 @@
|
||||
trainingController: null
|
||||
};
|
||||
|
||||
// Initialize components when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize chart manager
|
||||
appState.chartManager = new ChartManager('chart-container', appState.currentTimeframes);
|
||||
|
||||
// Initialize annotation manager
|
||||
appState.annotationManager = new AnnotationManager(appState.chartManager);
|
||||
|
||||
// Initialize time navigator
|
||||
appState.timeNavigator = new TimeNavigator(appState.chartManager);
|
||||
|
||||
// Initialize training controller
|
||||
appState.trainingController = new TrainingController();
|
||||
|
||||
// Load initial data
|
||||
loadInitialData();
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
setupKeyboardShortcuts();
|
||||
});
|
||||
// Initialize components when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize chart manager
|
||||
window.appState.chartManager = new ChartManager('chart-container', window.appState.currentTimeframes);
|
||||
|
||||
// Initialize annotation manager
|
||||
window.appState.annotationManager = new AnnotationManager(window.appState.chartManager);
|
||||
|
||||
// Initialize time navigator
|
||||
window.appState.timeNavigator = new TimeNavigator(window.appState.chartManager);
|
||||
|
||||
// Initialize training controller
|
||||
window.appState.trainingController = new TrainingController();
|
||||
|
||||
// Load initial data
|
||||
loadInitialData();
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
setupKeyboardShortcuts();
|
||||
|
||||
// Setup global functions
|
||||
setupGlobalFunctions();
|
||||
});
|
||||
|
||||
function loadInitialData() {
|
||||
// Fetch initial chart data
|
||||
@@ -90,11 +93,11 @@
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
appState.chartManager.initializeCharts(data.chart_data);
|
||||
window.appState.chartManager.initializeCharts(data.chart_data);
|
||||
|
||||
// Load existing annotations
|
||||
appState.annotations.forEach(annotation => {
|
||||
appState.chartManager.addAnnotation(annotation);
|
||||
window.appState.annotations.forEach(annotation => {
|
||||
window.appState.chartManager.addAnnotation(annotation);
|
||||
});
|
||||
} else {
|
||||
showError('Failed to load chart data: ' + data.error.message);
|
||||
@@ -110,18 +113,40 @@
|
||||
// Arrow left - navigate backward
|
||||
if (e.key === 'ArrowLeft') {
|
||||
e.preventDefault();
|
||||
appState.timeNavigator.scrollBackward();
|
||||
if (window.appState.timeNavigator) {
|
||||
window.appState.timeNavigator.scrollBackward();
|
||||
}
|
||||
}
|
||||
// Arrow right - navigate forward
|
||||
else if (e.key === 'ArrowRight') {
|
||||
e.preventDefault();
|
||||
appState.timeNavigator.scrollForward();
|
||||
if (window.appState.timeNavigator) {
|
||||
window.appState.timeNavigator.scrollForward();
|
||||
}
|
||||
}
|
||||
// Space - mark point (if chart is focused)
|
||||
else if (e.key === ' ' && e.target.tagName !== 'INPUT') {
|
||||
e.preventDefault();
|
||||
// Trigger mark at current crosshair position
|
||||
appState.annotationManager.markCurrentPosition();
|
||||
if (window.appState.annotationManager) {
|
||||
window.appState.annotationManager.markCurrentPosition();
|
||||
}
|
||||
}
|
||||
// Escape - cancel pending annotation
|
||||
else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
if (window.appState.annotationManager) {
|
||||
window.appState.annotationManager.pendingAnnotation = null;
|
||||
document.getElementById('pending-annotation-status').style.display = 'none';
|
||||
showSuccess('Annotation cancelled');
|
||||
}
|
||||
}
|
||||
// Enter - complete annotation (if pending)
|
||||
else if (e.key === 'Enter' && e.target.tagName !== 'INPUT') {
|
||||
e.preventDefault();
|
||||
if (window.appState.annotationManager && window.appState.annotationManager.pendingAnnotation) {
|
||||
showSuccess('Click on chart to mark exit point');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -169,5 +194,86 @@
|
||||
bsToast.show();
|
||||
toast.addEventListener('hidden.bs.toast', () => toast.remove());
|
||||
}
|
||||
|
||||
function setupGlobalFunctions() {
|
||||
// Make functions globally available
|
||||
window.showError = showError;
|
||||
window.showSuccess = showSuccess;
|
||||
window.renderAnnotationsList = renderAnnotationsList;
|
||||
window.deleteAnnotation = deleteAnnotation;
|
||||
window.highlightAnnotation = highlightAnnotation;
|
||||
}
|
||||
|
||||
function renderAnnotationsList(annotations) {
|
||||
const listElement = document.getElementById('annotations-list');
|
||||
if (!listElement) return;
|
||||
|
||||
listElement.innerHTML = '';
|
||||
|
||||
annotations.forEach(annotation => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'annotation-item mb-2 p-2 border rounded';
|
||||
item.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<small class="text-muted">${annotation.timeframe}</small>
|
||||
<div class="fw-bold ${annotation.profit_loss_pct >= 0 ? 'text-success' : 'text-danger'}">
|
||||
${annotation.direction} ${annotation.profit_loss_pct >= 0 ? '+' : ''}${annotation.profit_loss_pct.toFixed(2)}%
|
||||
</div>
|
||||
<small class="text-muted">
|
||||
${new Date(annotation.entry.timestamp).toLocaleString()}
|
||||
</small>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-primary btn-sm" onclick="highlightAnnotation('${annotation.annotation_id}')" title="Highlight">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="deleteAnnotation('${annotation.annotation_id}')" title="Delete">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
listElement.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteAnnotation(annotationId) {
|
||||
if (!confirm('Delete this annotation?')) return;
|
||||
|
||||
fetch('/api/delete-annotation', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({annotation_id: annotationId})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove from app state
|
||||
window.appState.annotations = window.appState.annotations.filter(a => a.annotation_id !== annotationId);
|
||||
|
||||
// Update UI
|
||||
renderAnnotationsList(window.appState.annotations);
|
||||
|
||||
// Remove from chart
|
||||
if (window.appState.chartManager) {
|
||||
window.appState.chartManager.removeAnnotation(annotationId);
|
||||
}
|
||||
|
||||
showSuccess('Annotation deleted');
|
||||
} else {
|
||||
showError('Failed to delete annotation: ' + data.error.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError('Network error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function highlightAnnotation(annotationId) {
|
||||
if (window.appState.chartManager) {
|
||||
window.appState.chartManager.highlightAnnotation(annotationId);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user