// ============================================================ // FC Map // ============================================================ var fcLeafletMap = null; var _lastSectionH = 0; var _mapIntroShown = false; function sizeMapSection() { var header = document.querySelector('.section-header'); var headerH = header ? header.getBoundingClientRect().height : 0; var section = document.querySelector('.section-map'); var newH = window.innerHeight - headerH; if (section) { if (!_mapIntroShown) { _mapIntroShown = true; // Start from 0 height, animate to full height section.style.height = '0px'; section.style.overflow = 'hidden'; section.style.transition = 'height 0.8s cubic-bezier(0.4,0,0.2,1)'; // rAF ensures the 0px is painted first requestAnimationFrame(function() { requestAnimationFrame(function() { section.style.height = newH + 'px'; section.addEventListener('transitionend', function onSlideEnd() { section.removeEventListener('transitionend', onSlideEnd); section.style.overflow = ''; section.style.transition = ''; if (fcLeafletMap) { fcLeafletMap.invalidateSize(); fcLeafletMap.fitCoverFn && fcLeafletMap.fitCoverFn(false); } }, { once: true }); }); }); // After 3s, fade out and remove the intro overlay setTimeout(function() { var intro = document.getElementById('fc-map-intro'); if (intro) { intro.classList.add('is-hidden'); intro.addEventListener('transitionend', function() { intro.parentNode && intro.parentNode.removeChild(intro); }, { once: true }); } }, 3000); } else { section.style.height = newH + 'px'; } } if (fcLeafletMap) { fcLeafletMap.invalidateSize(); fcLeafletMap.fitCoverFn && fcLeafletMap.fitCoverFn(false); _lastSectionH = newH; } } document.addEventListener('DOMContentLoaded', sizeMapSection); window.addEventListener('resize', sizeMapSection); (function() { if (!document.getElementById('fc-map')) return; var IMG_SRC = 'https://famacollection.org/layout/fc-map-main.jpg'; // ───────────────────────────────────────────────────────────────── // PINS — dodajte/editujte ovdje // lat/lng su koordinate u pikselima slike (y od dna, x od lijeva) // Koristite konzolu: map.on('click', function(e){console.log(e.latlng);}) // pa zakomentirajte taj debug listener kad završite. // ───────────────────────────────────────────────────────────────── var SPECIFIC_DATA = [ { x: 276, y: 1677, title: 'Aerodrom', slug: 'airport' }, { x: 1538, y: 1139, title: 'Fabrika duhana', slug: 'tobacco-factory' }, { x: 1382, y: 957, title: 'Hotel Holiday Inn ', slug: 'holiday-inn-hotel' }, { x: 2083, y: 1271, title: 'Narodno pozorište', slug: 'national-theatre' }, { x: 2300, y: 887, title: 'Olimpijski muzej', slug: 'olympic-museum' }, { x: 2335, y: 1073, title: 'Pijaca Markale', slug: 'markale' }, { x: 2534, y: 1619, title: 'Pivara', slug: 'brewery' }, { x: 1927, y: 214, title: 'Porodilište', slug: 'maternity-hospital' }, { x: 1980, y: 1244, title: 'Pošta', slug: 'post-office' }, { x: 175, y: 1789, title: 'Tunel', slug: 'tunnel' }, { x: 877, y: 710, title: 'Velepekara', slug: 'city-bakery' }, { x: 2600, y: 1390, title: 'Vijećnica', slug: 'city-hall' }, { x: 1339, y: 1058, title: 'Zemaljski muzej', slug: 'national-museum' }, { x: 1869, y: 467, title: 'Zetra', slug: 'zetra' }, { x: 1063, y: 988, title: 'Zgrada Elektroprivrede', slug: 'elektroprivreda' }, { x: 152, y: 741, title: 'Zgrada Oslobođenja', slug: 'oslobodjenje' }, { x: 1848, y: 1100, title: 'Zgrada Predsjedništva', slug: 'presidency_' }, { x: 460, y: 715, title: 'Zgrada radio-televizije', slug: 'radio-television' }, { x: 1447, y: 721, title: 'Željeznička stanica', slug: 'railway-station' }, ]; // Neutralne lokacije — grupisane. // Svaka grupa daje title (prikaz u listi), slug (modal), // i coords: niz koordinata za pinove na karti. // Tematske lokacije — isti princip kao GROUP_DATA. var THEMATIC_DATA = [{ title: 'Voda', slug: 'water', coords: [ { x: 2454, y: 1641 }, { x: 2105, y: 1515 }, { x: 2235, y: 1286 }, { x: 1348, y: 888 }, { x: 823, y: 959 }, { x: 566, y: 1001 }, { x: 780, y: 783 }, { x: 1016, y: 759 } ] }, { title: 'Struja', slug: 'electricity', coords: [ { x: 269, y: 223 }, { x: 428, y: 320 }, { x: 679, y: 464 } ] }, { title: 'Grijanje', slug: 'heating', coords: [ { x: 1027, y: 666 }, { x: 1179, y: 549 }, { x: 650, y: 560 }, { x: 1977, y: 935 }, { x: 1967, y: 1529 }, { x: 2502, y: 1563 }, { x: 2336, y: 788 } ] }, { title: 'Hrana', slug: 'food', coords: [ { x: 2188, y: 1426 }, { x: 2307, y: 1510 }, { x: 1853, y: 710 }, { x: 1783, y: 899 }, { x: 716, y: 990 }, { x: 431, y: 865 } ] }, { title: 'Umjetnost', slug: 'art', coords: [ { x: 719, y: 825 }, { x: 1917, y: 1309 }, { x: 2041, y: 1270 }, { x: 1783, y: 1314 }, { x: 1540, y: 1320 }, { x: 2226, y: 1324 } ] }, { title: 'Film', slug: 'film', coords: [ { x: 1752, y: 997 } ] }, { title: 'Izrada objekata', slug: 'building-objects', coords: [ { x: 2218, y: 930 }, { x: 2227, y: 1312 } ] }, { title: 'Škole', slug: 'schools', coords: [ { x: 510, y: 904 }, { x: 590, y: 940 }, { x: 861, y: 1051 }, { x: 1651, y: 787 }, { x: 2120, y: 1034 }, { x: 2251, y: 1073 }, { x: 2443, y: 1235 }, { x: 2553, y: 1234 }, { x: 2338, y: 1352 }, { x: 2058, y: 1183 }, { x: 1928, y: 1472 }, { x: 1723, y: 1404 } ] }, { title: 'Društvo', slug: 'society', coords: [ { x: 1548, y: 948 }, { x: 1664, y: 696 }, { x: 2078, y: 1165 }, { x: 2041, y: 858 }, { x: 1932, y: 655 }, { x: 2413, y: 960 }, { x: 2465, y: 1226 }, { x: 2362, y: 1379 }, { x: 2267, y: 1614 }, { x: 1933, y: 1457 }, { x: 1157, y: 885 }, { x: 803, y: 823 }, { x: 463, y: 839 }, { x: 210, y: 863 }, { x: 346, y: 978 }, { x: 525, y: 952 }, { x: 643, y: 1050 }, { x: 892, y: 962 }, { x: 1028, y: 1063 } ] }, ]; var GROUP_DATA = [{ title: 'Mostovi', slug: 'bridges', coords: [ { x: 724, y: 912 }, { x: 825, y: 998 }, { x: 975, y: 1026 }, { x: 1100, y: 1064 }, { x: 1148, y: 1078 }, { x: 1446, y: 1185 }, { x: 1628, y: 1204 }, { x: 1731, y: 1243 }, { x: 1991, y: 1327 }, { x: 2145, y: 1374 }, { x: 2273, y: 1412 }, { x: 2379, y: 1445 }, { x: 2457, y: 1462 }, { x: 2664, y: 1530 } ] }, { title: 'Groblja', slug: 'cemeteries', coords: [ { x: 2493, y: 809 }, { x: 1932, y: 507 }, { x: 2095, y: 390 } ] }, { title: 'Bašte', slug: 'gardens', coords: [ { x: 1824, y: 713 }, { x: 1823, y: 880 }, { x: 2283, y: 1510 } ] }, { title: 'Bolnice', slug: 'hospitals', coords: [ { x: 2233, y: 525 }, { x: 1601, y: 864 }, { x: 1173, y: 787 } ] }, { title: 'Pijace', slug: 'markets', coords: [ { x: 1833, y: 647 }, { x: 2298, y: 1073 }, { x: 717, y: 943 } ] }, { title: 'Parkovi', slug: 'parks', coords: [ { x: 1874, y: 1007 }, { x: 1981, y: 951 }, { x: 717, y: 943 }, { x: 1764, y: 907 }, { x: 2335, y: 1512 }, { x: 2495, y: 1562 } ] }, { title: 'Zaštita', slug: 'protection', coords: [ { x: 285, y: 934 }, { x: 279, y: 1064 }, { x: 961, y: 814 }, { x: 1091, y: 874 }, { x: 1281, y: 870 }, { x: 1443, y: 893 }, { x: 1590, y: 993 }, { x: 1582, y: 1235 }, { x: 2106, y: 1163 }, { x: 1659, y: 1103 } ] }, { title: 'Opasne zone', slug: 'dangerous-zones', coords: [ { x: 881, y: 1062 }, { x: 897, y: 888 }, { x: 1042, y: 914 }, { x: 1188, y: 983 }, { x: 1435, y: 963 }, { x: 1565, y: 943 }, { x: 1511, y: 1072 }, { x: 1657, y: 1041 }, { x: 1641, y: 1167 }, { x: 1987, y: 1109 }, { x: 2011, y: 1304 }, { x: 2115, y: 1148 }, { x: 2172, y: 942 }, { x: 2664, y: 1468 }, { x: 2592, y: 1260 }, { x: 643, y: 854 }, { x: 293, y: 768 } ] }, { title: 'Snajperi', slug: 'snipers', coords: [ { x: 392, y: 805 }, { x: 282, y: 894 }, { x: 591, y: 857 }, { x: 736, y: 889 }, { x: 882, y: 914 }, { x: 1006, y: 945 }, { x: 1124, y: 841 }, { x: 1269, y: 899 }, { x: 1201, y: 998 }, { x: 1320, y: 1016 }, { x: 1540, y: 740 }, { x: 1444, y: 875 }, { x: 1438, y: 913 }, { x: 1451, y: 998 }, { x: 1396, y: 1043 }, { x: 1457, y: 1168 }, { x: 1505, y: 1098 }, { x: 1529, y: 1052 }, { x: 1752, y: 694 }, { x: 1737, y: 803 }, { x: 1699, y: 1026 }, { x: 1655, y: 1050 }, { x: 1669, y: 1076 }, { x: 1667, y: 1141 }, { x: 1627, y: 1180 }, { x: 1738, y: 1218 }, { x: 1897, y: 771 }, { x: 1904, y: 899 }, { x: 1911, y: 1064 }, { x: 1928, y: 1106 }, { x: 1948, y: 1200 }, { x: 1998, y: 1322 }, { x: 2055, y: 1241 }, { x: 2098, y: 1183 }, { x: 2129, y: 1131 }, { x: 2185, y: 953 }, { x: 2149, y: 1377 }, { x: 2284, y: 1389 }, { x: 2391, y: 1438 }, { x: 2367, y: 1503 }, { x: 2659, y: 1566 }, { x: 2654, y: 1488 }, { x: 2594, y: 1220 }, { x: 2560, y: 1285 }, { x: 2436, y: 1091 } ] }, { title: 'Prevoz', slug: 'transportation', coords: [ { x: 1196, y: 754 }, { x: 686, y: 781 }, { x: 1710, y: 644 }, { x: 1632, y: 1188 }, { x: 1861, y: 1070 }, { x: 2720, y: 1426 }, { x: 1391, y: 828 }, { x: 701, y: 872 }, { x: 2244, y: 1291 }, { x: 1568, y: 1075 }, { x: 1014, y: 927 }, { x: 950, y: 913 } ] }, { title: 'UNPROFOR', slug: 'unprofor', coords: [ { x: 295, y: 697 }, { x: 1364, y: 823 }, { x: 1690, y: 857 }, { x: 1555, y: 1287 }, { x: 353, y: 1626 }, { x: 1820, y: 773 } ] }, ]; var SITE_DATA = [ // url: Google Maps link koji se otvara na klik pina ili u listi { x: 1499, y: 378, title: 'Hum', title_eng: 'Hum', url: 'https://maps.app.goo.gl/EnUxHTk69rZ29GL2A' }, { x: 1890, y: 413, title: 'Asim Ferhatović Hase (Koševo) Olimpijski stadion', title_eng: 'Asim Ferhatović Hase (Koševo) Olympic Stadium', url: 'https://maps.app.goo.gl/Ludnio5k3vpeSL9X6' }, { x: 1505, y: 989, title: 'UNIS (sada UNITIC) neboderi', title_eng: 'UNIS (now UNITIC) Skyscrapers', url: 'https://maps.app.goo.gl/G78UEBALZbDNxdsYA' }, { x: 2389, y: 1197, title: 'Katedrala Srca Isusova', title_eng: 'Sacred Heart Cathedral', url: 'https://maps.app.goo.gl/mFYfbHenvnNi81ar5' }, { x: 1990, y: 971, title: 'Veliki park', title_eng: 'Veliki park', url: 'https://maps.app.goo.gl/sN7fAYx8H9ggNagBA' }, { x: 1944, y: 1144, title: 'Robna kuća Sarajka (sada ARIA Mall)', title_eng: 'Department Store Sarajka (now ARIA Mall)', url: 'https://maps.app.goo.gl/LGQEgoGxwhRWcwCY7' }, { x: 1880, y: 1248, title: 'Pravni fakultet Sarajevo', title_eng: 'Faculty of Law Sarajevo', url: 'https://maps.app.goo.gl/Su2FTSCX83nVzpLTA' }, { x: 1858, y: 1372, title: 'Likovna akademija Sarajevo', title_eng: 'Academy of Fine Arts', url: 'https://maps.app.goo.gl/8Lq9EHC5o55VcrUo9' }, { x: 2174, y: 564, title: 'Bolnica Koševo (sada Klinički centar Univerziteta Sarajevo)', title_eng: 'Hospital Koševo (now Sarajevo University Clinical Centre)', url: 'https://maps.app.goo.gl/G8vguSVjEmnkAdaj9' }, { x: 2070, y: 428, title: 'Groblje Lav', title_eng: 'Cemetery Lav', url: 'https://maps.app.goo.gl/fCk9xWQQWA3nsWzV9' }, { x: 1661, y: 722, title: 'Ciglane', title_eng: 'Ciglane', url: 'https://maps.app.goo.gl/c2rByRQxGoT3Ua3N9' }, { x: 1609, y: 927, title: 'Vojna bolnica (sada Opća bolnica \'Prim. dr. Abdulah Nakaš\')', title_eng: 'Military Hospital (now General Hospital \'Prim. dr. Abdulah Nakaš\')', url: 'https://maps.app.goo.gl/uJuJubPFB6MjDNL76' }, { x: 1709, y: 1276, title: 'Ajfelov most', title_eng: 'Eiffel\'s Bridge', url: 'https://maps.app.goo.gl/6PZLDGoZ8Hqon8V37' }, { x: 1487, y: 1361, title: 'Centar Skenderija', title_eng: 'Centre Skenderija', url: 'https://maps.app.goo.gl/rRXhW3XHwSHLVcaC9' }, { x: 1974, y: 1370, title: 'Most Čobanija', title_eng: 'Čobanija Bridge', url: 'https://maps.app.goo.gl/4B9sm4grDcM1TXfd6' }, { x: 2191, y: 1494, title: 'Papagajka', title_eng: 'Papagajka Building', url: 'https://maps.app.goo.gl/mxgj3t5cyrVY9Z9J6' }, { x: 2396, y: 1566, title: 'Careva džamija', title_eng: 'Emperor\'s Mosque', url: 'https://maps.app.goo.gl/EYc5MSRZbbRXnhur6' }, { x: 2372, y: 1679, title: 'Crkva Sv. Ante Padovanskog', title_eng: 'St. Anthony Church', url: 'https://maps.app.goo.gl/2VaqGUSd2XKCMkFV9' }, { x: 2057, y: 1457, title: 'Aškenaska sinagoga', title_eng: 'Ashkenazi Synagogue', url: 'https://maps.app.goo.gl/iWf1Mk2Q8agT7bqW9' }, { x: 852, y: 1343, title: 'Spomen-park Vraca', title_eng: 'Memorial Park Vraca', url: 'https://maps.app.goo.gl/H2F4JJVZCSZqUyCr9' }, { x: 1332, y: 1343, title: 'Jevrejsko groblje', title_eng: 'Jewish Cemetery', url: 'https://maps.app.goo.gl/WB3vhSNx2NJfZjuX8' }, { x: 1437, y: 1214, title: 'Vrbanja most (sada Most Suade i Olge)', title_eng: 'Vrbanja Bridge (now Suada and Olga Bridge)', url: 'https://maps.app.goo.gl/VKL1unFyyQYSjrv78' }, { x: 1656, y: 1015, title: 'Crveni križ Sarajevo (nekada i Kino Sutjeska)', title_eng: 'Red Cross Sarajevo (once also Cinema Sutjeska)', url: 'https://maps.app.goo.gl/MZCdwPKrpwGJBwB76' }, { x: 1603, y: 1255, title: 'Most Skenderija', title_eng: 'Skenderija Bridge', url: 'https://maps.app.goo.gl/5Rs67XF6yvgVCSr97' }, { x: 2257, y: 1453, title: 'Most Ćumurija', title_eng: 'Ćumurija Bridge', url: 'https://maps.app.goo.gl/fdwMrcZeioPvKWev7' }, { x: 2138, y: 1412, title: 'Most Drvenija', title_eng: 'Drvenija Bridge', url: 'https://maps.app.goo.gl/hfwT58vwuxLfSrF19' }, { x: 2379, y: 1490, title: 'Latinska ćuprija', title_eng: 'Latin Bridge', url: 'https://maps.app.goo.gl/jXJCAZe2h37DRkmLA' }, { x: 2450, y: 1512, title: 'Careva ćuprija', title_eng: 'Emperor\'s Bridge', url: 'https://maps.app.goo.gl/zHzebUEx3M4AcFjn9' }, { x: 2646, y: 1552, title: 'Šeher Ćehajina Ćuprija', title_eng: 'Šeher Ćehaja Bridge', url: 'https://maps.app.goo.gl/6hCenQqXg7V3E9qQ7' }, { x: 2601, y: 1299, title: 'Sebilj', title_eng: 'Sebilj', url: 'https://maps.app.goo.gl/hc9mFv5X87rHEyYP9' }, { x: 2462, y: 1320, title: 'Sahat kula', title_eng: 'Clock Tower', url: 'https://maps.app.goo.gl/17HSfREXPNBHjRJf6' }, { x: 2293, y: 1299, title: 'Saborna crkva', title_eng: 'Orthodox Church', url: 'https://maps.app.goo.gl/THrz8LJNcQeTyBYk7' }, { x: 2086, y: 1109, title: 'Centralna banka', title_eng: 'Central Bank', url: 'https://maps.app.goo.gl/Emd2VhkRWS3iHjtv5' }, { x: 2248, y: 1104, title: 'Srednja muzička škola / Muzička akademija', title_eng: 'Music School / Music Academy', url: 'https://maps.app.goo.gl/6HhWwQ9BSouLzE5h7' }, { x: 1539, y: 1049, title: 'Tršćanska ulica (sada ul. Fra Anđela Zvizdovića)', title_eng: 'Tršćanska Street (now Fra Anđela Zvizdovića Street)', url: 'https://maps.app.goo.gl/6sdHyzcUg2AxGtbq9' }, { x: 1209, y: 909, title: 'Energoinvest', title_eng: 'Energoinvest', url: 'https://maps.app.goo.gl/sX7wDBTKbzHgVeSt9' }, { x: 1295, y: 972, title: 'Kasarna "Maršal Tito" (sada Kampus Univerziteta Sarajevo)', title_eng: '"Marshal Tito" military barracks (now Campus of the University of Sarajevo)', url: 'https://maps.app.goo.gl/fpci1tovRhejxJfv8' }, { x: 993, y: 1180, title: 'Grbavica', title_eng: 'Grbavica', url: 'https://maps.app.goo.gl/udBCc5HZn3dGLF6Y7' }, { x: 679, y: 823, title: 'Remiza (spremište za tramvaje)', title_eng: 'Tram depot', url: 'https://maps.app.goo.gl/ShoHUofM4NvWxYiW9' }, { x: 783, y: 941, title: 'Hrasno', title_eng: 'Hrasno', url: 'https://maps.app.goo.gl/Eb4wTBvZo4TAfi7R6' }, { x: 430, y: 912, title: 'Alipašino Polje', title_eng: 'Alipašino Polje', url: 'https://maps.app.goo.gl/Ts7ipsf42j1U4dVXA' }, { x: 611, y: 925, title: 'Otoka', title_eng: 'Otoka', url: 'https://maps.app.goo.gl/5XJecJV9YWu92cQF6' }, { x: 342, y: 980, title: 'Mojmilo', title_eng: 'Mojmilo', url: 'https://maps.app.goo.gl/4YyHrsRpBF6EvBjx7' }, { x: 1719, y: 1147, title: 'Skupština Grada Sarajeva (sada Općina Centar i Kanton Sarajevo)', title_eng: 'Sarajevo City Assembly (now Centre Municipality and Canton Sarajevo building)', url: 'https://maps.app.goo.gl/mbTcSwa956EmVQab9' }, { x: 250, y: 878, title: 'Vojničko Polje', title_eng: 'Vojničko Polje', url: 'https://maps.app.goo.gl/EdLGGzGUqbHq95C9A' }, { x: 2504, y: 1358, title: 'Gazi Husrev-begova džamija', title_eng: 'Gazi Husrev-beg Mosque', url: 'https://maps.app.goo.gl/JnwraeV4KQ1iz6BD6' }, { x: 2156, y: 1043, title: 'Dalmatinska ulica', title_eng: 'Dalmatinska street', url: 'https://maps.app.goo.gl/ywgLoJqwF6jHDLk89' }, { x: 2174, y: 943, title: 'Mejtaš', title_eng: 'Mejtaš', url: 'https://maps.app.goo.gl/rCBfKLNW6y3TA77u9' }, { x: 2215, y: 945, title: 'Dom izviđača (sada O.Š. Silvije Strahimir Kranjčević', title_eng: 'Scout Headquarters (now Primary School Silvije Strahimir Kranjčević', url: 'https://maps.app.goo.gl/T3x3FFKGNaPsTYZi8' }, { x: 1990, y: 912, title: 'Džidžikovac', title_eng: 'Džidžikovac', url: 'https://maps.app.goo.gl/iHnJc7y9EL71DXPK6' }, { x: 1654, y: 780, title: 'Radio ZID', title_eng: 'Radio ZID', url: 'https://maps.app.goo.gl/jHGcCKv26PpCoCyh9' }, { x: 280, y: 699, title: 'PTT Inžinjering', title_eng: 'PTT Building', url: 'https://maps.app.goo.gl/RTQfPfMxNTYxWZvLA' }, { x: 1558, y: 651, title: 'Tunel Ciglane', title_eng: 'Brick-yard Tunnel', url: 'https://maps.app.goo.gl/HxrZaCyt5VhYnS3b7' }, { x: 2563, y: 840, title: 'Višegradska kapija', title_eng: 'Višegrad Gate', url: 'https://maps.app.goo.gl/5KFaay9ejLmjVPAfA' }, { x: 1137, y: 1004, title: 'Hotel Bristol (sada Mövenpick Hotel)', title_eng: 'Hotel Bristol (now Mövenpick Hotel)', url: 'https://maps.app.goo.gl/d6sDxK6KT1jL9zhm8' }, { x: 1513, y: 1160, title: 'Fabrika duhana (sada SCC)', title_eng: 'Tobacco Factory (now SCC)', url: 'https://maps.app.goo.gl/EWcREsCT57gajS1k7' }, { x: 2288, y: 1195, title: 'Tržnica Markale', title_eng: 'Markale Market', url: 'https://maps.app.goo.gl/JLjB8rg6HxLwPzpq9' }, { x: 729, y: 846, title: 'Kentauri (premješteni)', title_eng: 'Centaurs (relocated)', url: 'https://maps.app.goo.gl/cedDjfPkzJxM5n316' }, { x: 2525, y: 982, title: 'Muzej Grada (sada Fakultet islamskih nauka)', title_eng: 'City Museum (now Faculty of Islamic Studies))', url: 'https://maps.app.goo.gl/EwuDmudQr6hrMTQr6' } ]; var map, mapBounds, w, h, coverZoom, mapImageOverlay, mapImageOverlayMono; var _allMarkers = []; function btnAnim(id) { var el = document.getElementById(id); el.classList.remove('btn-pulse'); requestAnimationFrame(function() {el.classList.add('btn-pulse');}); el.addEventListener('animationend', function() {el.classList.remove('btn-pulse');}, { once: true }); } var probe = new Image(); probe.onload = function() { initMap(this.naturalWidth, this.naturalHeight); }; probe.onerror = function() { initMap(4000, 2800); }; probe.src = IMG_SRC; function initMap(imgW, imgH) { w = imgW; h = imgH; mapBounds = [ [0, 0], [h, w] ]; map = L.map('fc-map', { crs: L.CRS.Simple, minZoom: -4, maxZoom: 4, zoomControl: false, attributionControl: false, zoomSnap: 0, scrollWheelZoom: false, keyboard: false, maxBounds: mapBounds, maxBoundsViscosity: 1.0 }); mapImageOverlay = L.imageOverlay(IMG_SRC, mapBounds, { opacity: 1 }).addTo(map); mapImageOverlayMono = L.imageOverlay('https://famacollection.org/layout/fc-map-gray.jpg', mapBounds, { opacity: 0 }).addTo(map); // Expose map and fitCover to the global sizeMapSection fcLeafletMap = map; fcLeafletMap.fitCoverFn = function(initial) { fitCover(initial !== false); }; // Size section first, then fit (ensures container has correct dimensions) sizeMapSection(); function updatePinScale() { document.getElementById('fc-map').classList.toggle('fc-map--cover', map.getZoom() <= coverZoom + 1.87); } function updateLabels() { var threshold = window.innerWidth <= 768 ? coverZoom + 3.0 : coverZoom + 2.0; document.getElementById('fc-map').classList.toggle('fc-map--labels', map.getZoom() > threshold); } map.on('zoomend', function() { updatePinScale(); updateLabels(); // Batch tooltip reposition in rAF so class changes are applied first requestAnimationFrame(function() { _allMarkers.forEach(function(m) { var tt = m.getTooltip(); if (tt) tt.update(); }); }); }); requestAnimationFrame(function() { fitCover(true); updatePinScale(); updateLabels(); }); // DEBUG — uključite da nađete koordinate, pa isključite: // map.on('click', function (e) {console.log(e.latlng);}); // Double right-click → zoom out (desktop only) var _lastRightClick = 0; map.getContainer().addEventListener('mousedown', function(e) { if (e.button !== 2) return; var now = Date.now(); if (now - _lastRightClick < 350) { var latlng = map.mouseEventToLatLng(e); map.flyTo(latlng, Math.max(map.getZoom() - 1, coverZoom - 0.75), { animate: true, duration: 0.4 }); _lastRightClick = 0; } else { _lastRightClick = now; } }); map.getContainer().addEventListener('contextmenu', function(e) {e.preventDefault();}); document.getElementById('fc-zoom-in').addEventListener('click', function() { var z = Math.min(map.getZoom() + 0.75, coverZoom + 3.75); map.flyTo(map.getCenter(), z, { animate: true, duration: 0.4 }); btnAnim('fc-zoom-in'); }); document.getElementById('fc-zoom-out').addEventListener('click', function() { var z = Math.max(map.getZoom() - 0.75, coverZoom - 0.75); map.flyTo(map.getCenter(), z, { animate: true, duration: 0.4 }); btnAnim('fc-zoom-out'); }); document.getElementById('fc-reset').addEventListener('click', function() { _prevView = null; document.getElementById('fc-overlay').classList.remove('is-open'); document.getElementById('fc-overlay-backdrop').classList.remove('is-open'); hideSpotlight(); // Compute cover target and flyTo it with animation var containerW = map.getContainer().offsetWidth; var containerH = map.getContainer().offsetHeight; var zoomW = Math.log2(containerW / w); var zoomH = Math.log2(containerH / h); var zoom = Math.max(zoomW, zoomH); coverZoom = zoom; var visibleH = containerH / Math.pow(2, zoom); var centerLat = h - visibleH / 2; map.flyTo([centerLat, w / 2], zoom, { animate: true, duration: 0.5 }); btnAnim('fc-reset'); }); SPECIFIC_DATA.forEach(function(pin) {addPin(pin);}); // Expand grouped GROUP_DATA into individual pins GROUP_DATA.forEach(function(group) { group.coords.forEach(function(coord) { var pin = { y: coord.y, x: coord.x, title: group.title, slug: group.slug, neutral: true, _group: group }; addPin(pin); group._pins = group._pins || []; group._pins.push(pin); }); }); THEMATIC_DATA.forEach(function(group) { group.coords.forEach(function(coord) { var pin = { y: coord.y, x: coord.x, title: group.title, slug: group.slug, thematic: true, _group: group }; addPin(pin); group._pins = group._pins || []; group._pins.push(pin); }); }); SITE_DATA.forEach(function(pin) { pin.site = true; addPin(pin); }); // Sort group _pins by x axis (left → right) GROUP_DATA.forEach(function(g) { if (g._pins) g._pins.sort(function(a, b) { return a.x - b.x; }); }); THEMATIC_DATA.forEach(function(g) { if (g._pins) g._pins.sort(function(a, b) { return a.x - b.x; }); }); // ── Mini-map init (needs map + coverZoom to be ready) ── (function() { var mm = document.getElementById('fc-minimap'); var mmRect = document.getElementById('fc-minimap-rect'); var MM_W = 200; function updateMinimap() { var visible = map.getZoom() > coverZoom + 0.15; mm.classList.toggle('is-visible', visible); if (!visible) return; var scale = MM_W / w; var b = map.getBounds(); var left = b.getWest() * scale; var top = (h - b.getNorth()) * scale; var rw = (b.getEast() - b.getWest()) * scale; var rh = (b.getNorth() - b.getSouth()) * scale; var mmH = MM_W * h / w; left = Math.max(0, Math.min(left, MM_W - rw)); top = Math.max(0, Math.min(top, mmH - rh)); mmRect.style.left = left + 'px'; mmRect.style.top = top + 'px'; mmRect.style.width = Math.max(4, rw) + 'px'; mmRect.style.height = Math.max(4, rh) + 'px'; } map.on('move zoom', updateMinimap); updateMinimap(); mm.addEventListener('click', function(e) { var rect = mm.getBoundingClientRect(); var scale = MM_W / w; var pixX = (e.clientX - rect.left) / scale; var pixY = (e.clientY - rect.top) / scale; map.flyTo([h - pixY, pixX], map.getZoom(), { animate: true, duration: 0.3 }); }); }()); window.addEventListener('resize', function() { sizeMapSection(); // sizeMapSection already calls invalidateSize + fitCover }); } function fitCover(resetView) { var containerW = map.getContainer().offsetWidth; var containerH = map.getContainer().offsetHeight; var zoomW = Math.log2(containerW / w); var zoomH = Math.log2(containerH / h); var zoom = Math.max(zoomW, zoomH); coverZoom = zoom; map.setMaxZoom(coverZoom + 3.75); map.setMinZoom(coverZoom - 0.75); if (resetView) { var visibleH = containerH / Math.pow(2, zoom); var centerLat = h - visibleH / 2; map.setView([centerLat, w / 2], zoom, { animate: false }); } } function makePinIcon(color) { var fill = color || '#CF1F25'; var isRed = (fill === '#CF1F25'); return L.divIcon({ className: 'fc-pin-icon fc-pin-icon-teardrop' + (isRed ? ' fc-pin-icon-red' : ''), html: '', iconSize: [28, 42], iconAnchor: [14, 42], popupAnchor: [0, -46] }); } function makeSiteIcon() { return L.divIcon({ className: 'fc-pin-icon fc-pin-icon-circle', html: '', iconSize: [28, 28], iconAnchor: [14, 14], popupAnchor: [0, -18] }); } var _prevView = null; var _prevViewKeepPos = false; var _focusMoveEndFn = null; function focusPin(pin) { _prevViewKeepPos = true; var targetZoom = Math.max((coverZoom || map.getZoom()) + Math.log2(3), coverZoom + 2.25); if (_focusMoveEndFn) { map.off('moveend', _focusMoveEndFn); } _focusMoveEndFn = function() { _focusMoveEndFn = null; showSpotlight(pin); }; map.once('moveend', _focusMoveEndFn); map.flyTo([pin.lat, pin.lng], targetZoom, { animate: true, duration: 0.6 }); } function _flyBackIfNeeded() { _prevView = null; _prevViewKeepPos = false; } function openOverlay(pin) { var overlay = document.getElementById('fc-overlay'); var backdrop = document.getElementById('fc-overlay-backdrop'); overlay.classList.add('is-open'); backdrop.classList.add('is-open'); var kicker = document.getElementById('fc-overlay-category'); var h2 = document.getElementById('fc-overlay-h2'); var content = document.getElementById('fc-overlay-content'); // Set title from JS data; static HTML in #fc-overlay-content stays untouched kicker.textContent = pin.neutral ? 'ZONE' : pin.thematic ? 'ŽIVOT' : 'LOKACIJE'; h2.textContent = pin.title || pin.title_eng; var mapsLink = document.getElementById('fc-overlay-maps-link'); if (!pin.neutral && !pin.thematic && !pin.site && pin.maps_url) { mapsLink.href = pin.maps_url; mapsLink.style.display = 'flex'; } else { mapsLink.style.display = 'none'; mapsLink.href = '#'; } // Reset all dynamic sections so stale/static HTML doesn't show through content.textContent = ''; document.getElementById('fc-overlay-macro-section').style.display = 'none'; document.getElementById('fc-overlay-macro-grid').innerHTML = ''; document.getElementById('fc-overlay-resilience-section').style.display = 'none'; document.getElementById('fc-overlay-resilience-grid').innerHTML = ''; document.getElementById('fc-overlay-gallery-section').style.display = 'none'; document.getElementById('fc-overlay-gallery').innerHTML = ''; document.getElementById('fc-overlay-voh-section').style.display = 'none'; document.getElementById('fc-overlay-voh').innerHTML = ''; document.getElementById('fc-overlay-vg-section').style.display = 'none'; document.getElementById('fc-overlay-vg').innerHTML = ''; if (pin.slug) { fetch('/layout/fcjson-map_bhs-12/map_' + pin.slug) .then(function(r) { return r.text(); }) .then(function(raw) { // EE outputs literal newlines inside text fields which break JSON.parse. // Collapsing all bare newlines to a space makes the JSON valid. var clean = raw.replace(/\r\n|\r|\n/g, ' '); var data; try { data = JSON.parse(clean); } catch (e) { console.error('FC Map JSON parse error:', e.message, '\nRaw (first 500):', raw.slice(0,500)); return; } if (!data) return; // Decode HTML entities produced by EE's |encode modifier function hDec(s) { if (!s) return ''; var t = document.createElement('textarea'); t.innerHTML = s; return t.value; } // Escape URL for use inside HTML attribute strings function escUrl(s) { return String(s || '').replace(/"/g, '%22'); } if (data.title) h2.textContent = hDec(data.title); if (data.desc) content.innerHTML = hDec(data.desc); if (data.maps_url) { mapsLink.href = data.maps_url; mapsLink.style.display = 'flex'; } // ── Macro Stories ────────────────────────────────────────── var macroSection = document.getElementById('fc-overlay-macro-section'); var macroGrid = document.getElementById('fc-overlay-macro-grid'); macroGrid.innerHTML = ''; if (data.macro && data.macro.length) { data.macro.forEach(function(item) { var a = document.createElement('a'); a.href = item.url || '#'; a.target = '_blank'; a.rel = 'noopener'; a.className = 'box cards2'; a.innerHTML = '