File size: 20,467 Bytes
a95f844 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | <!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mapa íbero · Estilo Neoíbero</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<style>
/* === Paleta y estilo inspirados en la UI (Neoíbero) === */
@font-face {
font-family: 'IberiaGeorgeos';
src: local('IberiaGeorgeos'), local('Georgia');
font-weight: normal; font-style: normal;
}
:root {
--iberian-clay:#8B4513;
--iberian-ochre:#CC7722;
--iberian-stone:#5C5C5C;
--iberian-sand:#D2B48C;
--iberian-rust:#A0522D;
--iberian-bronze:#CD7F32;
--bg-grad-1:#f4e8d8;
--bg-grad-2:#e8d5c4;
--bg-grad-3:#d4c4b0;
}
*{box-sizing:border-box}
body{
margin:0;
background:linear-gradient(135deg,#f4e8d8 0%,#e8d5c4 50%,#d4c4b0 100%)!important;
color:var(--iberian-stone);
font-family: Georgia, 'Times New Roman', serif;
}
.wrap{max-width:1100px;margin:0 auto;padding:24px}
h1,h2,h3{
color:var(--iberian-clay);
text-shadow:2px 2px 4px rgba(139,69,19,.15);
letter-spacing:.5px;
}
h1{
font-size:clamp(22px,2.6vw,32px);
margin:0 0 8px;
border-bottom:3px solid var(--iberian-bronze);
padding-bottom:.5rem;
}
.lead{margin:0 0 16px;color:#5a534c}
.grid{display:grid;gap:12px;grid-template-columns:1fr}
@media (min-width: 1024px){ .grid{grid-template-columns:2fr 1fr 1fr} }
.card{
background:linear-gradient(to bottom,#f9f6f0,#ede6dc);
border:2px solid var(--iberian-sand);
border-radius:10px;
box-shadow:0 4px 12px rgba(139,69,19,.18), inset 0 1px 0 rgba(255,255,255,.5);
padding:14px;
}
label, input, button{font-size:14px}
input[type="text"]{
width:100%;padding:8px 10px;border:2px solid var(--iberian-sand);
background:linear-gradient(to bottom,#faf8f3,#f5f0e8);
border-radius:8px;outline:none;color:var(--iberian-stone);
box-shadow:inset 2px 2px 4px rgba(139,69,19,.1);
}
input[type="text"]:focus{border-color:var(--iberian-bronze); box-shadow:inset 2px 2px 4px rgba(139,69,19,.1), 0 0 8px rgba(205,127,50,.3)}
input[type="range"]{width:100%}
.hint{font-size:12px;color:#6f655c;margin-top:6px}
.btn{
display:inline-block;background:linear-gradient(145deg,var(--iberian-bronze),var(--iberian-rust));
color:#fff;border:2px solid var(--iberian-clay);border-radius:8px;padding:.6rem 1rem;
text-decoration:none;font-weight:600;box-shadow:0 4px 8px rgba(139,69,19,.3), inset 0 1px 0 rgba(255,255,255,.2);
}
.btn:hover{background:linear-gradient(145deg,var(--iberian-rust),var(--iberian-bronze));transform:translateY(-1px)}
.ticks{display:flex;justify-content:space-between;font-size:11px;color:#6b7280;user-select:none;margin-top:6px}
.map-wrap{position:relative}
#map{
height:clamp(420px, 70vh, 1000px);
width:100%;
border-radius:10px;
border:2px solid var(--iberian-sand);
box-shadow:0 4px 12px rgba(139,69,19,.25)
}
.legend{
position:absolute;right:12px;top:12px;background:rgba(255,255,255,.9);
border:2px solid var(--iberian-sand);border-radius:10px;padding:8px 10px;font-size:12px;
box-shadow:2px 2px 6px rgba(0,0,0,.15)
}
.dot{display:inline-block;width:9px;height:9px;border-radius:999px;margin-right:6px;vertical-align:middle}
.dot-oppida{background:var(--iberian-clay)}
.dot-contact{background:var(--iberian-bronze)}
.dot-tribe{background:transparent;border:2px solid var(--iberian-rust)}
.side{display:grid;grid-template-columns:1fr;gap:12px;margin-top:12px}
@media(min-width:768px){ .side{grid-template-columns:1fr 2fr} }
ul.clean{list-style:none;padding:0;margin:0}
ul.clean li{display:flex;align-items:center;gap:8px;padding:3px 0;border-bottom:1px dashed #e2d4c4}
ul.clean li:last-child{border-bottom:0}
.prose{line-height:1.7}
.prose h2{margin-top:22px}
code{background:#f3f4f6;border:1px solid #e5e7eb;border-radius:6px;padding:1px 4px}
pre{background:#0b1220;color:#e2e8f0;border-radius:10px;padding:12px;overflow:auto}
</style>
</head>
<body>
<header class="wrap">
<h1>Mapa interactivo · Pueblos íberos (estilo Neoíbero)</h1>
<p class="lead">Explora tribus, <em>oppida</em> y contactos mediterráneos (c. 800 a. C. – 100 d. C.). Paleta y estética adaptadas a la UI del traductor Neoíbero.</p>
<div class="grid">
<div class="card">
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px">
<label for="year"><strong>Año:</strong> <span id="yearLabel"></span></label>
<label style="font-size:12px"><input type="checkbox" id="showAllYears"> Mostrar todo</label>
</div>
<input id="year" type="range" min="-800" max="100" step="5">
<div class="ticks" id="ticks"></div>
</div>
<div class="card">
<div><strong>Capas</strong></div>
<label><input type="checkbox" id="layerTribes" checked> Áreas tribales</label><br>
<label><input type="checkbox" id="layerSites" checked> Oppida / santuarios</label><br>
<label><input type="checkbox" id="layerContacts" checked> Colonias y contactos</label>
</div>
<div class="card">
<label for="filter"><strong>Filtro por nombre</strong></label>
<input id="filter" type="text" placeholder="Escribe 'Sagunto', 'Gadir', 'Baza'…">
<div class="hint">El filtro aplica a todas las capas visibles.</div>
</div>
</div>
</header>
<main class="wrap">
<div class="map-wrap card" aria-label="Mapa de España con capas históricas (paleta Neoíbero)">
<div id="map"></div>
<div class="legend">
<div style="font-weight:600;margin-bottom:4px">Leyenda</div>
<div><span class="dot dot-oppida"></span>Oppida / santuarios</div>
<div><span class="dot dot-contact"></span>Colonias / contactos</div>
<div><span class="dot dot-tribe"></span>Áreas tribales (aprox.)</div>
</div>
</div>
<div class="side">
<div class="card">
<h3 style="margin:0 0 6px">Elementos visibles <span id="visibleScope"></span></h3>
<ul class="clean" id="visibleList"></ul>
</div>
<div class="card">
<h3 style="margin:0 0 6px">Cronología clave</h3>
<ol id="timelineList" style="margin:0 0 0 18px"></ol>
</div>
</div>
<article class="card prose" style="margin-top:12px">
<h2>Notas y compatibilidad</h2>
<p>Este archivo sigue la <strong>paleta</strong> y el <strong>estilo</strong> del proyecto Neoíbero: arcilla, ocre, bronce y arena, con tipografía serif y tarjetas con bordes texturizados. Puedes integrarlo como página independiente o incrustarlo en tu sitio.</p>
<h3>Cómo incrustar</h3>
<pre><iframe src="mapa_iberos_neoibero.html" width="100%" height="720" style="border:0"></iframe></pre>
<p class="hint">Teselas de <em>OpenStreetMap</em> con atribución incluida.</p>
</article>
</main>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// ===== Utilidades formato/año =====
const fmtYear = (y) => (y < 0 ? Math.abs(y) + " a. C." : y + " d. C.");
const YEAR_MIN = -800, YEAR_MAX = 100;
// ===== Colores desde CSS =====
function cssVar(name){ return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); }
const COLORS = {
oppida: cssVar('--iberian-clay') || '#8B4513',
contact: cssVar('--iberian-bronze') || '#CD7F32',
tribe: cssVar('--iberian-rust') || '#A0522D',
tribeFill: cssVar('--iberian-ochre') || '#CC7722',
};
// ===== Datos (resumen didáctico) =====
const TRIBES = [
{ name: "Turdetanos", center: [37.4, -5.9], radius: 120000, start: -500, end: -100, note: "Herederos en parte de Tarteso; Guadalquivir bajo y medio." },
{ name: "Bastetanos", center: [37.5, -2.7], radius: 90000, start: -500, end: -50, note: "Sureste: Basti (Baza), Acci (Guadix)." },
{ name: "Contestanos", center: [38.6, -0.8], radius: 85000, start: -500, end: -50, note: "Sur de Valencia y norte de Alicante." },
{ name: "Edetanos", center: [39.6, -0.5], radius: 70000, start: -500, end: -50, note: "Hinterland de Valencia; Edeta (Llíria)." },
{ name: "Ilergetes", center: [41.6, 0.6], radius: 70000, start: -500, end: -100, note: "Llanos del Segre-Cinca (Lleida)." },
{ name: "Ilercavones", center: [40.8, 0.5], radius: 70000, start: -500, end: -50, note: "Bajo Ebro y norte de Castellón." },
{ name: "Oretanos (ibéricos)", center: [38.5, -3.3], radius: 80000, start: -500, end: -50, note: "Alto Guadalquivir; Cástulo." },
{ name: "Lacetanos", center: [41.8, 1.8], radius: 60000, start: -450, end: -50, note: "Interior de Cataluña central." },
{ name: "Layetanos", center: [41.4, 2.1], radius: 40000, start: -500, end: -50, note: "Costa de Barcelona; contactos griegos y fenicios." },
{ name: "Indiketes", center: [42.1, 3.1], radius: 40000, start: -575, end: -50, note: "Empordà; entorno de Emporion." },
{ name: "Ausetanos", center: [41.9, 2.3], radius: 50000, start: -450, end: -50, note: "Zona de Vic (Osona)." },
{ name: "Cessetanos", center: [41.2, 1.2], radius: 50000, start: -450, end: -50, note: "Penedès y entorno de Tarraco." },
{ name: "Sedetanos (frontera)", center: [41.6, -0.9], radius: 65000, start: -400, end: -50, note: "Valle medio del Ebro (área de Zaragoza)." },
{ name: "Mastienos", center: [37.8, -1.1], radius: 60000, start: -500, end: -200, note: "Entorno de Mastia/Carthago Nova (Murcia-Cartagena)." }
];
const IBERIAN_SITES = [
{ name: "Ullastret (Indika)", coords: [42.0, 3.0], start: -550, end: -200, note: "Oppidum con murallas monumentales." },
{ name: "La Bastida de les Alcusses (Moixent)", coords: [38.85, -0.81], start: -500, end: -350, note: "‘Guerrero de Moixent’." },
{ name: "La Alcudia – Ilici (Elche)", coords: [38.25, -0.72], start: -500, end: 100, note: "Centro ibérico y romano; contexto de la Dama de Elche." },
{ name: "Basti (Baza)", coords: [37.49, -2.77], start: -400, end: -50, note: "Necrópolis con esculturas (Dama de Baza)." },
{ name: "Cástulo (Linares)", coords: [38.11, -3.63], start: -500, end: 50, note: "Nodo minero-comercial del alto Guadalquivir." },
{ name: "Arse / Saguntum (Sagunto)", coords: [39.68, -0.28], start: -500, end: 100, note: "Asedio cartaginés en 219 a. C." },
{ name: "Castellar de Meca (Ayora-Alpera)", coords: [38.96, -1.13], start: -400, end: -50, note: "Oppidum rupestre con cisternas talladas." },
{ name: "Tossal de Sant Miquel – Edeta (Llíria)", coords: [39.63, -0.58], start: -500, end: -50, note: "Capital edetana; epigrafía íbera." },
{ name: "La Serreta (Alcoi)", coords: [38.72, -0.45], start: -375, end: -50, note: "Santuario con exvotos y cerámica pintada." },
{ name: "Puig Castellar (Sta. Coloma de Gramenet)", coords: [41.46, 2.23], start: -350, end: -50, note: "Asentamiento layetano en altura." },
{ name: "Lucentum – Tossal de Manises (Alicante)", coords: [38.37, -0.42], start: -300, end: 100, note: "Centro ibérico romanizado (Lucentum)." },
{ name: "Cabezo Lucero (Guardamar del Segura)", coords: [38.08, -0.61], start: -400, end: -200, note: "Necrópolis; Dama de Guardamar." },
{ name: "El Cigarralejo (Mula)", coords: [38.05, -1.49], start: -350, end: -50, note: "Necrópolis ibérica con rico ajuar." },
{ name: "Cerro de los Santos (Montealegre del Castillo)", coords: [38.73, -1.23], start: -350, end: -50, note: "Santuario con esculturas oferentes." },
{ name: "Porcuna – Cerrillo Blanco (Obulco)", coords: [37.88, -4.19], start: -400, end: -50, note: "Conjunto escultórico ibérico excepcional." },
{ name: "Puente Tablas (Jaén)", coords: [37.81, -3.71], start: -600, end: -300, note: "Oppidum con puerta-santuario y urbanismo planificado." }
];
const CONTACT_SITES = [
{ name: "Emporion (Empúries, griega)", coords: [42.13, 3.12], start: -575, end: 100, note: "Fundación focea; puerta de bienes e ideas griegas." },
{ name: "Gadir (Cádiz, fenicia)", coords: [36.53, -6.29], start: -800, end: 100, note: "Larga tradición fenicia; comercio atlántico." },
{ name: "Qart Hadasht / Carthago Nova (Cartagena)", coords: [37.6, -0.99], start: -228, end: 100, note: "Fundada por Asdrúbal; tomada en 209 a. C." },
{ name: "Malaka (Málaga, fenicia)", coords: [36.72, -4.42], start: -700, end: 100, note: "Factoría fenicia; salazones y comercio." },
{ name: "Sexi (Almuñécar, fenicia)", coords: [36.73, -3.69], start: -700, end: 100, note: "Red fenicia en la costa granadina." },
{ name: "Abdera (Adra, fenicia)", coords: [36.75, -3.02], start: -700, end: 100, note: "Punto nodal del sudeste." }
];
const TIMELINE = [
{ year: -800, label: "Primeras factorías fenicias en el sur (Tiro–Gadir)." },
{ year: -650, label: "Intensificación de intercambios fenicio-púnicos." },
{ year: -575, label: "Fundación de Emporion (Empúries) por foceos." },
{ year: -500, label: "Consolidación de oppida ibéricos y redes regionales." },
{ year: -450, label: "Difusión de escrituras ibéricas (meridional y nororiental)." },
{ year: -350, label: "Apogeo urbano; cerámicas pintadas y santuarios monumentales." },
{ year: -300, label: "Primeras acuñaciones locales y monetización creciente." },
{ year: -219, label: "Asedio de Arse (Sagunto); preludio de la II Guerra Púnica." },
{ year: -209, label: "Escipión toma Qart Hadasht (Cartagena)." },
{ year: -197, label: "Hispania Citerior y Ulterior: organización provincial romana." },
{ year: -154, label: "Inicio de las guerras celtibéricas (contexto peninsular)." },
{ year: -133, label: "Fin de las guerras celtibéricas." },
{ year: -27, label: "Reforma de Augusto y municipalización." },
{ year: -19, label: "Fin de las guerras cántabras; integración peninsular completada." },
{ year: 14, label: "Muerte de Augusto; romanización avanzada." }
];
// ===== DOM helpers / estado =====
const $ = (id) => document.getElementById(id);
const state = { year:-250, showAllYears:false, layerTribes:true, layerSites:true, layerContacts:true, filter:"" };
const withinYear = (item) => state.showAllYears ? true : (state.year >= item.start && state.year <= item.end);
const nameMatches = (item) => item.name.toLowerCase().includes(state.filter.trim().toLowerCase());
// ===== Leaflet =====
const map = L.map('map', { zoomControl:true, scrollWheelZoom:true }).setView([39.8, -3.7], 6);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© OpenStreetMap contributors'
}).addTo(map);
const gTribes = L.layerGroup().addTo(map), gSites = L.layerGroup().addTo(map), gContacts = L.layerGroup().addTo(map);
function renderLayers(){
gTribes.clearLayers(); gSites.clearLayers(); gContacts.clearLayers();
if(state.layerTribes){
TRIBES.filter(x=>withinYear(x) && nameMatches(x)).forEach(t => {
L.circle(t.center, {radius:t.radius,color:COLORS.tribe,weight:2,fillOpacity:.08,fillColor:COLORS.tribeFill})
.bindPopup(`<div style="font-size:13px"><div style="font-weight:600">${t.name}</div><div style="color:#5a534c">${fmtYear(t.start)} – ${fmtYear(t.end)}</div><p style="margin:.3em 0 0">${t.note}</p><p style="margin:.3em 0 0;color:#6b7280;font-size:11px">Área aproximada (fines didácticos).</p></div>`)
.addTo(gTribes);
});
}
if(state.layerSites){
IBERIAN_SITES.filter(x=>withinYear(x) && nameMatches(x)).forEach(s => {
L.circleMarker(s.coords, {radius:6,color:COLORS.oppida,weight:2,fillOpacity:.9,fillColor:COLORS.oppida})
.bindPopup(`<div style="font-size:13px"><div style="font-weight:600">${s.name}</div><div style="color:#5a534c">${fmtYear(s.start)} – ${fmtYear(s.end)}</div><p style="margin:.3em 0 0">${s.note}</p></div>`)
.addTo(gSites);
});
}
if(state.layerContacts){
CONTACT_SITES.filter(x=>withinYear(x) && nameMatches(x)).forEach(c => {
L.circleMarker(c.coords, {radius:5,color:COLORS.contact,weight:2,fillOpacity:.7,fillColor:COLORS.contact})
.bindPopup(`<div style="font-size:13px"><div style="font-weight:600">${c.name}</div><div style="color:#5a534c">${fmtYear(c.start)} – ${fmtYear(c.end)}</div><p style="margin:.3em 0 0">${c.note}</p></div>`)
.addTo(gContacts);
});
}
}
function updateControlsUI(){
$('year').disabled = state.showAllYears;
$('year').value = state.year;
$('yearLabel').textContent = state.showAllYears ? 'todos los años' : fmtYear(state.year);
$('visibleScope').textContent = state.showAllYears ? '(todos los años)' : 'en ' + fmtYear(state.year);
}
function updateVisibleList(){
const visible = [];
if(state.layerTribes) TRIBES.filter(x=>withinYear(x) && nameMatches(x)).forEach(t => visible.push({k:'T', name:t.name}));
if(state.layerSites) IBERIAN_SITES.filter(x=>withinYear(x) && nameMatches(x)).forEach(s => visible.push({k:'S', name:s.name}));
if(state.layerContacts) CONTACT_SITES.filter(x=>withinYear(x) && nameMatches(x)).forEach(c => visible.push({k:'C', name:c.name}));
const ul = $('visibleList'); ul.innerHTML = '';
if(visible.length === 0){ ul.innerHTML = '<li style="color:#6b7280">No hay elementos con estos filtros.</li>'; return; }
visible.forEach(v => {
const li = document.createElement('li');
const dot = document.createElement('span');
dot.className = 'dot ' + (v.k==='T' ? 'dot-tribe' : v.k==='S' ? 'dot-oppida' : 'dot-contact');
li.appendChild(dot);
li.appendChild(document.createTextNode(v.name));
ul.appendChild(li);
});
}
function renderTimeline(){
const ticks = $('ticks'); ticks.innerHTML = '';
TIMELINE.forEach(t => {
const span = document.createElement('span');
span.textContent = t.year; span.title = fmtYear(t.year) + ' · ' + t.label; ticks.appendChild(span);
});
const ol = $('timelineList'); ol.innerHTML='';
TIMELINE.forEach(t => {
const li = document.createElement('li');
li.innerHTML = '<strong>'+fmtYear(t.year)+':</strong> '+t.label; ol.appendChild(li);
});
}
function refresh(){ renderLayers(); updateControlsUI(); updateVisibleList(); }
// ===== Eventos UI =====
$('year').addEventListener('input', e => { state.year = parseInt(e.target.value,10); refresh(); ensureSize(); });
$('showAllYears').addEventListener('change', e => { state.showAllYears = e.target.checked; refresh(); ensureSize(); });
$('layerTribes').addEventListener('change', e => { state.layerTribes = e.target.checked; refresh(); });
$('layerSites').addEventListener('change', e => { state.layerSites = e.target.checked; refresh(); });
$('layerContacts').addEventListener('change', e => { state.layerContacts = e.target.checked; refresh(); });
$('filter').addEventListener('input', e => { state.filter = e.target.value; refresh(); });
renderTimeline(); refresh();
// ===== Robustez en contenedores ocultos (HF Spaces / pestañas Gradio) =====
function ensureSize(){ try{ map.invalidateSize({animate:false}); }catch(e){} }
// al cargar y tras pequeños retrasos (layout async)
window.addEventListener('load', ()=>{ ensureSize(); setTimeout(ensureSize,200); setTimeout(ensureSize,900); });
// al redimensionar ventana
window.addEventListener('resize', ()=>{ ensureSize(); });
// cuando la página vuelve a ser visible
document.addEventListener('visibilitychange', ()=>{ if(!document.hidden){ setTimeout(ensureSize,60); }});
// si el padre avisa que la pestaña se mostró
window.addEventListener('message', (e)=>{
try{
if(e && e.data && e.data.type==='neoibero-tab-shown'){ setTimeout(ensureSize,50); }
}catch(_){}
});
// ===== Comunicar altura al padre para iframes autoajustables =====
function postHeight(){
try{
const h = document.body.scrollHeight;
parent && parent.postMessage && parent.postMessage({type:'neoibero-map-height', height:h}, '*');
}catch(e){}
}
new ResizeObserver(postHeight).observe(document.body);
setTimeout(postHeight, 500);
</script>
</body>
</html>
|