Skip to content

Commit ad3b85c

Browse files
authored
Feat: Dev to main - Multi-Improves in Auto-Guard (#95)
* feat(ui): enhance guard UI with new action buttons and configuration options - Added new buttons for starting, stopping, repositioning, saving, analyzing, and logging. - Introduced a configuration button that opens a new configuration window. - Updated the layout for area selection buttons with transitions for better UX. - Moved captured coordinates display to the end of the area section. - Simplified button labels for start and stop protection in Spanish localization. - Created a new configuration window with various settings for protection patterns, color preferences, and load management. - Implemented event listeners for configuration changes and persistence of settings. * feat(window-manager): add window management system for z-index control Implement global window manager to handle z-index of multiple windows. Includes register/unregister functions and bring-to-front behavior on click. Applied to all window components (log, config, guard UI, analysis). feat(guard): add human-like protection patterns and improve watch mode Add 16 new human-like protection patterns (zigzag, diagonal, clusters, etc.) with detailed documentation. Enhance watch mode with toggle button and visual feedback. Improve stop behavior to handle both protection and watch modes. docs: add PATRONES.md documenting all protection patterns Create comprehensive documentation for all implemented protection patterns including descriptions, use cases, and technical implementation details. refactor(analysis-window): optimize refresh to preserve zoom level Modify analysis window refresh logic to only update data without resetting zoom/opacity settings. Improves user experience during auto-refresh. * feat(guard): add color exclusion feature and improve UI - Implement color exclusion functionality in pixel repair process - Add responsive layout to configuration window - Improve button states and transitions in guard UI - Move coordinates display to analysis window
1 parent d98e089 commit ad3b85c

File tree

12 files changed

+2694
-560
lines changed

12 files changed

+2694
-560
lines changed

Auto-Guard.js

Lines changed: 208 additions & 118 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/PATRONES.md

Lines changed: 413 additions & 0 deletions
Large diffs are not rendered by default.

src/core/window-manager.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Gestor global de ventanas para traer al frente
2+
let currentMaxZIndex = 100000;
3+
const windowElements = new Set();
4+
5+
/**
6+
* Registra una ventana para el manejo de z-index
7+
* @param {HTMLElement} windowElement - El elemento de la ventana
8+
*/
9+
export function registerWindow(windowElement) {
10+
if (!windowElement) return;
11+
12+
windowElements.add(windowElement);
13+
14+
// Agregar event listener para traer al frente al hacer click
15+
const bringToFrontHandler = (event) => {
16+
// Solo traer al frente si el click es en la ventana misma, no en elementos internos específicos
17+
if (event.target === windowElement || windowElement.contains(event.target)) {
18+
bringWindowToFront(windowElement);
19+
}
20+
};
21+
22+
windowElement.addEventListener('mousedown', bringToFrontHandler);
23+
24+
// Guardar referencia del handler para poder removerlo después
25+
windowElement._bringToFrontHandler = bringToFrontHandler;
26+
27+
// Establecer z-index inicial si no tiene uno
28+
if (!windowElement.style.zIndex) {
29+
windowElement.style.zIndex = currentMaxZIndex++;
30+
}
31+
}
32+
33+
/**
34+
* Desregistra una ventana del manejo de z-index
35+
* @param {HTMLElement} windowElement - El elemento de la ventana
36+
*/
37+
export function unregisterWindow(windowElement) {
38+
if (!windowElement) return;
39+
40+
windowElements.delete(windowElement);
41+
42+
// Remover event listener
43+
if (windowElement._bringToFrontHandler) {
44+
windowElement.removeEventListener('mousedown', windowElement._bringToFrontHandler);
45+
delete windowElement._bringToFrontHandler;
46+
}
47+
}
48+
49+
/**
50+
* Trae una ventana al frente
51+
* @param {HTMLElement} windowElement - El elemento de la ventana a traer al frente
52+
*/
53+
export function bringWindowToFront(windowElement) {
54+
if (!windowElement || !windowElements.has(windowElement)) return;
55+
56+
// Incrementar el z-index máximo y asignarlo a esta ventana
57+
currentMaxZIndex++;
58+
windowElement.style.zIndex = currentMaxZIndex;
59+
}
60+
61+
/**
62+
* Obtiene el z-index máximo actual
63+
* @returns {number} - El z-index máximo actual
64+
*/
65+
export function getCurrentMaxZIndex() {
66+
return currentMaxZIndex;
67+
}
68+
69+
/**
70+
* Establece un z-index mínimo para futuras ventanas
71+
* @param {number} minZIndex - El z-index mínimo
72+
*/
73+
export function setMinZIndex(minZIndex) {
74+
if (minZIndex > currentMaxZIndex) {
75+
currentMaxZIndex = minZIndex;
76+
}
77+
}

src/guard/analysis-window.js

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import { log } from '../core/logger.js';
33
import { guardState } from './config.js';
44
import { analyzeAreaPixels } from './processor.js';
5+
import { registerWindow, unregisterWindow } from '../core/window-manager.js';
6+
import { getGuardTexts } from '../locales/index.js';
57

68
// Variables globales para la ventana
79
let analysisWindowInstance = null;
@@ -12,6 +14,9 @@ let autoRefreshInterval = null;
1214
// Cerrar ventana de análisis
1315
export function closeAnalysisWindow() {
1416
if (analysisWindowInstance) {
17+
// Desregistrar ventana del gestor
18+
unregisterWindow(analysisWindowInstance.analysisWindow);
19+
1520
// Limpiar interval si existe
1621
if (autoRefreshInterval) {
1722
window.clearInterval(autoRefreshInterval);
@@ -170,6 +175,20 @@ export function createAnalysisWindow() {
170175
<button id="autoFitZoom" style="width: 100%; padding: 8px; background: #10b981; color: white; border: none; border-radius: 6px; font-weight: 600; cursor: pointer; margin-top: 8px;">
171176
📐 Ajustar Zoom
172177
</button>
178+
179+
<!-- Coordenadas del área -->
180+
<div style="margin-top: 15px; padding-top: 10px; border-top: 1px solid #4b5563;">
181+
<div style="font-size: 10px; color: #9ca3af; margin-bottom: 5px;">
182+
<div style="display: flex; justify-content: space-between; margin-bottom: 2px;">
183+
<span>Superior Izq.:</span>
184+
<span id="coordsUpperLeft">--</span>
185+
</div>
186+
<div style="display: flex; justify-content: space-between;">
187+
<span>Inferior Der.:</span>
188+
<span id="coordsLowerRight">--</span>
189+
</div>
190+
</div>
191+
</div>
173192
</div>
174193
`;
175194

@@ -214,6 +233,9 @@ export function createAnalysisWindow() {
214233
analysisWindow.appendChild(resizeHandle);
215234
document.body.appendChild(analysisWindow);
216235

236+
// Registrar ventana para manejo de z-index
237+
registerWindow(analysisWindow);
238+
217239
// Inicializar el análisis
218240
initializeAnalysis(canvas, controlPanel);
219241

@@ -294,6 +316,26 @@ export function createAnalysisWindow() {
294316
return { analysisWindow, canvas, controlPanel };
295317
}
296318

319+
// Función para refrescar solo los datos sin reajustar zoom
320+
async function refreshAnalysisData(canvas, controlPanel) {
321+
try {
322+
// Obtener píxeles actuales del canvas
323+
const currentPixels = await analyzeAreaPixels(guardState.protectionArea);
324+
325+
// Comparar con píxeles originales
326+
const analysis = comparePixels(guardState.originalPixels, currentPixels || new Map());
327+
328+
// Actualizar estadísticas
329+
updateStatistics(controlPanel, analysis);
330+
331+
// Renderizar visualización manteniendo zoom actual
332+
renderVisualization(canvas, analysis);
333+
334+
} catch (error) {
335+
log('❌ Error en refresco de análisis:', error);
336+
}
337+
}
338+
297339
// Inicializar el análisis y visualización
298340
async function initializeAnalysis(canvas, controlPanel) {
299341
try {
@@ -335,9 +377,12 @@ async function initializeAnalysis(canvas, controlPanel) {
335377
renderVisualization(canvas, analysis);
336378

337379
// Configurar controles
338-
setupControls(controlPanel, canvas, analysis);
339-
340-
log('✅ Análisis completado');
380+
setupControls(controlPanel, canvas, analysis);
381+
382+
// Actualizar coordenadas
383+
updateCoordinatesDisplay(controlPanel);
384+
385+
log('✅ Análisis completado');
341386
} catch (error) {
342387
log('❌ Error en análisis:', error);
343388
console.error('Error detallado:', error);
@@ -560,21 +605,7 @@ function setupControls(controlPanel, canvas, analysis) {
560605
if (autoRefreshCheckbox.checked) {
561606
const interval = parseInt(refreshIntervalInput.value) * 1000;
562607
autoRefreshInterval = window.setInterval(async () => {
563-
// Preservar el zoom actual antes del refresco
564-
const currentZoom = parseFloat(zoomSlider.value);
565-
const currentOpacity = parseFloat(opacitySlider.value);
566-
567-
await initializeAnalysis(canvas, controlPanel);
568-
569-
// Restaurar el zoom y opacidad después del refresco
570-
zoomSlider.value = currentZoom;
571-
zoomValue.textContent = `${Math.round(currentZoom * 100)}%`;
572-
canvas.style.transform = `scale(${currentZoom})`;
573-
canvas.style.transformOrigin = 'top left';
574-
575-
opacitySlider.value = currentOpacity;
576-
opacityValue.textContent = `${Math.round(currentOpacity * 100)}%`;
577-
canvas.style.opacity = currentOpacity;
608+
await refreshAnalysisData(canvas, controlPanel);
578609
}, interval);
579610
log(`🔄 Auto-refresco activado cada ${refreshIntervalInput.value} segundos`);
580611
} else {
@@ -595,29 +626,15 @@ function setupControls(controlPanel, canvas, analysis) {
595626
}
596627
const interval = parseInt(refreshIntervalInput.value) * 1000;
597628
autoRefreshInterval = window.setInterval(async () => {
598-
// Preservar el zoom actual antes del refresco
599-
const currentZoom = parseFloat(zoomSlider.value);
600-
const currentOpacity = parseFloat(opacitySlider.value);
601-
602-
await initializeAnalysis(canvas, controlPanel);
603-
604-
// Restaurar el zoom y opacidad después del refresco
605-
zoomSlider.value = currentZoom;
606-
zoomValue.textContent = `${Math.round(currentZoom * 100)}%`;
607-
canvas.style.transform = `scale(${currentZoom})`;
608-
canvas.style.transformOrigin = 'top left';
609-
610-
opacitySlider.value = currentOpacity;
611-
opacityValue.textContent = `${Math.round(currentOpacity * 100)}%`;
612-
canvas.style.opacity = currentOpacity;
629+
await refreshAnalysisData(canvas, controlPanel);
613630
}, interval);
614631
log(`🔄 Intervalo de auto-refresco actualizado a ${refreshIntervalInput.value} segundos`);
615632
}
616633
});
617634

618635
// Botón de actualizar
619636
refreshBtn.addEventListener('click', async () => {
620-
await initializeAnalysis(canvas, controlPanel);
637+
await refreshAnalysisData(canvas, controlPanel);
621638
});
622639

623640
// Checkboxes de visualización - refresco inmediato
@@ -689,4 +706,19 @@ function calculateDeltaE(lab1, lab2) {
689706
const deltaB = lab1.b - lab2.b;
690707

691708
return Math.sqrt(deltaL * deltaL + deltaA * deltaA + deltaB * deltaB);
709+
}
710+
711+
// Función para actualizar las coordenadas mostradas
712+
function updateCoordinatesDisplay(controlPanel) {
713+
const coordsUpperLeft = controlPanel.querySelector('#coordsUpperLeft');
714+
const coordsLowerRight = controlPanel.querySelector('#coordsLowerRight');
715+
716+
if (guardState.protectionArea) {
717+
const { x1, y1, x2, y2 } = guardState.protectionArea;
718+
coordsUpperLeft.textContent = `(${x1}, ${y1})`;
719+
coordsLowerRight.textContent = `(${x2}, ${y2})`;
720+
} else {
721+
coordsUpperLeft.textContent = '--';
722+
coordsLowerRight.textContent = '--';
723+
}
692724
}

0 commit comments

Comments
 (0)