diff --git a/application_events.json b/application_events.json
index d6dafca..adc6053 100644
--- a/application_events.json
+++ b/application_events.json
@@ -4357,8 +4357,183 @@
"trigger_variable": null,
"auto_started": true
}
+ },
+ {
+ "timestamp": "2025-08-15T00:55:29.278884",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'Clock' created and started",
+ "details": {
+ "session_id": "Clock",
+ "variables": [
+ "AUX Blink_1.0S",
+ "AUX Blink_1.6S"
+ ],
+ "time_window": 60,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:04.171748",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'Clock' created and started",
+ "details": {
+ "session_id": "Clock",
+ "variables": [
+ "AUX Blink_1.0S",
+ "AUX Blink_1.6S"
+ ],
+ "time_window": 60,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:33.247778",
+ "level": "info",
+ "event_type": "application_started",
+ "message": "Application initialization completed successfully",
+ "details": {}
+ },
+ {
+ "timestamp": "2025-08-15T00:56:33.360494",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: DAR",
+ "details": {
+ "dataset_id": "DAR",
+ "variables_count": 2,
+ "streaming_count": 2,
+ "prefix": "gateway_phoenix"
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:33.369004",
+ "level": "info",
+ "event_type": "dataset_activated",
+ "message": "Dataset activated: Fast",
+ "details": {
+ "dataset_id": "Fast",
+ "variables_count": 2,
+ "streaming_count": 1,
+ "prefix": "fast"
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:33.375426",
+ "level": "info",
+ "event_type": "csv_recording_started",
+ "message": "CSV recording started: 2 datasets activated",
+ "details": {
+ "activated_datasets": 2,
+ "total_datasets": 3
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:43.455835",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'Clock' created and started",
+ "details": {
+ "session_id": "Clock",
+ "variables": [
+ "AUX Blink_1.0S",
+ "AUX Blink_1.6S"
+ ],
+ "time_window": 60,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:56:50.145968",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'UR29' created and started",
+ "details": {
+ "session_id": "plot_1",
+ "variables": [
+ "UR29_Brix",
+ "UR29_ma",
+ "AUX Blink_1.0S"
+ ],
+ "time_window": 360,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:57:04.660061",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'Clock' created and started",
+ "details": {
+ "session_id": "Clock",
+ "variables": [
+ "AUX Blink_1.0S",
+ "AUX Blink_1.6S"
+ ],
+ "time_window": 60,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T00:57:09.226184",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'Clock' created and started",
+ "details": {
+ "session_id": "Clock",
+ "variables": [
+ "AUX Blink_1.0S",
+ "AUX Blink_1.6S"
+ ],
+ "time_window": 60,
+ "trigger_variable": null,
+ "auto_started": true
+ }
+ },
+ {
+ "timestamp": "2025-08-15T10:44:49.036843",
+ "level": "info",
+ "event_type": "datasets_resumed_after_reconnection",
+ "message": "Automatically resumed streaming for 2 datasets after PLC reconnection",
+ "details": {
+ "resumed_datasets": 2,
+ "total_attempted": 2
+ }
+ },
+ {
+ "timestamp": "2025-08-15T10:45:35.434594",
+ "level": "info",
+ "event_type": "datasets_resumed_after_reconnection",
+ "message": "Automatically resumed streaming for 2 datasets after PLC reconnection",
+ "details": {
+ "resumed_datasets": 2,
+ "total_attempted": 2
+ }
+ },
+ {
+ "timestamp": "2025-08-15T10:47:54.448887",
+ "level": "info",
+ "event_type": "plot_session_created",
+ "message": "Plot session 'UR29' created and started",
+ "details": {
+ "session_id": "plot_1",
+ "variables": [
+ "UR29_Brix",
+ "UR29_ma",
+ "AUX Blink_1.0S"
+ ],
+ "time_window": 36,
+ "trigger_variable": null,
+ "auto_started": true
+ }
}
],
- "last_updated": "2025-08-15T00:53:37.664354",
- "total_entries": 390
+ "last_updated": "2025-08-15T10:47:54.448887",
+ "total_entries": 403
}
\ No newline at end of file
diff --git a/config/data/plot_definitions.json b/config/data/plot_definitions.json
index 1832b26..92f69bd 100644
--- a/config/data/plot_definitions.json
+++ b/config/data/plot_definitions.json
@@ -7,12 +7,23 @@
"point_hover_radius": 4,
"point_radius": 0,
"stepped": true,
- "time_window": 360,
+ "time_window": 36,
"trigger_enabled": false,
"trigger_on_true": true,
"trigger_variable": null,
"y_max": null,
"y_min": null
+ },
+ {
+ "id": "Clock",
+ "line_tension": 0,
+ "name": "Clock",
+ "point_hover_radius": 4,
+ "point_radius": 1,
+ "stepped": true,
+ "time_window": 60,
+ "trigger_enabled": false,
+ "trigger_on_true": true
}
]
}
\ No newline at end of file
diff --git a/config/data/plot_variables.json b/config/data/plot_variables.json
index 08ae190..2281c79 100644
--- a/config/data/plot_variables.json
+++ b/config/data/plot_variables.json
@@ -4,26 +4,45 @@
"plot_id": "plot_1",
"variables": [
{
- "variable_name": "UR29_Brix",
- "label": "Brix",
"color": "#3498db",
+ "enabled": true,
+ "label": "Brix",
"line_width": 2,
- "y_axis": "left",
- "enabled": true
+ "variable_name": "UR29_Brix",
+ "y_axis": "left"
},
{
- "variable_name": "UR29_ma",
- "label": "ma",
"color": "#dce740",
+ "enabled": true,
+ "label": "ma",
"line_width": 2,
- "y_axis": "left",
- "enabled": true
+ "variable_name": "UR29_ma",
+ "y_axis": "left"
},
+ {
+ "color": "#3498db",
+ "enabled": true,
+ "line_width": 2,
+ "variable_name": "AUX Blink_1.0S",
+ "y_axis": "right"
+ }
+ ]
+ },
+ {
+ "plot_id": "Clock",
+ "variables": [
{
"variable_name": "AUX Blink_1.0S",
"color": "#3498db",
"line_width": 2,
- "y_axis": "right",
+ "y_axis": "left",
+ "enabled": true
+ },
+ {
+ "variable_name": "AUX Blink_1.6S",
+ "color": "#87db33",
+ "line_width": 2,
+ "y_axis": "left",
"enabled": true
}
]
diff --git a/frontend/src/components/ChartjsPlot.jsx b/frontend/src/components/ChartjsPlot.jsx
index 0e7f5f0..0281a29 100644
--- a/frontend/src/components/ChartjsPlot.jsx
+++ b/frontend/src/components/ChartjsPlot.jsx
@@ -1,5 +1,5 @@
import React, { useRef, useEffect, useState, useCallback } from 'react';
-import { Box, Text, useColorModeValue } from '@chakra-ui/react';
+import { Box, Text, Switch, FormLabel, HStack, useColorModeValue } from '@chakra-ui/react';
// Global dependencies check - run once
let dependenciesChecked = false;
@@ -66,11 +66,9 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
const [dataPointsCount, setDataPointsCount] = useState(0);
const [isRefreshing, setIsRefreshing] = useState(false);
const [isLoadingHistorical, setIsLoadingHistorical] = useState(false);
+ const [isZoomEnabled, setIsZoomEnabled] = useState(true);
const resolvedConfigRef = useRef(null);
- // Data preservation system for zoom operations
- const dataBackupRef = useRef(new Map());
-
// Chart health monitoring
const chartHealthRef = useRef({
lastDataTimestamp: 0,
@@ -238,7 +236,6 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
sessionId: session?.session_id,
sessionActive: session?.is_active,
sessionPaused: session?.is_paused,
- dataBackupSize: dataBackupRef.current.size,
health: chartHealthRef.current,
datasets: chartRef.current?.data?.datasets?.length || 0,
realtimeConfig: !!chartRef.current?.options?.scales?.x?.realtime
@@ -615,7 +612,6 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
// Sort points by timestamp to ensure proper order
historicalPoints.sort((a, b) => a.x - b.x);
datasets[index].data = historicalPoints;
- console.log(`π Added ${historicalPoints.length} historical points for ${variableInfo.name}`);
}
});
@@ -698,9 +694,9 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
},
...(zoomAvailable ? {
zoom: {
- // Habilitar zoom/pan siempre, pero con configuraciΓ³n optimizada para streaming
+ // Enable/disable zoom/pan based on switch state
pan: {
- enabled: true,
+ enabled: isZoomEnabled,
mode: 'x',
modifierKey: 'shift',
onPanComplete: function(context) {
@@ -717,14 +713,14 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
},
zoom: {
drag: {
- enabled: true,
+ enabled: isZoomEnabled,
backgroundColor: 'rgba(128,128,128,0.3)'
},
wheel: {
- enabled: true,
+ enabled: isZoomEnabled,
speed: 0.1
},
- pinch: { enabled: true },
+ pinch: { enabled: isZoomEnabled },
mode: 'x',
onZoomComplete: function(context) {
// Preserve streaming state and data after zoom
@@ -848,7 +844,7 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
setError(error.message);
setIsLoading(false);
}
- }, []);
+ }, [isZoomEnabled]);
const onStreamingRefresh = useCallback(async (chart) => {
const sessionId = sessionDataRef.current.sessionId;
@@ -875,10 +871,6 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
const pointsAdded = addNewDataToStreaming(plotData, now);
updatePointsCounter(plotData);
- if (pointsAdded > 0) {
- console.log(`π Plot ${sessionId}: Added ${pointsAdded} points to chart`);
- }
-
// Auto-pause when no data arrives for several cycles; resume when data appears
if (pointsAdded > 0) {
sessionDataRef.current.noDataCycles = 0;
@@ -990,18 +982,6 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
// Update health monitoring
chartHealthRef.current.lastDataTimestamp = Date.now();
chartHealthRef.current.consecutiveErrors = 0;
-
- // Backup data periodically when significant data is added
- if (pointsAdded > 5 && dataBackupRef.current) {
- const backup = chart.data.datasets.map(dataset => ({
- label: dataset.label,
- data: [...(dataset.data || [])],
- timestamp: Date.now()
- }));
-
- dataBackupRef.current.set('current', backup);
- console.log(`π¦ Data backed up: ${backup.reduce((total, ds) => total + ds.data.length, 0)} points`);
- }
} else {
// No new data received - increment error counter
chartHealthRef.current.consecutiveErrors++;
@@ -1113,7 +1093,6 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
// Sort points by timestamp to ensure proper order
historicalPoints.sort((a, b) => a.x - b.x);
chart.data.datasets[index].data = historicalPoints;
- console.log(`π Added ${historicalPoints.length} historical points for ${variableInfo.name} on start`);
}
});
@@ -1206,9 +1185,45 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
// Get current time window (use same as initial load)
const timeWindow = cfg.time_window || 3600; // Default 1 hour
+ const variableNames = enabledVariables.map(v => v.name);
// Load fresh historical data
- await loadHistoricalData(enabledVariables, timeWindow);
+ const historicalData = await loadHistoricalData(variableNames, timeWindow);
+
+ if (historicalData.length > 0) {
+ console.log(`π Loaded ${historicalData.length} historical data points for reset`);
+
+ // Group data by variable and add to appropriate dataset
+ const dataByVariable = {};
+ historicalData.forEach(point => {
+ const { variable, timestamp, value } = point;
+ if (!dataByVariable[variable]) {
+ dataByVariable[variable] = [];
+ }
+ dataByVariable[variable].push({
+ x: new Date(timestamp),
+ y: value
+ });
+ });
+
+ // Add historical data to datasets
+ enabledVariables.forEach((variableInfo, index) => {
+ const historicalPoints = dataByVariable[variableInfo.name] || [];
+ if (historicalPoints.length > 0) {
+ // Sort points by timestamp to ensure proper order
+ historicalPoints.sort((a, b) => a.x - b.x);
+ chartRef.current.data.datasets[index].data = historicalPoints;
+ }
+ });
+
+ // Update chart with historical data
+ chartRef.current.update('quiet');
+
+ // Update data points counter
+ const totalHistoricalPoints = Object.values(dataByVariable).reduce((sum, points) => sum + points.length, 0);
+ setDataPointsCount(totalHistoricalPoints);
+ }
+
console.log('β
Historical data reloaded');
}
@@ -1348,6 +1363,27 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
}
}, [session?.isFullscreen, createStreamingChart]);
+ // Update zoom configuration when zoom enabled state changes
+ useEffect(() => {
+ if (!chartRef.current) return;
+
+ const chart = chartRef.current;
+ const zoomPlugin = chart.options?.plugins?.zoom;
+
+ if (zoomPlugin) {
+ // Update zoom configuration dynamically
+ zoomPlugin.pan.enabled = isZoomEnabled;
+ zoomPlugin.zoom.drag.enabled = isZoomEnabled;
+ zoomPlugin.zoom.wheel.enabled = isZoomEnabled;
+ zoomPlugin.zoom.pinch.enabled = isZoomEnabled;
+
+ // Update the chart to apply the new configuration
+ chart.update('none');
+
+ console.log(`π Zoom/Pan ${isZoomEnabled ? 'enabled' : 'disabled'}`);
+ }
+ }, [isZoomEnabled]);
+
// Periodic health monitoring
useEffect(() => {
if (!session?.session_id || !chartRef.current) return;
@@ -1569,24 +1605,35 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
π Loading historical data...
)}
-
- {/* Data points counter */}
- {dataPointsCount > 0 && (
-
- π {dataPointsCount} points
-
- )}
+
+ {/* Zoom/Pan Toggle Switch */}
+
+
+ π Zoom/Pan
+
+ setIsZoomEnabled(e.target.checked)}
+ colorScheme="blue"
+ />
+
{/* Reset Zoom Button */}
{chartRef.current && (
@@ -1676,16 +1723,19 @@ const ChartjsPlot = ({ session, height = '400px' }) => {
{/* Points counter */}
- Points: {dataPointsCount}
+ π {dataPointsCount} points
);
diff --git a/system_state.json b/system_state.json
index 024e8b7..f88f4dd 100644
--- a/system_state.json
+++ b/system_state.json
@@ -3,11 +3,11 @@
"should_connect": true,
"should_stream": false,
"active_datasets": [
- "DAR",
"Fast",
- "Test"
+ "Test",
+ "DAR"
]
},
"auto_recovery_enabled": true,
- "last_update": "2025-08-15T00:46:30.361074"
+ "last_update": "2025-08-15T00:56:33.380433"
}
\ No newline at end of file