USER
Revisa este código en busca de errores:
<script>
const source = document.getElementById('source');
const target = document.getElementById('map');
let draggable;
source.addEventListener('click', () => {
if (!draggable) {
draggable = document.createElement('div');
draggable.id = 'draggable';
target.appendChild(draggable);
interact(draggable).draggable({
modifiers: [
interact.modifiers.restrictRect({
restriction: target,
endOnly: true
})
],
listeners: {
start(event) {
console.log(event.type, event.target);
},
move(event) {
const target = event.target;
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
target.style.transform = `translate(${x}px, ${y}px)`;
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
},
end(event) {
console.log(event.type, event.target);
}
}
});
}
});
</script>
<script>
var latitud = parseFloat('21.434093106363974');
var longitud = parseFloat('-79.89889674949028');
var z = 20;
</script>
<script>
// Selección de elementos del DOM
const imagen1 = document.getElementById('imagen1');
const imagen2 = document.getElementById('imagen2');
const imagen3 = document.getElementById('imagen3');
const imagen4 = document.getElementById('imagen4');
const imagen5 = document.getElementById('imagen5');
const imagen6 = document.getElementById('imagen6');
const imagen7 = document.getElementById('imagen7');
const imagen8 = document.getElementById('imagen8');
const imagen9 = document.getElementById('imagen9');
const acercar = document.getElementById('acercar');
const alejar = document.getElementById('alejar');
const arriba = document.getElementById('arriba');
const abajo = document.getElementById('abajo');
const derecha = document.getElementById('derecha');
const izquierda = document.getElementById('izquierda'); // Nuevo botón
// Límites para el zoom y las coordenadas
const MAX_ZOOM = 20;
const MIN_ZOOM = 1;
const MAX_LATITUD = 90;
const MIN_LATITUD = -90;
const MAX_LONGITUD = 180;
const MIN_LONGITUD = -180;
// Objeto que define los decrementos según el nivel de zoom
const decrementosZoom = {
20: 0.000300,
19: 0.00060,
18: 0.0012,
17: 0.0024,
16: 0.0048,
15: 0.0096,
14: 0.0192,
13: 0.0384,
12: 0.0768,
11: 0.1536,
10: 0.3072,
9: 0.6144,
8: 1.2288,
7: 2.4576,
6: 4.9152,
5: 9.8304,
4: 19.6608,
3: 39.3216,
2: 45,
1: 90
};
// Función para generar URLs de imágenes del mapa
function generarURLs(latitud, longitud, z) {
const lat = latitud;
const lon = longitud;
const zoom = z;
const x = Math.floor((lon + 180) / 360 * Math.pow(2, zoom));
const y = Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, zoom));
function construirURLs(x, y, z) {
const coords = [
[x - 1, y - 1], [x, y - 1], [x + 1, y - 1],
[x - 1, y], [x, y], [x + 1, y],
[x - 1, y + 1], [x, y + 1], [x + 1, y + 1]
];
return coords.map(([xi, yi]) => `https://wavesunpv.com/core/mapdesigner.php?5fhge=${yi}&4d5fhr=${xi}&hfst4=${z}`);
}
// Construir las URLs
const urls = construirURLs(x, y, z);
// Asignar URLs a las imágenes con manejo de errores
for (let i = 0; i < urls.length; i++) {
const img = document.getElementById(`imagen${i + 1}`);
// Quitar cualquier manejador previo para evitar múltiples asignaciones
img.onerror = null;
// Establecer un manejador de error único
img.onerror = () => {
console.error(`Error al cargar la imagen: ${urls[i]}`);
// Establecer una imagen de reemplazo solo una vez
if (!img.dataset.error) {
img.src = 'ruta_a_una_imagen_de_error.png'; // Asegúrate de que esta ruta sea válida
img.dataset.error = 'true'; // Marcar que ya intentó cargar la imagen de error
}
};
img.src = urls[i];
}
return urls;
}
// Generación inicial de URLs (llamada única)
generarURLs(latitud, longitud, z);
console.log(`URLs iniciales generadas.`);
// Función para restringir valores dentro de los límites
function limitarValor(valor, minimo, maximo) {
return Math.min(Math.max(valor, minimo), maximo);
}
// Función para actualizar el mapa
function actualizarMapa() {
generarURLs(latitud, longitud, z);
console.log(`Latitud: ${latitud}, Longitud: ${longitud}, Zoom: ${z}`);
}
// Manejo de eventos para acercar (Zoom In)
acercar.addEventListener('click', () => {
if (z < MAX_ZOOM) {
z += 1;
actualizarMapa();
} else {
console.warn(`Nivel de zoom máximo alcanzado: ${MAX_ZOOM}`);
}
});
// Manejo de eventos para alejar (Zoom Out)
alejar.addEventListener('click', () => {
if (z > MIN_ZOOM) {
z -= 1;
actualizarMapa();
} else {
console.warn(`Nivel de zoom mínimo alcanzado: ${MIN_ZOOM}`);
}
});
// Función para mover el mapa en una dirección específica
function moverMapa(direccion) {
const decremento = decrementosZoom[z];
if (decremento === undefined) {
console.error(`No hay decremento definido para el nivel de zoom: ${z}`);
return;
}
switch(direccion) {
case 'arriba':
latitud += decremento;
latitud = limitarValor(latitud, MIN_LATITUD, MAX_LATITUD);
break;
case 'abajo':
latitud -= decremento;
latitud = limitarValor(latitud, MIN_LATITUD, MAX_LATITUD);
break;
case 'derecha':
longitud += (z >=1 && z <=20) ? decremento * 1.25 : decremento; // Ajuste opcional
if (longitud > MAX_LONGITUD) longitud -= 360; // Envolver a través de la longitud
break;
case 'izquierda':
longitud -= (z >=1 && z <=20) ? decremento * 1.25 : decremento; // Ajuste opcional
if (longitud < MIN_LONGITUD) longitud += 360; // Envolver a través de la longitud
break;
default:
console.error(`Dirección desconocida: ${direccion}`);
return;
}
actualizarMapa();
}
// Manejo de eventos para mover arriba
arriba.addEventListener('click', () => {
moverMapa('arriba');
});
// Manejo de eventos para mover abajo
abajo.addEventListener('click', () => {
moverMapa('abajo');
});
// Manejo de eventos para mover derecha
derecha.addEventListener('click', () => {
moverMapa('derecha');
});
// Manejo de eventos para mover izquierda
izquierda.addEventListener('click', () => {
moverMapa('izquierda');
});
</script>ASSISTANT
He revisado el código que proporcionaste y he identificado varios puntos que podrían causar errores o comportamientos inesperados. A continuación, detallo estos aspectos junto con recomendaciones para corregirlos:
### 1. **Inclusión de la Biblioteca `interact.js`**
**Problema:**
En el primer bloque de código, utilizas la función `interact()`, que forma parte de la biblioteca `interact.js`. Sin embargo, no veo que hayas incluido esta biblioteca en tu HTML.
**Solución:**
Asegúrate de incluir la biblioteca antes de tu script que la utiliza. Puedes hacerlo añadiendo la siguiente línea en la sección `<head>` de tu HTML o antes de tus scripts:
```html
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
```
**Ejemplo:**
```html
<head>
<!-- Otras etiquetas -->
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
</head>
```
### 2. **Existencia de Elementos del DOM**
**Problema:**
El código hace referencia a múltiples elementos por su `id` (por ejemplo, `source`, `map`, `imagen1` a `imagen9`, `acercar`, `alejar`, etc.). Si alguno de estos elementos no existe en el HTML, `document.getElementById` retornará `null`, lo que puede causar errores al intentar acceder a sus propiedades o agregar event listeners.
**Solución:**
Verifica que todos los elementos mencionados existan en tu HTML y que sus `id` coincidan exactamente con los utilizados en el JavaScript. Por ejemplo:
```html
<div id="source">Fuente</div>
<div id="map">
<img id="imagen1" src="" alt="Imagen 1">
<!-- Repite para imagen2 a imagen9 -->
</div>
<button id="acercar">Acercar</button>
<button id="alejar">Alejar</button>
<!-- Repite para los demás botones: arriba, abajo, derecha, izquierda -->
```
**Recomendación Adicional:**
Para evitar errores en tiempo de ejecución, puedes agregar comprobaciones después de obtener los elementos:
```javascript
const source = document.getElementById('source');
const target = document.getElementById('map');
if (!source || !target) {
console.error("Los elementos 'source' o 'map' no existen en el DOM.");
}
```
### 3. **Declaración de Variables Globales**
**Problema:**
Estás usando `var` para declarar `latitud`, `longitud` y `z`, lo que las convierte en variables globales. Esto puede llevar a conflictos o comportamientos inesperados, especialmente si el código crece o se integra con otras librerías.
**Solución:**
Es preferible usar `let` o `const` para declarar variables con alcance de bloque y mejorar la gestión de variables.
**Ejemplo:**
```javascript
let latitud = parseFloat('21.434093106363974');
let longitud = parseFloat('-79.89889674949028');
let z = 20;
```
### 4. **Valores en el Objeto `decrementosZoom`**
**Problema:**
En el objeto `decrementosZoom`, los niveles de zoom 2 y 1 tienen valores notoriamente altos (`45` y `90`, respectivamente). Esto podría ser intencional, pero parece inconsistente con los valores anteriores.
**Solución:**
Verifica si estos valores son correctos según la lógica de tu aplicación. Si son errores tipográficos, corrígelos. Por ejemplo, si se esperaba `39.3216` en el nivel 2 en lugar de `45`:
```javascript
const decrementosZoom = {
// ...
3: 39.3216,
2: 0.045, // Valor corregido si es necesario
1: 0.09 // Valor corregido si es necesario
};
```
### 5. **Ruta de la Imagen de Error**
**Problema:**
En la función `generarURLs`, estableces una ruta para una imagen de reemplazo en caso de error: `'ruta_a_una_imagen_de_error.png'`. Si esta ruta no es válida o el archivo no existe, las imágenes no se cargarán correctamente.
**Solución:**
Asegúrate de que la ruta proporcionada sea correcta y que la imagen exista en esa ubicación. Por ejemplo, si tienes una imagen llamada `error.png` en una carpeta `images`, la ruta sería:
```javascript
img.src = 'images/error.png';
```
### 6. **Asignación de Event Listeners a Elementos Nulos**
**Problema:**
Si alguno de los elementos como `acercar`, `alejar`, `arriba`, etc., no existe en el DOM, intentar agregar un `addEventListener` resultará en un error, ya que estarías llamando una función sobre `null`.
**Solución:**
Después de obtener los elementos, verifica que no sean `null` antes de asignarles event listeners.
**Ejemplo:**
```javascript
if (acercar) {
acercar.addEventListener('click', () => {
if (z < MAX_ZOOM) {
z += 1;
actualizarMapa();
} else {
console.warn(`Nivel de zoom máximo alcanzado: ${MAX_ZOOM}`);
}
});
} else {
console.error("El botón 'acercar' no existe en el DOM.");
}
```
### 7. **Funciones y Variables con el Mismo Nombre**
**Problema:**
En el primer script, tienes una variable llamada `target`, y dentro de los listeners, vuelves a declarar `const target = event.target;`. Esto puede causar confusión debido a la reutilización del mismo nombre para diferentes propósitos.
**Solución:**
Usa nombres distintos para evitar conflictos y mejorar la legibilidad del código.
**Ejemplo:**
```javascript
const mainTarget = document.getElementById('map');
source.addEventListener('click', () => {
if (!draggable) {
draggable = document.createElement('div');
draggable.id = 'draggable';
mainTarget.appendChild(draggable);
interact(draggable).draggable({
modifiers: [
interact.modifiers.restrictRect({
restriction: mainTarget,
endOnly: true
})
],
listeners: {
start(event) {
console.log(event.type, event.target);
},
move(event) {
const draggableElement = event.target;
const x = (parseFloat(draggableElement.getAttribute('data-x')) || 0) + event.dx;
const y = (parseFloat(draggableElement.getAttribute('data-y')) || 0) + event.dy;
draggableElement.style.transform = `translate(${x}px, ${y}px)`;
draggableElement.setAttribute('data-x', x);
draggableElement.setAttribute('data-y', y);
},
end(event) {
console.log(event.type, event.target);
}
}
});
}
});
```
### 8. **Optimización de la Función `moverMapa`**
**Problema:**
En la función `moverMapa`, multiplicas el `decremento` por `1.25` para las direcciones `derecha` e `izquierda` solo si `z` está entre 1 y 20. Sin embargo, según las constantes definidas, `z` siempre estará dentro de este rango, haciendo que la condición adicional pueda ser innecesaria.
**Solución:**
Clarifica si este ajuste es realmente necesario. Si siempre se aplica, puedes simplificar la lógica:
```javascript
function moverMapa(direccion) {
const decremento = decrementosZoom[z];
if (decremento === undefined) {
console.error(`No hay decremento definido para el nivel de zoom: ${z}`);
return;
}
switch(direccion) {
case 'arriba':
latitud += decremento;
latitud = limitarValor(latitud, MIN_LATITUD, MAX_LATITUD);
break;
case 'abajo':
latitud -= decremento;
latitud = limitarValor(latitud, MIN_LATITUD, MAX_LATITUD);
break;
case 'derecha':
longitud += decremento * 1.25;
if (longitud > MAX_LONGITUD) longitud -= 360;
break;
case 'izquierda':
longitud -= decremento * 1.25;
if (longitud < MIN_LONGITUD) longitud += 360;
break;
default:
console.error(`Dirección desconocida: ${direccion}`);
return;
}
actualizarMapa();
}
```
Si la multiplicación por `1.25` es condicional, asegúrate de que tiene un propósito claro y documenta por qué se realiza.
### 9. **Uso de `parseFloat` con Strings Literales**
**Problema:**
En la segunda script, utilizas `parseFloat` sobre strings que ya representan números:
```javascript
var latitud = parseFloat('21.434093106363974');
var longitud = parseFloat('-79.89889674949028');
```
**Solución:**
Aunque no hay un error directo, es redundante usar `parseFloat` en strings que ya son números válidos. Puedes declarar directamente los valores como números.
**Ejemplo:**
```javascript
let latitud = 21.434093106363974;
let longitud = -79.89889674949028;
let z = 20;
```
### 10. **Manejo de Escenarios de Error Adicionales**
**Problema:**
La función `generarURLs` asigna imágenes y maneja errores básicos de carga. Sin embargo, si todas las imágenes fallan al cargar, el usuario no recibe feedback visual claro, aparte de los mensajes en la consola.
**Solución:**
Puedes mejorar la experiencia del usuario mostrando una alerta o un mensaje visible en la interfaz indicando que hubo un problema al cargar el mapa.
**Ejemplo:**
Dentro del `img.onerror`, además de registrar el error en la consola, podrías mostrar un mensaje en una sección específica de la página:
```javascript
img.onerror = () => {
console.error(`Error al cargar la imagen: ${urls[i]}`);
if (!img.dataset.error) {
img.src = 'ruta_a_una_imagen_de_error.png';
img.dataset.error = 'true';
// Mostrar mensaje al usuario
const mensajeError = document.getElementById('mensajeError');
if (mensajeError) {
mensajeError.textContent = "Hubo un problema al cargar algunas partes del mapa.";
}
}
};
```
Y en tu HTML, agregarías un elemento para mostrar el mensaje:
```html
<div id="mensajeError" style="color: red;"></div>
```
### 11. **Consideraciones de Rendimiento**
**Problema:**
Cada vez que se llama a `actualizarMapa`, se generan nuevas URLs y se asignan a las imágenes, lo que podría causar múltiples solicitudes HTTP rápidamente si el usuario interactúa mucho con los controles.
**Solución:**
Implementa mecanismos de **debounce** o **throttle** para limitar la frecuencia con la que se actualiza el mapa, mejorando así el rendimiento y reduciendo la carga en el servidor.
**Ejemplo:**
Puedes utilizar una función debounce:
```javascript
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), delay);
};
}
const actualizarMapaDebounced = debounce(actualizarMapa, 300);
// Luego, en los event listeners, llama a actualizarMapaDebounced en lugar de actualizarMapa
```
### 12. **Validación de Coordenadas**
**Problema:**
Aunque limitas `latitud` y `longitud` dentro de ciertos rangos, no validas si las nuevas coordenadas son posibles geográficamente, especialmente cerca de los polos donde las proyecciones pueden distorsionarse.
**Solución:**
Considera implementar validaciones adicionales o ajusta la lógica según las necesidades específicas de tu aplicación de mapas.
### 13. **Claridad y Mantenimiento del Código**
**Recomendación:**
Para mejorar la legibilidad y mantenimiento del código:
- **Comentarios Claros:** Asegúrate de que los comentarios expliquen el propósito y no solo lo que hace el código.
- **Modularización:** Considera dividir tu código en módulos o funciones más pequeñas y reutilizables.
- **Consistencia en Nombres:** Usa nombres de variables y funciones consistentes y descriptivos en todo el código.
### **Conclusión**
El código proporcionado tiene una buena estructura general para manejar interacciones y actualizaciones en un mapa. Sin embargo, es crucial asegurarse de que todos los elementos del DOM existan, que las librerías necesarias estén incluidas, y que se manejen adecuadamente los posibles errores. Además, optimizar el rendimiento y mejorar la legibilidad del código facilitarán futuras expansiones y mantenimientos.
Si implementas las correcciones y recomendaciones mencionadas, deberías tener un código más robusto y libre de errores.