1 2 <!DOCTYPE html> 3 4 5 <html lang="de"> 6 7<head><title> 8 Bregenzerwald - Startseite 9</title> 10 11 12 <!-- Free Header --> 13<!-- CORE CSS --> 14<link rel="stylesheet" type="text/css" media="all" href="/system/web/GetDocument.ashx?fileid=998472&cts=1603823288" /> 15 16 17<!-- TEST CSS --> 18<!-- link rel="stylesheet" type="text/css" media="all" href="http://localhost:3000/css/main.css " / --> 19 20<style type="text/css"> 21span.boxVeranstaltungsvorschauTag { 22 display: none; 23} 24.openinghours-info { 25 width: 90%; 26 border-top: 1px dotted rgba(255,255,255,0.5); 27 padding: 0.5em 0 0; 28 color: #fff; 29} 30.openinghours-info ul { 31 margin: 0; 32 padding-left: 1em 33} 34.openinghours-info p, a { 35 color: #fff; 36 margin: 0; 37} 38.section__info { 39background: none!important; 40} 41span.ris_oz_times { 42 text-align: right; 43} 44.apps .app-container>a .app-image { 45 align-self: center; 46 padding-right: 0.5em; 47} 48.abteilungcmsdetail .abt_img_spacer { 49 padding-top: 1em; 50} 51#main .section__footer .map img { 52 padding-left: 0em; 53 max-width: 55%; 54 margin: 0 auto; 55 display: table; 56} 57.backToTop { 58 border: 1px solid #ccc; 59 border-radius: 0.25em; 60 background: #FFF; 61 padding: 0.25em; 62 margin: 0.5em; 63} 64@media all and (-ms-high-contrast:none) { 65 .megamenu > ul > li.wide { 66 position: inherit!important; 67 } 68} 69</style> 70 <link rel="canonical" href="https://www.regiobregenzerwald.at/" /> 71 72 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" /> 73 74 <link rel="stylesheet" type="text/css" href="/system/statV.1789655742/web/css/riscms_pre.css" /> 75<link rel="stylesheet" type="text/css" href="/system/statV.1789655742/Javascript/jquery/jquery-ui-1.8.17.min.css" /> 76<link rel="stylesheet" type="text/css" media="screen,print" href="/css/startseite2022__pt.css?cts=1788776812" /> 77<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick.min.css" /> 78<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-theme.min.css" /> 79<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-ris.min.css" /> 80<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-ris-indiv.min.css" /> 81<link rel="stylesheet" type="text/css" media="screen,print" href="/system/statV.1789655742/web/css/extensions/2061.css" /> 82<link rel="stylesheet" type="text/css" href="/cdnstatic/system/CSSz/fontawesome/css/all.min.css" /> 83 84 85 86
86<script type="text/javascript">var envurl = "https://www.regiobregenzerwald.at/";</script>
vendor: 2 bytes, line 86
86
87<script type="text/javascript">var rissprachid = "1";</script>
vendor: 2 bytes, line 87
87
88<script type="text/javascript">var allowTracking = false;</script>
vendor: 2 bytes, line 88
88
89<script src="/system/statV.1789655742/Javascript/Jquery/jquery.min_1.7.2.js" type="text/javascript"></script>
vendor: 2 bytes, line 89
89
90<script src="/system/statV.1789655742/Javascript/AdapterUtils.js" type="text/javascript"></script>
vendor: 2 bytes, line 90
90
91<script src="/system/statV.1789655742/Javascript/jquery/jquery-ui-1.8.17.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 91
91
92<script src="/system/statV.1789655742/Javascript/formular/jquery.validate.js" type="text/javascript"></script>
vendor: 2 bytes, line 92
92
93<script type="text/javascript">$(document).ready(function(){ 94 jQuery.extend(jQuery.validator.messages, { 95 required: "Dieses Feld ist Pflicht!", 96 email: "Bitte geben Sie eine korrekte E-Mail Adresse an!", 97 url: "Bitte geben Sie einen korrekten Link an!", 98 number: "Bitte geben Sie eine Zahl an!", 99 maxlength: "Bitte geben Sie nicht mehr als {0} Zeichen ein.", 100 minlength: "Bitte geben Sie mindestens {0} Zeichen ein.", 101 max: $.validator.format( "Bitte geben Sie einen Wert kleiner oder gleich {0} ein." ), 102 min: $.validator.format( "Bitte geben Sie einen Wert gröÃer oder gleich {0} ein." ) 103 }); 104 $('form').each(function() { 105 var $frm = $(this); 106 if($frm.data('validator') == undefined){ 107 $frm.validate( {ignoreTitle: true, errorClass: "risFrmError"}); 108 $('[type="submit"]').click(function(){ 109 var frmid = $(this).data("formonr"); 110 if (typeof frmid !== 'undefined') 111 { 112 $(this).closest('form').validate().settings.ignore = ":not([data-formonr='" + frmid + "'])"; 113 } 114 }); 115 } 116 }); 117 }); 118 </script>
vendor: 2 bytes, line 118
118
119<script src="/system/statV.1789655742/Javascript/jquery/jquery.lazy.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 119
119
120<script src="/system/statV.1789655742/Javascript/jquery/jquery.lazy.plugins.min.js" type="text/javascript" async="async"></script>
vendor: 2 bytes, line 120
120
121<script src="/system/statV.1789655742/Javascript/fingerprint.js" type="text/javascript"></script>
vendor: 2 bytes, line 121
121
122<script src="/system/statV.1789655742/JavaScript/MenuAdapter.js" type="text/javascript"></script>
vendor: 2 bytes, line 122
122
123<script src="/cdnstatic/system/Javascript/ris/mobileMenu.js" type="text/javascript"></script>
vendor: 2 bytes, line 123
123
124<script type="text/javascript">initMenu(1, 225047683, [{"sprachid":1,"datei":"german.gif","langlink":"","bez":"deutsch","title":"deutsch"}], 'Startseite', 'Suchbegriffe', 'Suche starten')</script>
vendor: 2 bytes, line 124
124
125<script src="/system/statV.1789655742/Javascript/template.js" type="text/javascript"></script>
vendor: 2 bytes, line 125
125
126<script src="/cdnstatic/system/Javascriptz/slick/slick.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 126
126
127<script type="text/javascript">var mobAppSettings = {"mobileApps":[{"name":"Gem2Go","variants":[{"agent":"Android","install":"market://details?id=WA66F5VEHP.com.ris.Gem2Go","start":null,"landscape":null},{"agent":"iPhone","install":"https://apps.apple.com/at/app/id547223237","start":null,"landscape":null},{"agent":"iPad","install":"https://apps.apple.com/at/app/id547223237","start":null,"landscape":null},{"agent":"Windows Phone","install":"http://www.microsoft.com/de-at/store/apps/gem2go/9wzdncrdr4x5","start":null,"landscape":null}],"addClass":null,"color":"#ffffff","backgroundimage":"statV.0/web/images/loginimages/mobileAppDetector-bg.jpg","image":"https://www.regiobregenzerwald.at/system/statV.0/web/images/loginimages/mobileAppDetector-512.png","imagealt":"App Icon","header":"GEM2GO APP","note":"Nutzen Sie unsere Gemeinde-App!","prompt":"in GEM2GO APP öffnen","landscape":false,"install":null,"urlSchema":"gem2go","start":null,"otherwise":null,"cookietime":30,"hinweistextHidePopup":"Diese Meldung die nächsten 30 Tage nicht mehr anzeigen","closetext":"Installationsaufforderung der GEM2GO APP schlieÃen","text":"In der GEM2GO APP öffnen","gnr":3094,"Id":"mobileapp-gem2go","deeplink":null,"arialabel":"GEM2GO Installationsaufforderung"}]}; 128</script>
128 129 130 131<meta name="author" content="Bregenzerwald" lang="de" /> 132<meta name="description" content="Bregenzerwald" lang="de" /> 133<meta name="google-site-verification" content="wkOR51duCdgoOZ7XgAphW4YK1liInC_hezFI0G3ogu4" lang="de" /> 134<meta name="keywords" content="Bregenzerwald Gemeinde Region Regional Regionales Information System Gemeinde Gemeinden" lang="de" /> 135<meta name="title" content="Bregenzerwald - Startseite" lang="de" /> 136<meta name="robots" content="index,follow" lang="de" /> 137<meta name="revisit-after" content="7 days" lang="de" /> 138<meta name="language" content="de-AT" lang="de" /> 139<meta property="fb:admins" content="100000414979333" lang="de" /> 140<meta property="og:title" content="Bregenzerwald" lang="de" /> 141<meta property="og:site_name" content="Bregenzerwald" lang="de" /> 142<meta property="og:type" content="website" lang="de" /> 143<meta property="og:url" content="https://www.regiobregenzerwald.at/" lang="de" /> 144<style type="text/css"> 145 .ctl00_ctl00_ctl00_cph_header_ctl02_0 { text-decoration:none; } 146 147</style></head> 148<body > 149 150
150<script src="/system/statV.1789655742/Javascript/rismap3/rismap3leaflet.js" type="text/javascript"></script>
vendor: 2 bytes, line 150
150
151<script src="/system/statV.1789655742/web/lightboxJQuery/js/jquery.lightbox-0.5.js" type="text/javascript"></script>
vendor: 2 bytes, line 151
151
152<script src="/system/statV.1789655742/Javascript/socialshare/jquery.socialshareprivacy.js" type="text/javascript"></script>
vendor: 2 bytes, line 152
152
153<script type="text/javascript"> 154 var rismap3_global_settings = { 155 "clickMessage" : "Klicken Sie hier um die Karte zu laden", 156 "showbasemap" : true, 157 "sgvgisenableorthophoto" : false, 158 "sgvgisenableaddress" : false, 159 "sgvgisenablestreet" : false, 160 "zoom": 16, 161 "clicktostart": false, 162 "defaultlayer": "grau", 163 164 "protocol": "https://", 165 "tilepath": "https://mffiles.gem2go.page/custom/regiobregenzerwald/tiles/", 166 "streetslbl": "StraÃen", 167 "addresslbl": "Adressen", 168 "orthofotolbl" : "Orthofoto" 169 } 170 </script>
170 171 172 173 <div id="main" class="show-all defaultcmsliste"> 174 <div id="page_top"></div> 175 176 <div id="accesskeys" class=""> 177 178 <ul class="ris_skiplinkList"> 179 <li><a href="#content" accesskey="1" class="ris_skiplink">Hauptinhalt: Kurztaste 1</a></li> 180<li><a href="#ctl00_ctl00_ctl00_cph_header_ctl02" accesskey="2" class="ris_skiplink">Hauptnavigation: Kurztaste 2</a></li> 181<li><a href="#search_225049642" accesskey="4" onclick="event.preventDefault(); document.querySelector('#search_225049642')?.focus()" class="ris_skiplink">Suche: Kurztaste 4</a></li> 182 183 </ul> 184 185 </div> 186 187 <div class="header_wrapper" aria-label="Mobilitäts-Banner" role="banner"><div id="header"> 188 189 <div class="box2042 section section__top"><div class="box2042 wrapper"><div class="box2042 wrapper__search"><div class="home"><a href="/default.aspx" aria-label="Link Startseite"><em class="fi flaticon-home"></em></a> 190 191 192</div><div class="search--einzeilig"><div class="sucheeinzeilig"> 193 <form action="/system/web/suche.aspx" id="Form_suche_225049642" method="get"> 194 <p><span id="ctl00_ctl00_ctl00_cph_header_ctl01"><input class="text" type="text" id="search_225049642" name="search" title="Suchbegriff" placeholder="Suchbegriff" /></span><input type="submit" class="button" id="searchbtn_225049642" aria-label="Suche" value=">>" /><input type="hidden" name="menuonr" value="225047683" /><input type="hidden" name="detailonr" value="0" /><input type="hidden" name="sprache" value="1" /><input type="hidden" name="mqs" value="0" /><input type="hidden" name="cmd" /></p> 195 </form> 196</div></div></div><div class="navigator navigator--text"><ul><li><a class="extlink" href="https://www.regiobregenzerwald.at/Karte">Karte</a></li><li class="navigator-tel"><a class="extlink" href="https://www.regiobregenzerwald.at/Kontakt">Kontakt</a></li><li>+<a href="tel:+43551226000" title="Regionalplanungsgemeinschaft Bregenzerwald anrufen">43 5512 26000</a></li><li class="navigator-tel"><a href="mailto:[email protected]">[email protected]</a></li></ul></div></div></div><div class="box2042 section section__header"><div class="box2042 section section__name"><div class="mandant__logo"><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/"><img src="/system/web/getImage.ashx?fileid=1348534&mode=T&width=640&height=480&cts=1787063325" class="fr-fil fr-dib width49" alt="Ein Logo mit grünem und grauem Text"></a></p><p><br></p></div><div class="box2042 wrapper"></div></div><div class="box2042 section section__topmenu"><div class="box2042 wrapper"><div class="topmenu"> 197 <div class="megamenu" id="ctl00_ctl00_ctl00_cph_header_ctl02"><ul> 198 <li class="mm-menuitem MegaMenu-WithChildren width20 normal"><a href="/Aktuelles"> 199 Aktuelles</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Aktuelles/Neuigkeiten"> 200 Neuigkeiten</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Aktuelles/Veranstaltungen"> 201 Veranstaltungen</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Aktuelles/Veranstaltungen/Veranstaltung_erfassen"> 202 Veranstaltung erfassen</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Aktuelles/Veranstaltungen/Veranstaltung_aendern"> 203 Veranstaltung ändern</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Karte"> 204 Karte</a></h3></li></ul></div></div></div></li> 205 <li class="mm-menuitem MegaMenu-WithChildren width20 wide"><a href="/Themen"> 206 Themen</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Leben"> 207 Leben</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Baurechtsverwaltung"> 208 Baurechtsverwaltung</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://sozialkompass.vorarlberg.at/" target="_blank" rel="noopener" class="extlink extlink" title="Sozialkompass (Ãffnet in neuem Fenster - Externer Link)"> 209 Sozialkompass</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Kinder_und_Jugend"> 210 Kinder und Jugend</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Gesundheit"> 211 Gesundheit</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Kultur"> 212 Kultur</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Pflege"> 213 Pflege</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Klimaschutz"> 214 Klimaschutz</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Bewegen"> 215 Bewegen</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Achtalweg"> 216 Achtalweg</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Fahrradfahren"> 217 Fahrradfahren</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/OePNV"> 218 ÃPNV</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald" target="_blank" rel="noopener" class="extlink extlink" title="Landbus Bregenzerwald (Ãffnet in neuem Fenster - Externer Link)"> 219 Landbus Bregenzerwald</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/fahrradbus-2026" target="_blank" rel="noopener" class="extlink extlink" title="Fahrradbus (Ãffnet in neuem Fenster - Externer Link)"> 220 Fahrradbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.regiobregenzerwald.at/Festspielbus_Bregenzerwald_2026" target="_blank" rel="noopener" class="extlink extlink" title="Festspielbus (Ãffnet in neuem Fenster - Externer Link)"> 221 Festspielbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/wanderbuslinie-497-bequem-ab-damuels-unterwegs" target="_blank" rel="noopener" class="extlink extlink" title="Wanderbus (Ãffnet in neuem Fenster - Externer Link)"> 222 Wanderbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/nachtbuslinien-8n1-und-8n2" target="_blank" rel="noopener" class="extlink extlink" title="Nachtbus (Ãffnet in neuem Fenster - Externer Link)"> 223 Nachtbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Carsharing"> 224 Carsharing</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Arbeiten"> 225 Arbeiten</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Bregenzerwald_Gutschein"> 226 Bregenzerwald Gutschein</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/ich_kauf_im_Wald"> 227 ich kauf im Wald</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Tourismus"> 228 Tourismus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Handwerk"> 229 Handwerk</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Landwirtschaft_1"> 230 Landwirtschaft</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/KaeseStrasse"> 231 KäseStrasse</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Bildung"> 232 Bildung</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Bewahren"> 233 Bewahren</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/bregenzerwaldarchiv"> 234 Bregenzerwald Archiv</a><ul class="forceHide"><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/A_Gemeindeverwaltung" title="Bestände der Gemeindeverwaltungen"> 235 ..... A Gemeindeverwaltung
235</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/B_Institutionen" title="Bestände von Institutionen"> 236 ..... B Institutionen</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/C_Nachlaesse" title="Nachlässe des Bregenzerwald Archivs"> 237 ..... C Nachlässe</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/D_Pertinenzbestaende" title="Pertinenzbestände des Archivs"> 238 ..... D Pertinenzbestände</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/E_Pfarrarchive" title="Pfarrarchive des Bregenzerwald Archivs"> 239 ..... E Pfarrarchive</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/F_Vereine" title="Vereinsunterlagen des Bregenzerwald Archivs"> 240 ..... F Vereine</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/G_Firmen" title="Firmenunterlagen des Bregenzerwald Archivs"> 241 ..... G Firmen</a></li></ul></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Alte_Bausubstanz"> 242 Alte Bausubstanz</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Barockbaumeister"> 243 Barockbaumeister</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Natura_2000"> 244 Natura 2000</a></li></ul></li></ul></div></div></div></li> 245 <li class="mm-menuitem MegaMenu-WithChildren width20 normal"><a href="/Regio"> 246 Regio</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Regio/Informationen"> 247 Informationen</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Kontakt"> 248 Kontakt</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Vorstand"> 249 Vorstand</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Team_Regio"> 250 Team Regio</a></h3></li></ul></div></div><div class="mm-row mm-rowX"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Team_Baurechtsverwaltung"> 251 Team Baurechtsverwaltung</a></h3></li></ul></div></div></div></li> 252 <li class="mm-menuitem MegaMenu-WithChildren width20"><a href="/Gemeinden"> 253 Gemeinden</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Gemeinden_1"> 254 Gemeinden</a></h3></li></ul></div></div></div></li> 255 <li class="mm-menuitem MegaMenu-WithChildren width20 normal"><a href="/Partner_1"> 256 Partner</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Regio_V"> 257 Regio V</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Europaeische_Projekte"> 258 Europäische Projekte</a></h3></li></ul></div></div></div></li> 259 </ul></div> 260 261 </div></div></div></div> 262 263 </div></div><div class="header2_wrapper" aria-label="Web-Banner" role="banner"><div id="header2"> 264 265 <div class="banner"><div id="slickSlider225104233" class="box2061"> 266 <div class="slick-slide-content" data-onr="225466586"><img alt="Fahrrad-Bus_Bregenzerwald_c_Ian_Ehm_-_buero_balanka_Bregenzerwald_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1350925&mode=T&width=1920&height=450&cropping=CENTER&cts=1788192864" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1440px;max-height:450px;" /></div> 267 <div class="slick-slide-content" data-onr="225466587">
267<img alt="Radweg_Bregenzerwald_c_Benjamin_Schlachter_-_Bregenzerwald_Tourismus_1_" data-lazy="/system/web/GetImage.ashx?fileid=1350926&mode=T&width=1920&height=450&cropping=CENTER&cts=1788192868" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div> 268 <div class="slick-slide-content" data-onr="225466585"><img alt="Bus_am_Bödele_c_Lucas_Tiefenthaler_-_Bregenzerwald_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1350924&mode=T&width=1920&height=450&cropping=CENTER&cts=1788192857" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1619px;max-height:450px;" /></div> 269 <div class="slick-slide-content" data-onr="225466592"><img alt="Auf_dem_Weg_zur_Winterstaude_c_Michael_Meusburger_-_witus_eGen" data-lazy="/system/web/GetImage.ashx?fileid=1345559&mode=T&width=1920&height=450&cropping=CENTER&cts=1784642417" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div> 270 <div class="slick-slide-content" data-onr="225466593"><img alt="Alpe_Oberdamüls_c_Huber_Images_-_Damüls-Faschina_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1345561&mode=T&width=1920&height=450&cropping=CENTER&cts=1784642419" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div> 271 <div class="slick-slide-content" data-onr="225460946"><img alt="Bodenvorsä_in_Au_mit_Blick_auf_Zitterklapfen_c_Emanuel_Sutterlüty_-_Au-Schoppernau_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1345500&mode=T&width=1920&height=450&cropping=CENTER&cts=1784632432" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1620px;max-height:450px;" /></div> 272 <div class="slick-slide-content" data-onr="225460938"><img alt="Mädchen_in_der_Juppe_-_Bregenzerwälder_Tracht_c_Ian_Ehm_-_friendship.is" data-lazy="/system/web/GetImage.ashx?fileid=1345492&mode=T&width=1920&height=450&cropping=CENTER&cts=1784632409" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1440px;max-height:450px;" /></div> 273</div>
274<script type="text/javascript">$("#slickSlider225104233").slick({ 275 slidesToShow: 1, 276 slidesToScroll: 1, 277 autoplay: true, 278 autoplaySpeed: 4000, 279 speed: 1000, 280 dots: true, 281 rows: 0, 282 fade: false, 283});</script>
283</div> 284 285 </div></div><div class="columns_wrapper" role="main"><div id="columns"> 286 <div class="cols-wrapper"> 287 <div id="ctl00_ctl00_ctl00_col_ab_container" class="float-wrapper"> 288 289 <div id="col-b" class="sidecol-b"> 290 291 292 293 294 295 </div><div id="col-a"> 296 297 <div class="main-content"> 298 299 300 301 <div id="main-content-header"><div class="box2042 section section__breadcrumb"><div class="box2042 wrapper"><div class="breadcrumb"><ul class="item_liste"> 302 <li><a href="/system/web/default.aspx?menuonr=225047665" class="breadcrumb-current">Startseite</a></li> 303 </ul></div></div></div></div> 304 305 <div id="content"></div> 306 <form method="post" action="/system/web/default.aspx?sprache=1" id="aspnetForm"> 307 <div class="aspNetHidden"> 308 <input type="hidden" name="ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState" id="ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState" value="enennneennnnnnnennnnnnnnnennnnnnneennnnnnnnnnennnnnenennennnn" /> 309 <input type="hidden" name="ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode" id="ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode" value="" /> 310 <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" /> 311 <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /> 312 <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUINTY1NjQ1NjNkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBSJjdGwwMCRjdGwwMCRjdGwwMCRjcGhfaGVhZGVyJGN0bDAy5Wt2XrHguC/pO/Ilzrd18uXGpEs=" /> 313 </div> 314
315<script type="text/javascript"> 316//<![CDATA[ 317var theForm = document.forms['aspnetForm']; 318 if (!theForm) { 319 theForm = document.aspnetForm; 320} 321 function __doPostBack(eventTarget, eventArgument) { 322 if (!theForm.onsubmit || (theForm.onsubmit() != false)) { 323 theForm.__EVENTTARGET.value = eventTarget; 324 theForm.__EVENTARGUMENT.value = eventArgument; 325 theForm.submit(); 326 } 327} 328 //]]> 329</script>
329 330 331
332<script src="/system/WebResource.axd?d=4NbBhsyxI7mn5DiJieNvpkRb5PMUHyWFFYQ2RFfWIHy9e_8yCMnSJbJpxCkWluTC5seyOHuKvXhDDa32ZNrkrXXxB281&t=639245057389592256" type="text/javascript"></script>
332 333 334
335<script src="/system/WebResource.axd?d=M-Bz-Kz21qb4W7sjbD_RDJcAZpORT9hz630ncoDj-NTxQIw5qMQxkUI0oU2f7zxwJz6FzLLyuQeLgXUYoNh3iY8ZNCk1&t=639245057389592256" type="text/javascript"></script>
vendor: 2 bytes, line 335
335
336<script type="text/javascript"> 337//<![CDATA[ 338var ctl00_ctl00_ctl00_cph_header_ctl02_Data = null;//]]> 339</script>
339 340 341 342 343 344 345 346 347 348 349 350 351<div class="box2042 section section__news"><div class="box2042 wrapper"><div class="titel"><h1>Aktuelle Informationen</h1><span class="titel_seperator"></span></div><div class="news"><div class='newslist'><div class='newsrow'><div class='width99 odd kat_225391296 float_left'><p class="float_right"> 27.08.2026</p><a href="/Sperre_des_Achtalwegs_beim_Kraftwerk_Langenegg" title="Sperre des Achtalwegs beim Kraftwerk Langenegg"><img alt="Bauarbeiten Achtalweg" src="/system/web/GetImage.ashx?fileid=1350575&mode=T&width=640&height=360&cropping=CENTER&cts=1787856732" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Sperre_des_Achtalwegs_beim_Kraftwerk_Langenegg">Sperre des Achtalwegs beim Kraftwerk Langenegg</a></span></h2><p>Aufgrund von Leitungsbauarbeiten oberhalb des Kraftwerks Langenegg muss der Achtalweg in diesem Bereich...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even kat_225391296 float_left'><p class="float_right"> 22.09.2026</p><a href="/Care_Management_Bregenzerwald-Kleinwalsertal" title="Care Management Bregenzerwald-Kleinwalsertal"><img alt="Eine rote Karte mit weiÃem Text" src="/system/web/GetImage.ashx?fileid=1354734&mode=T&width=640&height=360&cropping=CENTER&cts=1790068857" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Care_Management_Bregenzerwald-Kleinwalsertal">Care Management Bregenzerwald-Kleinwalsertal</a></span></h2><p>Mit der neuen Care Management-Struktur wird die Betreuung und Pflege älterer Menschen in der Region gemeinsam...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 odd kat_225391296 float_left'><p class="float_right"> 29.09.2026</p><a href="/Strassensperre_L_21_Sulzberg_-_Fahl" title="StraÃensperre L 21 Sulzberg - Fahl"><img alt="ein Kegel auf einer Oberfläche" src="/system/web/GetImage.ashx?fileid=1356382&mode=T&width=640&height=360&cropping=CENTER&cts=1790692681" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Strassensperre_L_21_Sulzberg_-_Fahl">StraÃensperre L 21 Sulzberg - Fahl</a></span></h2><p>Aufgrund von Bauarbeiten kann die Linie 823 von Montag, 5. Oktober 2026, 8:30 Uhr, bis Mittwoch, 7. Oktober...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even kat_225391296 float_left'><p class="float_right"> 21.09.2026</p><a href="/Beratungsstelle_fuer_NS-Objekte_2" title="Beratungsstelle für NS-Objekte"><img alt="Eine Person, die alte Fotos hält" src="/system/web/GetImage.ashx?fileid=1354540&mode=T&width=640&height=360&cropping=CENTER&cts=1790000946" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Beratungsstelle_fuer_NS-Objekte_2">Beratungsstelle für NS-Objekte</a></span></h2><p>Im Rahmen der Ausstellung âBaustelle Erinnerung | ,Hitler entsorgenââ bietet das vorarlberg museum in...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 odd kat_225391296 float_left'><p class="float_right"> 21.07.2026</p><a href="/Nachtbus_Bregenzerwald" title="Nachtbus Bregenzerwald"><img alt="Eine Person und eine Person, die mit einem groÃen Stofftier für ein Foto posieren" src="/system/web/GetImage.ashx?fileid=1345668&mode=T&width=640&height=360&cropping=CENTER&cts=1784711639" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Nachtbus_Bregenzerwald">Nachtbus Bregenzerwald</a></span></h2><p>Die Nachtbusse 8N1 und 8N2 fahren in der Nacht von Samstag auf Sonntag, auÃer an Feiertagen. Die Linie...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even kat_225391296 float_left'><p class="float_right"> 21.04.2026</p><a href="/Fahrradbus_2026" title="Fahrradbus 2026"><img alt="Fahrradbus am Bahnhof Egg" src="/system/web/GetImage.ashx?fileid=1329784&mode=T&width=640&height=360&cropping=CENTER&cts=1776771372" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a href="/Fahrradbus_2026">Fahrradbus 2026</a></span></h2><p>Die Busse 8R1 und 8R2 fahren vom 14. Mai bis 04. Oktober 2026 jeweils Donnerstag bis Sonntag. Alle Fahrzeiten...</p></div></div><div class='clear'></div></div><p class="cls_weiterenews"><a href="/Aktuelles/Neuigkeiten">Weitere News...</a></p></div></div></div><div class="box2042 section section__karte"><div class="box2042 wrapper"><div class="titel"><h1>Bregenzerwaldkarte</h1></div><div class="karte"><!-- ============================================================ 352 Karte Bregenzerwald â Kulturkarte + Veranstaltungen 353 STARTSEITEN-VARIANTE (Basis: Version 41) 354 355 Fehlerbehebung: Das schwebende Menü wuchs beim Aufklappen
356 unbegrenzt nach unten (kein internes Scrollen), weil 357 #bwk-kartenbox keine eigene Höhe hatte â "max-height: 358 calc(100% - ...)" beim Menü konnte sich dadurch auf nichts 359 Festes beziehen. #bwk-kartenbox hat jetzt dieselbe feste Höhe 360 wie #bwk-karte (am Aussehen ändert sich dadurch nichts), das 361 Menü scrollt jetzt korrekt innerhalb der Kartenbox. 362 363 Unterschiede zur normalen Version: 364 ⢠Kein Filter-Feld über der Karte, keine Werkzeugzeile. Das 365 Menü (Gemeinden + Kategorien) liegt IMMER als schwebendes 366 Feld direkt über der Karte, auf-/zuklappbar über das 367 Ebenen-Icon oben links â genau wie sonst nur im Vollbild. 368 ⢠"Auswahl drucken" (CSV-Export) komplett entfernt. 369 ⢠Alle Kategorien und alle Gemeinden starten aktiv (nicht 370 abgewählt wie in der normalen Version). 371 372 Sonst identisch zu Version 40: Gemeinde-Filter mit echten 373 Gemeindegrenzen, Zeitraum-Dialog bei Veranstaltungen, Farben, 374 Ebenen-Reihenfolge nach uMap-Rang usw. â siehe dortiger 375 Ãnderungsverlauf. 376 377 378 Neu gegenüber Version 39: 379 ⢠Zeitraum-Dialog hat jetzt oben rechts ein X zum SchlieÃen 380 ohne zu übernehmen (wie Escape/Klick daneben). 381 ⢠"AuÃerhalb vom Bregenzerwald" hat keine eigene Grenze zum 382 Hinzoomen â die Karte zoomt bei dieser Auswahl jetzt grob 383 auf ganz Vorarlberg statt gar nichts zu tun. 384 ⢠Linien (Radwege usw.) stehen jetzt auch im CSV-Export, mit 385 dem ersten Stützpunkt der Linie als Koordinate. Das war 386 vermutlich auch der Grund, warum ganze Kategorien im Export 387 zu fehlen schienen: eine Ebene wie "Radweg" besteht komplett 388 aus Linien und hatte darum bisher schlicht null Zeilen. 389 390 391 Neu gegenüber Version 38 (drei Fehlerbehebungen): 392 ⢠Datumsfilter wirkungslos: die Von/Bis-Felder waren 393 deaktiviert, solange "Alle Termine anzeigen" angehakt war 394 (Startzustand) â ein deaktiviertes Feld lässt sich gar 395 nicht anklicken. Felder sind jetzt immer bedienbar; wird 396 ein Datum gewählt, hakt "Alle Termine anzeigen" automatisch 397 ab. Knopf heiÃt jetzt "Filter anwenden". 398 ⢠Dialog blieb im echten Vollbildmodus unsichtbar: er hing an 399 document.body, das der Browser im Vollbild aber gar nicht 400 mehr rendert (nur der Vollbild-Container selbst). Der 401 Dialog hängt jetzt an #bwk-kartenbox. 402 ⢠CSV-Export zeigte nur Veranstaltungen: layer.eachLayer() 403 geht bei den Kultur-Ebenen nicht in die verschachtelte 404 GeoJSON-Gruppe hinein. Neue Hilfsfunktion steigt jetzt in 405 verschachtelte Gruppen hinab. Der Export hat auÃerdem eine 406 neue Spalte "Kategorie" und sortiert zuerst danach, dann 407 erst alphabetisch nach Name. 408 409 410 Neu gegenüber Version 37: 411 ⢠Gemeinden starten wieder alle abgewählt (wie die 412 Kategorien). 413 ⢠Neuer Zeitraum-Dialog für Veranstaltungen: geht auf, 414 sobald "Veranstaltungen" angehakt wird. Von/Bis wählen 415 oder "Alle Termine anzeigen" ankreuzen â nur Termine im 416 gewählten Zeitraum erscheinen dann auf der Karte 417 (Abschnitt "Termin-Zeitraum-Dialog"). 418 ⢠Neuer Knopf "Auswahl drucken" unter dem Filter, über der 419 Karte: lädt eine CSV-Datei mit allen gerade sichtbaren 420 Einträgen herunter (Name, Beschreibung, Koordinaten), 421 alphabetisch sortiert â berücksichtigt automatisch 422 Kategorie-, Gemeinde- und Zeitraum-Filter, weil er direkt 423 von den tatsächlich gezeichneten Markern abliest. 424 ⢠Ãndert sich die Gemeinde-Auswahl, bewegt sich die Karte 425 jetzt automatisch dorthin (nutzt die schon geladenen 426 echten Gemeindegrenzen). 427 428 Neu gegenüber Version 36: 429 ⢠Im Vollbild verdeckte das Gemeinden/Kategorien-Menü das 430 Icon zum Ein-/Ausblenden der Ebenen (beide saÃen in der 431 gleichen Ecke). Das Menü setzt im Vollbild jetzt weiter 432 unten an (top 14px -> 64px, max-height entsprechend 433 angepasst), damit das Icon frei bleibt. 434 435 436 Neu gegenüber Version 35: 437 ⢠Die neue Rang-Sortierung ist jetzt gegen Fehler abgesichert: 438 schlägt sie fehl, fällt sie auf die Reihenfolge aus der Datei 439 zurück, statt (wie es einmal beobachtet wurde) die komplette 440 Kultur-Ansicht zu leeren. 441 442 443 Neu gegenüber Version 34: 444 ⢠Eine Ebene mit eigens gesetzter Farbe behält diese jetzt, 445 auch wenn ihre Gruppe eine Farbe hat â bisher überschrieb
446 die Gruppenfarbe das immer. Normalfall (keine eigene Farbe 447 gesetzt) bleibt: Ebene erbt die Farbe der Gruppe. 448 ⢠Reihenfolge von Gruppen und Ebenen im Filter richtet sich 449 jetzt nach uMaps eigenem Feld "rank" (die Reihenfolge, in 450 der sie in uMap selbst angeordnet sind), nicht mehr nach 451 der Reihenfolge im Datei-Export. 452 453 Neu gegenüber Version 33: 454 ⢠Der Gemeinde-Filter wirkt jetzt auch auf Linien (Routen wie 455 Radwege). Eine Linie kann mehrere Gemeinden berühren â sie 456 bleibt sichtbar, sobald mindestens eine davon angehakt ist. 457 Flächen sind davon weiter nicht betroffen (kommen in den 458 Kulturdaten bisher nicht vor). 459 460 Neu gegenüber Version 32: 461 ⢠25. Eintrag im Gemeinde-Filter: "AuÃerhalb vom 462 Bregenzerwald". Jeder Punkt bekommt jetzt IMMER eine der 463 25 Gemeinden zugewiesen â auch wenn er in keiner der 24 464 echten Grenzen liegt und auch nicht per Text erkannt wird. 465 Damit gibt es keinen Sonderfall "immer sichtbar" mehr, der 466 den Filter wirkungslos gemacht hat. 467 ⢠Veranstaltungen erschienen unabhängig vom Gemeinde-Filter 468 immer: Ursache war ein alter Zwischenspeicher-Eintrag im 469 Browser (aus einer Version ohne Gemeinde-Feld je Punkt). 470 Der Zwischenspeicher-Schlüssel für Veranstaltungen wurde 471 darum angehoben (bwk-termine-v3) â erzwingt beim nächsten 472 Laden einmalig einen frischen Abruf. 473 ⢠Gemeinden starten jetzt wieder alle aktiv (wie zuvor in 474 Version 31), inklusive der neuen 25. Gemeinde. 475 ⢠Die Gemeindegrenzen kommen jetzt aus EINER einzigen 476 Overpass-Abfrage (statt 24 einzelnen Nominatim-Anfragen im 477 Sekundentakt) â der Filter ist dadurch in der Regel nach 478 wenigen statt nach ~30 Sekunden vollständig genau. 479 480 Neu gegenüber Version 31: 481 ⢠Gemeinde-Zuordnung läuft jetzt in erster Linie über die 482 echten Gemeindegrenzen (Polygone von OpenStreetMap), 483 einmalig geladen und im Browser zwischengespeichert, nicht 484 mehr nur über Texterkennung in Adresse oder Name. Die reine 485 Texterkennung bleibt als Rückfallebene, solange die Grenzen 486 noch laden. 487 488 Neu gegenüber Version 30: 489 ⢠Gemeinde-Filter (24 Regio-Gemeinden) oberhalb des 490 Kategorien-Filters. Beide Filter gelten gemeinsam (UND): 491 ein Punkt erscheint nur, wenn seine Kategorie UND seine 492 Gemeinde angehakt sind. 493 ⢠Jeder Punkt bekommt dafür eine Gemeinde zugewiesen â 494 bei Veranstaltungen aus der "Datenquelle" der Karte, bei 495 Kulturpunkten aus Adresse/Name (gleiche Texterkennung wie 496 schon bisher für die Ortssuche). Nicht zuordenbare Punkte 497 bleiben immer sichtbar, statt sie zu verstecken. 498 499 Neu gegenüber Version 29: 500 ⢠Die Seite "Aktuelles > Veranstaltungen" wurde umgebaut 501 (neue Adresse /Aktuelles/Veranstaltungen, Kartenansicht 502 statt Tabelle, Blättern per Formular statt über die URL). 503 Abschnitt 10 (Listenseiten) und die Gruppierung in 504 aktualisiere() wurden entsprechend neu geschrieben. 505 ⢠Koordinaten stehen jetzt oft schon direkt in der Liste 506 (data-lat/data-lon); Nominatim/Detailseite werden nur noch 507 als Rückfallebene gebraucht, wenn diese fehlen. 508 ⢠Nichts wird mehr fest verdrahtet (Formularfelder, das 509 Blätter-Ziel, die Feldnamen): der Code liest das Formular 510 und die Paginierung jedes Mal aus der gerade geladenen 511 Seite, damit spätere Ãnderungen an der Liste nicht gleich 512 wieder alles zerlegen. 513 514 Farben zentral ändern: der Block --bwk-⦠ganz oben im 515 Stylesheet. --bwk-akzent ist die Hausfarbe, 516 --bwk-spalte die Breite der Filterspalten. 517 518 Datei aktualisieren: 519 1. uMap -> Bearbeiten -> Erweiterte Aktionen -> 520 Daten herunterladen -> "Alle Daten" 521 2. Datei in der Medienverwaltung hochladen bzw. die 522 bestehende ersetzen 523 (wird .umap/.geojson abgelehnt: in .txt umbenennen) 524 3. Bleibt die fileid gleich, ist am Code nichts zu ändern. 525 Sonst unten KULTUR_FILEID anpassen. 526 ============================================================ --> 527 528<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" crossorigin="" />
529<script src="https://unpkg.com/[email protected]/dist/leaflet.js" crossorigin=""></script>
529 530 531<style> 532/* ============================================================ 533 Farben und Grundwerte 534 Auf allen drei Wurzeln gesetzt, weil die Karte im Vollbild 535 aus #bwk-wrap heraus an den Seitenkörper gehängt wird. 536 ============================================================ */ 537#bwk-wrap, #bwk-kartenbox, #bwk-menu{ 538 --bwk-tinte:#23241f; 539 --bwk-grau:#6f6a62; 540 --bwk-linie:#e4dfd5; 541 --bwk-linie-fein:#efebe3; 542 --bwk-flaeche:#faf8f4; 543 --bwk-akzent:#2f6b4f; 544 --bwk-akzent-tief:#255840; 545 --bwk-akzent-hell:rgba(47,107,79,.10); 546 --bwk-schatten:0 1px 3px rgba(35,36,31,.06); 547 --bwk-schatten-hoch:0 12px 34px rgba(35,36,31,.20); 548 /* Spaltenbreite von Gruppen und Kästchen im Filter */ 549 --bwk-spalte:230px; 550} 551 552#bwk-wrap{ 553 margin:26px 0; font-family:inherit; color:var(--bwk-tinte); 554 line-height:1.5; box-sizing:border-box; 555} 556#bwk-wrap *{box-sizing:border-box;} 557 558/* ============================================================ 559 Filter über der Karte 560 ============================================================ */ 561#bwk-menu{ 562 font-family:inherit; color:var(--bwk-tinte); line-height:1.5; 563 border:1px solid var(--bwk-linie); border-radius:16px; 564 background:linear-gradient(180deg, #ffffff 0%, var(--bwk-flaeche) 100%); 565 box-shadow:var(--bwk-schatten); 566 padding:16px 18px 18px; margin:0 0 16px; box-sizing:border-box; 567} 568#bwk-menu *{box-sizing:border-box;} 569 570#bwk-menu .bwk-kopfzeile{display:flex; align-items:center; gap:12px; 571 margin:0 0 4px; padding:0 0 13px; border-bottom:1px solid var(--bwk-linie-fein);} 572#bwk-menu .bwk-ueberschrift{margin:0; flex:1 1 auto; 573 font-size:19px; font-weight:700; line-height:1.25; letter-spacing:-.005em; 574 color:var(--bwk-akzent); text-transform:none;} 575 576#bwk-menu .bwk-alle{font:inherit; font-size:13px; color:var(--bwk-grau); 577 background:#fff; border:1px solid var(--bwk-linie); border-radius:10px; 578 padding:6px 12px; cursor:pointer; white-space:nowrap; text-decoration:none; 579 -webkit-appearance:none; appearance:none; 580 transition:color .15s ease-out, border-color .15s ease-out, box-shadow .15s ease-out;} 581#bwk-menu .bwk-alle:hover{color:var(--bwk-akzent); border-color:var(--bwk-akzent); 582 box-shadow:0 2px 8px rgba(35,36,31,.09);} 583#bwk-menu .bwk-alle:focus-visible{outline:2px solid var(--bwk-akzent); outline-offset:2px;} 584 585#bwk-menu .bwk-inhalt{display:flex; flex-wrap:wrap; gap:18px 26px; 586 align-items:flex-start; padding:15px 0 0;} 587 588/* feste Spaltenbreite: Gruppen und Kästchen stehen bündig */ 589#bwk-menu .bwk-gruppe{display:flex; flex-direction:column; gap:9px; 590 width:var(--bwk-spalte); flex:0 0 var(--bwk-spalte); min-width:0; max-width:100%;} 591 592/* Ãberschrift einer Kategorie: bricht um statt zu kürzen */ 593#bwk-menu .bwk-gruppen-kopf{display:flex; align-items:flex-start; gap:9px; 594 width:100%; padding:0 0 2px;} 595#bwk-menu .bwk-gruppen-kopf input[type="checkbox"]{margin-top:2px;} 596#bwk-menu .bwk-gruppen-kopf label{flex:1 1 auto; min-width:0; 597 font-size:12px; font-weight:700; letter-spacing:.09em; text-transform:uppercase; 598 color:var(--bwk-grau); cursor:pointer; 599 white-space:normal; overflow-wrap:break-word; word-break:break-word; hyphens:auto;} 600#bwk-menu .bwk-gruppen-kopf label:hover{color:var(--bwk-tinte);} 601 602/* Ebenen einer Kategorie stehen untereinander */ 603#bwk-menu .bwk-gruppen-liste{display:flex; flex-direction:column; 604 align-items:stretch; gap:7px; width:100%;} 605 606/* ---------- Gemeinde-Filter (Chips) ---------- */ 607#bwk-menu .bwk-gemeinden{margin:0 0 15px; padding:0 0 15px; 608 border-bottom:1px solid var(--bwk-linie-fein);} 609#bwk-menu .bwk-gemeinde-liste{display:flex; flex-wrap:wrap; gap:8px; padding:13px 0 0;} 610#bwk-menu .bwk-chip{position:relative; display:inline-flex; align-items:center; gap:6px; 611 padding:6px 12px; border-radius:999px; cursor:pointer; user-select:none; 612 background:#fff; border:1px solid var(--bwk-linie); 613 font-size:13px; font-weight:500; line-height:1.3; color:var(--bwk-tinte); 614 transition:border-color .15s ease-out, background-color .15s ease-out, 615 color .15s ease-out, box-shadow .15s ease-out, opacity .15s ease-out;} 616#bwk-menu .bwk-chip:hover{border-color:#cfc8bb; box-shadow:0 2px 8px rgba(35,36,31,.09);} 617#bwk-menu .bwk-chip:focus-within{outline:2px solid var(--bwk-akzent); outline-offset:2px;} 618#bwk-menu .bwk-chip.bwk-an{background:var(--bwk-akzent-hell); 619 border-color:var(--bwk-akzent); color:var(--bwk-akzent-tief);} 620#bwk-menu .bwk-chip.bwk-aus{opacity:.55; border-style:dashed;} 621#bwk-menu .bwk-chip-anzahl{font-size:11px; font-weight:700; color:var(--bwk-grau); 622 font-variant-numeric:tabular-nums; padding:0 5px; border-radius:6px; 623 background:rgba(35,36,31,.06);} 624#bwk-menu .bwk-chip.bwk-an .bwk-chip-anzahl{background:rgba(255,255,255,.65); 625 color:var(--bwk-akzent-tief);} 626#bwk-menu .bwk-chip-anzahl:empty{display:none;} 627 628/* ---------- Kästchen einer Ebene ---------- */ 629#bwk-menu .bwk-zeile{position:relative; display:flex; align-items:center; 630 gap:9px; padding:6px 13px 6px 8px; margin:0; cursor:pointer; 631 width:100%; min-width:0; 632 background:#fff; border:1px solid var(--bwk-linie); border-radius:10px; 633 box-shadow:0 1px 2px rgba(35,36,31,.05); font-size:14px; line-height:1.3; 634 transition:border-color .15s ease-out, background-color .15s ease-out, 635 box-shadow .15s ease-out, opacity .15s ease-out;} 636#bwk-menu .bwk-zeile:hover{border-color:#cfc8bb; box-shadow:0 3px 10px rgba(35,36,31,.11);} 637#bwk-menu .bwk-zeile.bwk-an{background:#fff; border-color:var(--bwk-linie);} 638#bwk-menu .bwk-zeile.bwk-aus{background:transparent; border-style:dashed; 639 border-color:var(--bwk-linie); box-shadow:none; opacity:.6;} 640#bwk-menu .bwk-zeile.bwk-aus .bwk-swatch{filter:grayscale(1);} 641#bwk-menu .bwk-zeile.bwk-aus .bwk-name{color:var(--bwk-grau);} 642#bwk-menu .bwk-zeile:focus-within{outline:2px solid var(--bwk-akzent); outline-offset:2px;} 643 644/* Name einer Ebene: bricht um statt zu kürzen */ 645#bwk-menu .bwk-name{flex:1 1 auto; min-width:0; font-weight:500; 646 white-space:normal; overflow-wrap:break-word; word-break:break-word; hyphens:auto;} 647#bwk-menu .bwk-anzahl{flex:0 0 auto; margin-left:auto; align-self:center; 648 font-size:11.5px; font-weight:700; 649 color:var(--bwk-grau); font-variant-numeric:tabular-nums; 650 padding:1px 7px; border-radius:6px; background:rgba(35,36,31,.06);} 651#bwk-menu .bwk-anzahl:empty{display:none;} 652 653/* Ankreuzfeld der Kästchen: unsichtbar, aber bedienbar */ 654#bwk-menu .bwk-haken{position:absolute !important; opacity:0 !important; 655 width:1px !important; height:1px !important; margin:0 !important; 656 padding:0 !important; pointer-events:none;} 657 658#bwk-menu input[type="checkbox"]{width:17px; height:17px; 659 accent-color:var(--bwk-akzent); cursor:pointer; margin:0; flex:0 0 auto;} 660#bwk-menu input[type="checkbox"]:focus-visible{outline:2px solid var(--bwk-akzent); 661 outline-offset:2px;} 662 663/* ---------- Auf- und Zuklappen ---------- */ 664#bwk-menu .bwk-auf{margin-left:auto; display:inline-flex; align-items:center; 665 justify-content:center; width:26px; height:26px; padding:0; flex:0 0 auto; 666 margin-top:-3px; 667 border:0; background:none; color:var(--bwk-grau); cursor:pointer; border-radius:8px; 668 -webkit-appearance:none; appearance:none;} 669#bwk-menu .bwk-auf:hover{background:rgba(35,36,31,.06); color:var(--bwk-tinte);} 670#bwk-menu .bwk-auf svg{display:block; transition:transform .15s ease-out;} 671#bwk-menu .bwk-gruppe.bwk-zugeklappt .bwk-gruppen-liste{display:none;} 672#bwk-menu .bwk-gruppe.bwk-zugeklappt .bwk-auf svg{transform:rotate(-90deg);} 673#bwk-menu .bwk-menu-zu{display:none; align-items:center; justify-content:center; 674 width:30px; height:30px; padding:0; flex:0 0 auto; cursor:pointer; 675 border:1px solid var(--bwk-linie); border-radius:10px; background:#fff; 676 color:var(--bwk-grau); font-size:17px; line-height:1; 677 -webkit-appearance:none; appearance:none;} 678#bwk-menu .bwk-menu-zu:hover{color:var(--bwk-tinte); border-color:var(--bwk-grau);} 679 680/* ---------- Farbtupfer im Filter ---------- */ 681.bwk-swatch{display:inline-flex !important; align-items:center; flex:0 0 auto; 682 align-self:center;} 683.bwk-punkt{display:inline-flex !important; align-items:center; justify-content:center; 684 width:22px !important; height:22px !important; flex:0 0 auto; 685 margin:0 !important; padding:0 !important; border:0 !important; 686 background:none !important; overflow:visible !important;} 687.bwk-punkt svg{display:block !important; width:22px !important; height:22px !important; 688 margin:0 !important; padding:0 !important; 689 max-width:none !important; max-height:none !important; 690 min-width:0 !important; min-height:0 !important;} 691 692/* ============================================================ 693 Marker im uMap-Stil
694 Tropfen, Piktogramm und Beschriftung gehören zum Marker. 695 Die !important-Regeln halten die CMS-Stile von den MaÃen fern. 696 ============================================================ */ 697.leaflet-marker-icon.bwk-pin-huelle{ 698 background:none !important; border:0 !important; 699 margin:0 !important; padding:0 !important; 700 width:32px !important; height:42px !important; overflow:visible !important;} 701.bwk-pin{position:relative !important; display:block !important; 702 width:32px !important; height:42px !important; 703 margin:0 !important; padding:0 !important; overflow:visible !important;} 704.bwk-pin svg.bwk-pin-form{display:block !important; 705 width:32px !important; height:42px !important; 706 margin:0 !important; padding:0 !important; 707 max-width:none !important; max-height:none !important; 708 min-width:0 !important; min-height:0 !important; 709 overflow:visible !important; 710 transform-origin:50% 100%; 711 transition:transform .12s ease-out; 712 filter:drop-shadow(0 1px 2px rgba(35,36,31,.35));} 713.bwk-pin:hover svg.bwk-pin-form{transform:scale(1.12);} 714 715/* Beschriftung: hängt fest unter der Nadelspitze */ 716.bwk-pin-name{position:absolute !important; left:50% !important; top:100% !important; 717 transform:translateX(-50%) !important; 718 padding:3px 8px !important; border-radius:4px !important; 719 background:#fff !important; border:1px solid #d9d5cd !important; 720 color:#23241f !important; font-family:inherit !important; 721 font-size:12px !important; font-weight:600 !important; line-height:1.35 !important; 722 white-space:nowrap !important; letter-spacing:0 !important; 723 box-shadow:0 2px 7px rgba(35,36,31,.20) !important; 724 opacity:0; visibility:hidden; pointer-events:none !important; 725 transition:opacity .12s ease-out; z-index:2;} 726.bwk-pin:hover .bwk-pin-name, .bwk-pin-name.bwk-immer{opacity:1; visibility:visible;} 727 728 /* Beschriftung der Linien beim Ãberfahren */ 729.leaflet-tooltip.bwk-linien-name{ 730 margin:0; padding:3px 9px; border:1px solid #d9d5cd; border-radius:5px; 731 background:#fff; color:#23241f; font-family:inherit; 732 font-size:12px; font-weight:600; line-height:1.35; 733 box-shadow:0 2px 8px rgba(35,36,31,.20); white-space:nowrap;} 734.leaflet-tooltip.bwk-linien-name::before{display:none !important;} 735 736/* ============================================================ 737 Popups 738 ============================================================ */ 739.leaflet-popup-content-wrapper{padding:0 !important; overflow:hidden; 740 border-radius:14px !important; box-shadow:var(--bwk-schatten-hoch) !important; 741 background:#fff;} 742.leaflet-popup-content{margin:0 !important; font-family:inherit; font-size:14px; 743 line-height:1.5; color:#23241f;} 744.leaflet-popup-tip{box-shadow:none;} 745.leaflet-popup-close-button{top:5px !important; right:6px !important; 746 width:22px !important; height:22px !important; font-size:18px !important; 747 line-height:20px !important; color:#a49d92 !important; border-radius:50%;} 748.leaflet-popup-close-button:hover{color:#23241f !important; 749 background:rgba(35,36,31,.06) !important;} 750/* Leaflet blendet bei zu hohem Inhalt diese Klasse ein und 751 fängt das Mausrad selbst ab â nur senkrecht scrollen. */ 752.leaflet-popup-scrolled{overflow-x:hidden !important; 753 border-top:0 !important; border-bottom:0 !important; 754 overscroll-behavior:contain;} 755 756.bwk-pop{min-width:190px; max-width:100%; overflow-wrap:anywhere;} 757/* feine Farbleiste als Zeichen der Kategorie */ 758.bwk-pop-balken{height:3px; background:var(--bwk-pop-farbe);} 759.bwk-pop-kopf{padding:11px 34px 0 16px;} 760.bwk-pop-titel{margin:0; font-size:16px; font-weight:700; line-height:1.3; 761 color:#23241f; letter-spacing:-.01em;} 762.bwk-pop-adresse{display:flex; align-items:flex-start; gap:6px; 763 margin:4px 0 0; font-size:12.5px; line-height:1.4; color:#6f6a62;} 764.bwk-pop-adresse svg{flex:0 0 auto; margin-top:2px; color:var(--bwk-pop-text); 765 opacity:.75;} 766/* auslaufende Haarlinie statt harter Kante */ 767.bwk-pop-trenner{height:1px; margin:10px 16px 0; border:0; 768 background:linear-gradient(90deg, 769 var(--bwk-pop-linie) 0%, rgba(35,36,31,.10) 45%, rgba(35,36,31,0) 100%);} 770.bwk-pop-koerper{padding:10px 16px 12px;} 771.bwk-pop-text{margin:0;} 772.bwk-pop-text a{color:var(--bwk-pop-text); font-weight:600; 773 text-decoration:underline; text-underline-offset:2px; 774 text-decoration-color:var(--bwk-pop-linie); overflow-wrap:anywhere;} 775.bwk-pop-text a:hover{text-decoration-color:currentColor;} 776 777.bwk-pop-marke{display:block; margin:0 0 7px; font-size:10.5px; font-weight:700; 778 letter-spacing:.11em; text-transform:uppercase; color:#a49d92;} 779.bwk-pop-koerper .bwk-pop-text + .bwk-pop-marke{margin-top:13px; padding-top:11px; 780 border-top:1px solid #f2eee7;} 781
782/* ---------- Terminliste ---------- */ 783.bwk-pop-liste{margin:0; padding:0; list-style:none;} 784.bwk-pop-liste li{display:flex; align-items:flex-start; gap:10px; 785 padding:9px 0; border-top:1px solid #f2eee7;} 786.bwk-pop-liste li:first-child{border-top:0; padding-top:1px;} 787.bwk-termin-icon{flex:0 0 auto; margin-top:2px; color:#b0a99e;} 788.bwk-termin-icon svg{display:block;} 789.bwk-termin-text{flex:1 1 auto; min-width:0;} 790.bwk-termin-datum{display:block; margin:0 0 3px; font-size:12px; font-weight:700; 791 line-height:1.35; color:#5f5a52; font-variant-numeric:tabular-nums;} 792.bwk-termin-zeit{font-weight:600; color:#948d83; white-space:nowrap;} 793.bwk-termin-titel{display:block; font-size:14px; line-height:1.4; 794 font-weight:600; color:#23241f; overflow-wrap:anywhere;} 795a.bwk-termin-titel{text-decoration:none;} 796a.bwk-termin-titel:hover{color:var(--bwk-pop-text); 797 text-decoration:underline; text-underline-offset:2px;} 798 799/* ============================================================ 800 Schaltflächen in der Karte 801 ============================================================ */ 802.leaflet-touch .leaflet-bar, .leaflet-bar{border:0 !important; 803 border-radius:11px !important; overflow:hidden; 804 box-shadow:0 2px 10px rgba(35,36,31,.18) !important;} 805.leaflet-bar a{background:#fff; color:var(--bwk-tinte); 806 border-bottom:1px solid var(--bwk-linie-fein) !important; 807 transition:background-color .15s ease-out, color .15s ease-out;} 808.leaflet-bar a:last-child{border-bottom:0 !important;} 809 810/* Zoom: grüner Grund, weiÃes Zeichen beim Ãberfahren */ 811.leaflet-control-zoom a{font-size:19px; font-weight:600; text-decoration:none !important;} 812.leaflet-control-zoom a:hover, .leaflet-control-zoom a:focus{ 813 background:var(--bwk-akzent) !important; color:#fff !important; 814 text-decoration:none !important;} 815 816.bwk-knopf a{display:flex !important; align-items:center; justify-content:center; 817 width:34px; height:34px;} 818.bwk-knopf a svg{display:block;} 819 820/* Vollbild: weià mit grünem Zeichen, beim Ãberfahren umgekehrt; 821 im Vollbild grün gefüllt, beim Ãberfahren wieder weià */ 822.bwk-vollbildknopf a{background:#fff !important; color:var(--bwk-akzent) !important;} 823.bwk-vollbildknopf a:hover{background:var(--bwk-akzent) !important; color:#fff !important;} 824.bwk-vollbildknopf.bwk-aktiv a{background:var(--bwk-akzent) !important; color:#fff !important;} 825.bwk-vollbildknopf.bwk-aktiv a:hover{background:#fff !important; 826 color:var(--bwk-akzent) !important;} 827 828.bwk-ebenenknopf{display:block !important;} 829.bwk-ebenenknopf a{background:#fff !important; color:var(--bwk-akzent) !important;} 830.bwk-ebenenknopf a:hover{background:var(--bwk-akzent) !important; color:#fff !important;} 831 832/* ============================================================ 833 Karte und Hinweiszeile 834 ============================================================ */ 835/* Feste Höhe hier ist der eigentliche Trick: ohne sie hat die 836 Kartenbox nur eine "automatische" Höhe (die sich aus dem Inhalt 837 ergibt), und dann kann "max-height: calc(100% - ...)" beim 838 schwebenden Menü nicht berechnet werden â das Menü würde beim 839 Aufklappen unbegrenzt nach unten wachsen statt intern zu 840 scrollen. Gleicher Wert wie #bwk-karte, damit sich am Aussehen 841 nichts ändert. */ 842#bwk-kartenbox{position:relative; height:clamp(460px, 72vh, 780px);} 843#bwk-karte{width:100%; height:clamp(460px, 72vh, 780px); 844 border:1px solid var(--bwk-linie); border-radius:16px; background:#e8e6e1; 845 position:relative; z-index:0; isolation:isolate; overflow:hidden;} 846#bwk-karte.bwk-zweifinger{touch-action:pan-y !important;} 847#bwk-hinweis{position:absolute; inset:0; margin:0; z-index:1000; 848 display:flex; align-items:center; justify-content:center; text-align:center; 849 padding:0 24px; border-radius:16px; 850 background:rgba(25,25,22,.5); color:#fff; font-size:16px; font-weight:600; 851 opacity:0; visibility:hidden; transition:opacity .18s ease-out; 852 pointer-events:none;} 853#bwk-hinweis.bwk-sichtbar{opacity:1; visibility:visible;} 854 855#bwk-status{margin:11px 2px 0; font-size:12.5px; font-weight:400; 856 line-height:1.5; color:var(--bwk-grau);} 857#bwk-status:empty{display:none;} 858 859/* ============================================================ 860 Termin-Zeitraum-Dialog (öffnet sich beim Aktivieren von 861 "Veranstaltungen"). Fest an document.body gehängt, damit er 862 in Vollbild und normaler Ansicht gleichermaÃen funktioniert. 863 ============================================================ */ 864#bwk-tf-hinter{position:fixed; inset:0; z-index:2147483647; 865 background:rgba(25,25,22,.55); 866 display:flex; align-items:center; justify-content:center; padding:20px;} 867#bwk-tf-hinter[hidden]{display:none;} 868.bwk-tf-box{position:relative; width:min(360px, 100%); background:#fff; 869 border-radius:16px; padding:22px 22px 18px; box-shadow:0 20px 50px rgba(35,36,31,.35); 870 font-family:inherit; color:var(--bwk-tinte);} 871.bwk-tf-schliessen{position:absolute; top:12px; right:12px; width:28px; height:28px; 872 display:flex; align-items:center; justify-content:center; padding:0; 873 border:0; background:none; border-radius:50%; cursor:pointer; 874 color:var(--bwk-grau); font-size:20px; line-height:1; 875 -webkit-appearance:none; appearance:none;} 876.bwk-tf-schliessen:hover{background:rgba(35,36,31,.06); color:var(--bwk-tinte);} 877.bwk-tf-titel{margin:0 26px 16px 0; font-size:17px; font-weight:700; 878 color:var(--bwk-akzent);} 879.bwk-tf-zeile{display:flex; gap:12px; margin:0 0 14px;} 880.bwk-tf-zeile label{flex:1 1 auto; display:flex; flex-direction:column; gap:5px; 881 font-size:12.5px; font-weight:600; color:var(--bwk-grau);} 882.bwk-tf-zeile input[type="date"]{font:inherit; font-size:14px; color:var(--bwk-tinte); 883 border:1px solid var(--bwk-linie); border-radius:8px; padding:7px 8px; 884 background:#fff;} 885.bwk-tf-zeile input[type="date"]:disabled{opacity:.5;} 886.bwk-tf-haken{display:flex; align-items:center; gap:8px; font-size:14px; 887 font-weight:500; margin:0 0 18px; cursor:pointer;} 888.bwk-tf-haken input{width:17px; height:17px; accent-color:var(--bwk-akzent);
889 cursor:pointer; margin:0;} 890.bwk-tf-knoepfe{display:flex; justify-content:flex-end;} 891.bwk-tf-anwenden{font:inherit; font-size:14px; font-weight:600; color:#fff; 892 background:var(--bwk-akzent); border:0; border-radius:10px; padding:9px 18px; 893 cursor:pointer; transition:background-color .15s ease-out;} 894.bwk-tf-anwenden:hover{background:var(--bwk-akzent-tief);} 895 896/* ============================================================ 897 Vollbild 898 ============================================================ */ 899html.bwk-vollbild-aktiv, html.bwk-vollbild-aktiv body{overflow:hidden !important;} 900#bwk-kartenbox.bwk-vollbild{ 901 position:fixed !important; left:0 !important; top:0 !important; 902 right:0 !important; bottom:0 !important; 903 width:100vw !important; height:100vh !important; height:100dvh !important; 904 margin:0 !important; padding:0 !important; z-index:2147483000; 905 background:#e8e6e1;} 906#bwk-kartenbox.bwk-vollbild #bwk-karte{ 907 width:100% !important; height:100% !important; 908 border:0 !important; border-radius:0 !important;} 909#bwk-kartenbox.bwk-vollbild #bwk-hinweis{border-radius:0;} 910/* Das Filtermenü liegt auf der Startseiten-Karte IMMER als 911 schwebendes Feld über der Karte (nicht nur im Vollbild) â über 912 das Ebenen-Icon auf- und zuklappbar. Dieselben Regeln, die sonst 913 nur für .bwk-vollbild gelten, gelten hier immer. */ 914#bwk-kartenbox #bwk-menu{ 915 position:absolute; z-index:100; left:14px; top:64px; 916 width:min(350px, calc(100vw - 28px)); max-height:calc(100% - 78px); 917 overflow:auto; -webkit-overflow-scrolling:touch; 918 margin:0; padding:14px; border-radius:16px; 919 background:rgba(255,255,255,.97); 920 box-shadow:0 10px 34px rgba(35,36,31,.30);} 921#bwk-kartenbox #bwk-menu .bwk-inhalt{flex-direction:column; gap:12px;} 922#bwk-kartenbox #bwk-menu .bwk-gruppe{ 923 width:100%; flex:0 0 auto; min-width:0; gap:9px; 924 border:1px solid var(--bwk-linie-fein); border-radius:12px; 925 background:var(--bwk-flaeche); padding:10px 12px 12px;} 926#bwk-kartenbox #bwk-menu .bwk-menu-zu{display:inline-flex;} 927#bwk-kartenbox #bwk-menu.bwk-zu{display:none;} 928 929@media (max-width:700px){ 930 #bwk-menu .bwk-gruppe{width:100%; flex:0 0 100%;} 931 #bwk-karte{height:440px;} 932 #bwk-kartenbox{height:440px;} 933} 934</style> 935 936<div id="bwk-wrap"> 937 <div id="bwk-kartenbox"> 938 <div id="bwk-menu" class="bwk-zu" aria-label="Kategorien"></div> 939 <div id="bwk-karte"></div> 940 <p id="bwk-hinweis" aria-hidden="true"></p> 941 </div> 942 <p id="bwk-status"></p> 943</div> 944
945<script> 946(function () { 947 "use strict"; 948 949 /* ========================================================= 950 1) KONFIGURATION 951 ========================================================= */ 952 953 var START = { lat: 47.4568, lng: 9.96, zoom: 12 }; 954 955 // Startseiten-Variante: zum Start alle Kategorien eingeschaltet 956 var START_ALLE_AUS = false; 957 958 // Alle Ebenen einer Gruppe in der Farbe der Gruppe zeichnen 959 var GRUPPENFARBE = true; 960 961 // Beschriftung dauerhaft anzeigen statt nur beim Ãberfahren 962 var BESCHRIFTUNG_IMMER = false; 963 964 // Abstand der Beschriftung unter der Nadelspitze (Pixel) 965 var BESCHRIFTUNG_ABSTAND = 5; 966 967 // Linien (Radwege): sichtbare Stärke, Stärke beim Ãberfahren 968 // und Breite des unsichtbaren Streifens zum Anklicken 969 var LINIEN_BREITE = 4; 970 var LINIEN_BREITE_HOVER = 7; 971 var KLICK_BREITE = 22; 972 973 // MaÃe der Popups 974 var POPUP_BREITE_MAX = 380; 975 var POPUP_BREITE_MIN = 230; 976 var POPUP_HOEHE_MAX = 360; // darüber scrollt Leaflet im Popup 977 978 // Ãberschrift des Filters 979 var FILTER_TITEL = "Kategorien"; 980 981 // Kleiner Hinweis unter der Karte 982 var TERMIN_HINWEIS = "Es kann einen Moment dauern, bis alle " + 983 "Veranstaltungstermine auf der Karte erscheinen."; 984 985 // Mausrad: "immer" | "strg" (nur mit Strg/â) | "klick" (nach Klick in die Karte) 986 var MAUSRAD = "immer"; 987 988 // Auf Touchgeräten die Karte nur mit zwei Fingern verschieben, 989 // damit ein Finger weiterhin die Seite scrollt 990 var ZWEI_FINGER_MOBIL = true; 991 992 // Vollbild-Schaltfläche anzeigen 993 var VOLLBILD_KNOPF = true; 994 995 // Gruppen im Vollbild zu Beginn zugeklappt zeigen 996 var VOLLBILD_GRUPPEN_ZU = false; 997 998 // ID der uMap-Datei in der Medienverwaltung. Leer lassen = 999 // keine Kulturebenen, nur Veranstaltungen. 1000 var KULTUR_FILEID = "1355173"; 1001 1002 // Adressmuster des RIS für Dokumente aus der Bibliothek 1003 var KULTUR_URL_MUSTER = "/system/web/GetDocument.ashx?fileid={id}"; 1004 1005 // Verhindert, dass der Browser eine alte Fassung der Datei anzeigt 1006 var DATEI_FRISCH_LADEN = true; 1007 1008 // Original-Piktogramm von uMap verwenden, sofern es erreichbar 1009 // ist. false = gar kein Zugriff auf umap.openstreetmap.de, 1010 // es erscheinen dann ausschlieÃlich die eingebauten Symbole. 1011 var PIKTOGRAMME_VON_UMAP = true; 1012 1013 // Diagnose in der Konsole: Ãbersicht der Ebenen und Bilanz, 1014 // welche Bildadressen erreichbar waren 1015 var SYMBOL_BERICHT = true; 1016 1017 // Ab dieser Helligkeit der Ebenenfarbe (0 = schwarz, 1 = weiÃ) 1018 // wird das Piktogramm schwarz statt weià gezeichnet 1019 var HELLE_FARBE_AB = 0.62; 1020 1021 // Server der Piktogramme; der erste wird nach Möglichkeit aus 1022 // der Datei übernommen. 1023 var UMAP_SERVER = "https://umap.openstreetmap.de"; 1024 var UMAP_ERSATZSERVER = [ 1025 "https://umap.openstreetmap.de", 1026 "https://umap.openstreetmap.fr" 1027 ]; 1028 1029 // Startseite der Veranstaltungsliste (öffentliche, "freundliche" Adresse). 1030 // Von dort liest der Code das Formular und die Paginierung jedes Mal 1031 // frisch aus â Feldnamen und Blätter-Ziel werden nicht fest verdrahtet. 1032 var VA_URL = "/Aktuelles/Veranstaltungen"; 1033 1034 // Sicherheitsobergrenze, damit ein kaputtes "nächste Seite"-Attribut 1035 // nie zu einer Endlosschleife führt. 1036 var VA_MAX_SEITEN = 20; 1037 1038 var DETAIL_PARALLEL = 4; 1039 1040 var CACHE_STUNDEN = 6; 1041 var ORT_TAGE = 90; 1042 var FEHLVERSUCH_TAGE = 7; 1043 1044 // Gemeindegrenzen ändern sich praktisch nie â ruhig lange im 1045 // Browser des Besuchers zwischenspeichern 1046 var GRENZEN_TAGE = 365; 1047 var NEUE_ORTE_PRO_MAL = 40; 1048 var PAUSE_ADRESSSUCHE = 1100; 1049 1050 var BEREICH = { latMin: 47.15, latMax: 47.80, lngMin: 9.55, lngMax: 10.45 }; 1051 var NUR_GENAUE_ORTE = true; 1052 1053 var GEMEINDEN = [ 1054 "Alberschwende", "Andelsbuch", "Au", "Bezau", "Bizau", "Buch", "Damüls", "Doren", 1055 "Egg", "Hittisau", "Krumbach", "Langen", "Langen bei Bregenz", "Langenegg", 1056 "Lindenberg", "Lingenau", "Mellau", "Reuthe", "Riefensberg", "Schnepfau", 1057 "Schoppernau", "Schröcken", "Schwarzenberg", "Sibratsgfäll", "Sulzberg", "Thal", 1058 "Warth" 1059 ]; 1060 1061 // Die 24 Mitgliedsgemeinden der Regio Bregenzerwald â Grundlage 1062 // des Gemeinde-Filters. Absichtlich eine eigene, kürzere Liste 1063 // als GEMEINDEN oben: die brauchen zusätzliche Ortsteile/Varianten 1064 // (z. B. "Thal", "Lindenberg") allein zum Erkennen in Adresstexten. 1065 var GEMEINDE_FILTER = [ 1066 "Alberschwende", "Andelsbuch", "Au", "Bezau", "Bizau", "Buch", "Damüls", "Doren", 1067 "Egg", "Hittisau", "Krumbach", "Langen bei Bregenz", "Langenegg", "Lingenau", 1068 "Mellau", "Reuthe", "Riefensberg", "Schnepfau", "Schoppernau", "Schröcken", 1069 "Schwarzenberg", "Sibratsgfäll", "Sulzberg", "Warth" 1070 ]; 1071 1072 // Ortsteile/Kurzformen, die keine eigene Gemeinde sind, sondern zu 1073 // einer der obigen 24 gehören (kleingeschrieben, wie erkenneGemeinde 1074 // sie liefert) 1075 var GEMEINDE_ALIAS = { 1076 "langen": "langen bei bregenz", 1077 "lindenberg": "langen bei bregenz", 1078 "thal": "sulzberg" 1079 }; 1080 1081 // Auffangbecken für Punkte, die zu keiner der 24 echten Gemeinden 1082 // gehören (weder nach Koordinate noch nach Text) â ein "25. Ort" 1083 // im Filter, statt sie einfach immer anzuzeigen 1084 var GEMEINDE_AUSSERHALB = "AuÃerhalb vom Bregenzerwald"; 1085 1086 // die Liste, die tatsächlich als Filter angezeigt wird (25 Chips). 1087 // GEMEINDE_FILTER selbst bleibt bei den 24 echten Gemeinden, weil 1088 // nur die eine eigene Grenze/einen Namen zum Zuordnen haben. 1089 var GEMEINDE_ANZEIGE = GEMEINDE_FILTER.concat([GEMEINDE_AUSSERHALB]); 1090 1091 var MONATE = ["Jän.", "Feb.", "März", "April", "Mai", "Juni", 1092 "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez."]; 1093 1094 var FARBEN = ["#c2410c", "#0e7490", "#15803d", "#7c3aed", "#b91c1c", "#a16207", "#0369a1"]; 1095 1096 // Zeitraum-Filter für Veranstaltungen. "alle" = kein Zeitraum 1097 // aktiv, alle Termine werden gezeigt. Wird über den Dialog 1098 // gesetzt, der beim Aktivieren von "Veranstaltungen" aufgeht. 1099 var TERMIN_FILTER = { von: "", bis: "", alle: true }; 1100 1101 /* ========================================================= 1102 2) EINGEBAUTE PIKTOGRAMME 1103 Inline-SVG im Koordinatenraum 24 x 24. Sie brauchen keine 1104 Netzverbindung und sind darum immer sichtbar. 1105 ========================================================= */ 1106 1107 var PIKTOGRAMME = { 1108 punkt: '<circle cx="12" cy="12" r="5" fill="currentColor" stroke="none"/>', 1109 museum: '<path d="M3 21h18M5.5 21V10M9.5 21V10M14.5 21V10M18.5 21V10M2.5 9.5 12 4l9.5 5.5"/>', 1110 fahrrad: '<circle cx="5.5" cy="16.5" r="3.6"/><circle cx="18.5" cy="16.5" r="3.6"/><path d="M5.5 16.5 10 7.5h4.5l4 9M8 7.5h4"/>', 1111 kiosk: '<path d="M4 9.5h16V20H4zM2.5 9.5 4.5 4.5h15l2 5M9.5 20v-6h5v6"/>', 1112 restaurant: '<path d="M6 3v6a2.5 2.5 0 0 0 5 0V3M8.5 9v12M17.5 3c-1.6 1.2-2.5 3.2-2.5 5.5 0 2 .9 3.5 2.5 3.5v9"/>', 1113 cafe: '<path d="M4.5 8h12v6a4.5 4.5 0 0 1-4.5 4.5H9A4.5 4.5 0 0 1 4.5 14zM16.5 9.5H18a2.75 2.75 0 0 1 0 5.5h-1.5M3.5 21h14M8 3v2M12 3v2"/>', 1114 hotel: '<path d="M3 20v-9M3 14h18v6M21 20v-5a3 3 0 0 0-3-3h-6v2"/><circle cx="7" cy="9.5" r="2"/>', 1115 buecherei: '<path d="M12 6.5C10.5 5 8 4.5 4 4.5V18c4 0 6.5.5 8 2 1.5-1.5 4-2 8-2V4.5c-4 0-6.5.5-8 2zM12 6.5V20"/>', 1116 buehne: '<path d="M9 17V4l11-2v13"/><circle cx="6" cy="17.5" r="3"/><circle cx="17" cy="15.5" r="3"/>', 1117 kirche: '<path d="M12 2.5v5M9.5 5h5M6 21v-9.5L12 7l6 4.5V21M10 21v-5h4v5"/>', 1118 info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v6M12 7.6v.6"/>', 1119 parken: '<rect x="3.5" y="3.5" width="17" height="17" rx="3.5"/><path d="M9.5 17.5V7h3.4a3.2 3.2 0 0 1 0 6.4H9.5"/>', 1120 aussicht: '<path d="M3 8.5h4L9 5.5h6l2 3h4V20H3z"/><circle cx="12" cy="13.5" r="3.4"/>', 1121 berg: '<path d="M2.5 19.5 9 8l4.5 7.5M11 19.5 16.5 10l5 9.5M2.5 19.5h19"/>', 1122 kalender: '<path d="M8 2.5v3M16 2.5v3M3.5 9.5h17M5 4.5h14a1.5 1.5 0 0 1 1.5 1.5v13a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V6A1.5 1.5 0 0 1 5 4.5z"/>', 1123 stern: '<path d="m12 3.5 2.7 5.6 6 .9-4.4 4.3 1.1 6.1-5.4-2.9-5.4 2.9 1.1-6.1L3.3 10l6-.9z"/>', 1124 handwerk: '<path d="M14.5 6.5a3.5 3.5 0 0 0 4.6 4.6L21 13l-8 8-2-2 2-2-6-6-2 2-2-2 8-8 1.9 1.9z"/>', 1125 haus: '<path d="M3.5 10.5 12 3.5l8.5 7M5.5 9.5V20h13V9.5M10 20v-6h4v6"/>', 1126 werkstatt: '<path d="M3 20.5V9l9-5.5 9 5.5v11.5M3 20.5h18M8 20.5V13h8v7.5"/>', 1127 wasser: '<path d="M12 3.5c3.5 4.4 5.5 7.4 5.5 10a5.5 5.5 0 0 1-11 0c0-2.6 2-5.6 5.5-10z"/>', 1128 schule: '<path d="M2.5 8.5 12 4l9.5 4.5L12 13z"/><path d="M6.5 10.5V16c0 1.5 2.5 3 5.5 3s5.5-1.5 5.5-3v-5.5M21.5 8.5V15"/>' 1129 }; 1130 1131 // Dateiname des uMap-Symbols -> eingebautes Symbol 1132 // (die Karte nutzt z. B. /static/pictograms/tourism/museum.svg) 1133 var PIKTOGRAMM_ALIASE = { 1134 "museum": "museum", "art-gallery": "museum", "gallery": "museum", "artwork": "museum", 1135 "monument": "museum", "castle": "museum", "attraction": "museum", "heritage": "museum", 1136 "historic": "museum", "archaeological": "museum", 1137 "bicycle": "fahrrad", "bike": "fahrrad", "cycling": "fahrrad", 1138 "bicycle-share": "fahrrad", "cyclist": "fahrrad", "velo": "fahrrad",
1139 "kiosk": "kiosk", "shop": "kiosk", "convenience": "kiosk", "supermarket": "kiosk", 1140 "marketplace": "kiosk", "bakery": "kiosk", "commercial": "kiosk", "grocery": "kiosk", 1141 "clothing-store": "kiosk", "butcher": "kiosk", "greengrocer": "kiosk", 1142 "restaurant": "restaurant", "fast-food": "restaurant", "food": "restaurant", 1143 "fastfood": "restaurant", "pizza": "restaurant", "eat": "restaurant", 1144 "cafe": "cafe", "coffee": "cafe", "bar": "cafe", "pub": "cafe", "beer": "cafe", 1145 "drink": "cafe", "teahouse": "cafe", "ice-cream": "cafe", 1146 "hotel": "hotel", "hostel": "hotel", "motel": "hotel", "lodging": "hotel", 1147 "guest-house": "hotel", "bed": "hotel", "campsite": "hotel", "camping": "hotel", 1148 "shelter": "hotel", "alpinehut": "hotel", "alpine-hut": "hotel", 1149 "library": "buecherei", "book": "buecherei", "books": "buecherei", 1150 "school": "schule", "college": "schule", "university": "schule", 1151 "kindergarten": "schule", "education": "schule", 1152 "theatre": "buehne", "theater": "buehne", "cinema": "buehne", "movie": "buehne", 1153 "music": "buehne", "concert": "buehne", "art": "buehne", "arts-centre": "buehne", 1154 "community-centre": "buehne", "dance": "buehne", 1155 "place-of-worship": "kirche", "church": "kirche", "chapel": "kirche", 1156 "religious-christian": "kirche", "cemetery": "kirche", "worship": "kirche", 1157 "information": "info", "tourist-information": "info", "town-hall": "info", 1158 "townhall": "info", "government": "info", "embassy": "info", "office": "info", 1159 "post": "info", "bank": "info", 1160 "parking": "parken", "car": "parken", "bus": "parken", "rail": "parken", 1161 "train": "parken", "airport": "parken", "fuel": "parken", "charging-station": "parken", 1162 "viewpoint": "aussicht", "camera": "aussicht", "photo": "aussicht", 1163 "telescope": "aussicht", "binoculars": "aussicht", 1164 "mountain": "berg", "peak": "berg", "hiking": "berg", "walking": "berg", 1165 "hike": "berg", "trail": "berg", "park": "berg", "picnic-site": "berg", 1166 "picnic": "berg", "tree": "berg", "forest": "berg", "garden": "berg", 1167 "nature-reserve": "berg", "cave": "berg", "skiing": "berg", 1168 "water": "wasser", "drinking-water": "wasser", "swimming": "wasser", 1169 "waterfall": "wasser", "fountain": "wasser", "lake": "wasser", "spring": "wasser", 1170 "calendar": "kalender", "event": "kalender", "clock": "kalender", "date": "kalender", 1171 "star": "stern", "marker": "stern", "circle": "stern", "square": "stern", 1172 "heart": "stern", "flag": "stern", 1173 "hammer": "handwerk", "tools": "handwerk", "wrench": "handwerk", 1174 "craft": "handwerk", "industrial": "handwerk", "factory": "werkstatt", 1175 "building": "haus", "home": "haus", "house": "haus", "village": "haus", 1176 "farm": "haus", "hut": "haus" 1177 }; 1178 1179 // Wörter im Ebenen- oder Punktnamen -> eingebautes Symbol 1180 // (greift, wenn die Datei keine oder eine unbekannte iconUrl hat) 1181 var WORT_SYMBOLE = [ 1182 ["museum", "museum"], ["ausstellung", "museum"], ["galerie", "museum"], 1183 ["sammlung", "museum"], ["denkmal", "museum"], ["schauraum", "museum"], 1184 ["büchere", "buecherei"], ["buechere", "buecherei"], ["bibliothek", "buecherei"], 1185 ["archiv", "buecherei"], ["lesen", "buecherei"], 1186 ["kirche", "kirche"], ["kapelle", "kirche"], ["pfarr", "kirche"], 1187 ["kloster", "kirche"], ["friedhof", "kirche"], 1188 ["gasthaus", "restaurant"], ["gasthof", "restaurant"], ["restaurant", "restaurant"], 1189 ["wirtshaus", "restaurant"], ["essen", "restaurant"], ["küche", "restaurant"], 1190 ["kulinarik", "restaurant"], ["jausen", "restaurant"], 1191 ["café", "cafe"], ["cafe", "cafe"], ["kaffee", "cafe"], ["bar", "cafe"], 1192 ["stube", "cafe"], ["konditorei", "cafe"], 1193 ["hotel", "hotel"], ["pension", "hotel"], ["gästehaus", "hotel"], 1194 ["ferienwohnung", "hotel"], ["übernacht", "hotel"], ["unterkunft", "hotel"], 1195 ["camping", "hotel"], 1196 ["fahrradbus", "fahrrad"], ["rad", "fahrrad"], ["bike", "fahrrad"], ["velo", "fahrrad"], 1197 ["haltestelle", "parken"], ["mobilität", "parken"], ["bahnhof", "parken"], 1198 ["bus", "parken"], ["parkplatz", "parken"], 1199 ["wander", "berg"], ["berg", "berg"], ["gipfel", "berg"], ["alpe", "berg"], 1200 ["alm", "berg"], ["natur", "berg"], ["route", "berg"], 1201 ["aussicht", "aussicht"], ["panorama", "aussicht"], ["blick", "aussicht"], 1202 ["bühne", "buehne"], ["buehne", "buehne"], ["theater", "buehne"], 1203 ["konzert", "buehne"], ["musik", "buehne"], ["kino", "buehne"], 1204 ["kultur", "buehne"], ["kunst", "buehne"], 1205 ["info", "info"], ["tourismus", "info"], ["gemeinde", "info"], 1206 ["rathaus", "info"], ["amt", "info"], 1207 ["gutschein", "kiosk"], ["laden", "kiosk"], ["shop", "kiosk"], 1208 ["geschäft", "kiosk"], ["markt", "kiosk"], ["hofladen", "kiosk"], 1209 ["bäcker", "kiosk"], ["metzger", "kiosk"], ["käse", "kiosk"], 1210 ["senner", "kiosk"], ["molkerei", "kiosk"], ["regional", "kiosk"], 1211 ["handwerk", "handwerk"], ["werkstatt", "werkstatt"], ["tischler", "handwerk"], 1212 ["schreiner", "handwerk"], ["zimmerei", "handwerk"], ["betrieb", "handwerk"], 1213 ["partner", "handwerk"], ["produktion", "werkstatt"], 1214 ["schule", "schule"], ["kindergarten", "schule"], ["bildung", "schule"], 1215 ["bad", "wasser"], ["see", "wasser"], ["brunnen", "wasser"], 1216 ["wasser", "wasser"], ["schwimm", "wasser"], 1217 ["veranstaltung", "kalender"], ["termin", "kalender"], ["kalender", "kalender"] 1218 ]; 1219 1220 var VA_BILD = { quellen: [], grund: "kalender" }; 1221 1222 var ORTE = { 1223 // "dorfbücherei@riefensberg": { name: "Dorfbücherei", adresse: "â¦", lat: 47.49, lng: 9.90 } 1224 }; 1225 1226 var EBENEN = [ 1227 { id: "va-kalender", name: "Veranstaltungen", farbe: "#1d4ed8", 1228 bild: VA_BILD, aktiv: !START_ALLE_AUS, punkte: [] } 1229 ]; 1230 1231 /* ========================================================= 1232 3) GRUNDLAGEN 1233 ========================================================= */ 1234 1235 var karte, layerVon = {}
1235, statusFeld, hinweisFeld, hinweisZeit, wartendeZeichnung = null; 1236 var CACHE_ORTE = "bwk-orte-v2", CACHE_TERMINE = "bwk-termine-v3"; 1237 var CACHE_GRENZEN = "bwk-grenzen-v2"; 1238 var letzteOffene = [], farbZaehler = 0, gruppenZaehler = 0; 1239 var menuInhalt, listeKultur, gruppeFest, kulturEbenen = [], kulturGruppen = []; 1240 var menuBox, menuHeimat, menuAnker, alleGruppen = [], alleKnopf = null; 1241 var kartenbox, kartenHeimat, kartenAnker; 1242 var vollbildAn = false, vollbildErsatz = false, vollbildWechsel = false; 1243 var vollbildKnopf = null; 1244 var SYMBOL_STAND = {}, bilanzZeit = null; 1245 var FERN_CACHE = {}, FERN_WARTEN = {}; 1246 var GEMEINDE_STAND = {}, GEMEINDE_ZEILEN = {}, gemeindeAlleKnopf = null; 1247 // Polygone der Gemeindegrenzen (von Nominatim geladen) und ob sie 1248 // schon (zumindest einmal) fertig geladen sind 1249 var GEMEINDE_GRENZEN = {}, GRENZEN_GELADEN = false; 1250 1251 function sicher(name, fn) { 1252 try { fn(); } catch (e) { console.warn("[Karte] " + name + ":", e); } 1253 } 1254 function txt(s) { return (s || "").replace(/\s+/g, " ").trim(); } 1255 function esc(s) { 1256 return String(s == null ? "" : s).replace(/&/g, "&").replace(/</g, "<") 1257 .replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); 1258 } 1259 function schlafe(ms) { return new Promise(function (r) { setTimeout(r, ms); }); } 1260 function findeEbene(id) { 1261 var t = null;
1261 EBENEN.forEach(function (e) { if (e.id === id) t = e; }); return t; 1262 } 1263 function imBereich(lat, lng) { 1264 return lat > BEREICH.latMin && lat < BEREICH.latMax && 1265 lng > BEREICH.lngMin && lng < BEREICH.lngMax; 1266 } 1267 function speicherLesen(k) { 1268 try { return JSON.parse(window.localStorage.getItem(k) || "null"); } catch (e) { return null; } 1269 } 1270 function speicherSchreiben(k, d) { 1271 try { window.localStorage.setItem(k, JSON.stringify(d)); } catch (e) { } 1272 } 1273 function normalisiere(s) { 1274 return txt(s).toLowerCase() 1275 .replace(/[.,;:()"'´`]/g, " ") 1276 .replace(/\b(im|in|am|an|der|die|das|dem|den|bei|zum|zur)\b/g, " ") 1277 .replace(/\s+/g, " ").trim(); 1278 } 1279 function erkenneGemeinde() { 1280 var quelle = (Array.prototype.join.call(arguments, " ") || "").toLowerCase(); 1281 var treffer = ""; 1282 GEMEINDEN.forEach(function (g) { 1283 var klein = g.toLowerCase(); 1284 var passt = klein.length <= 4 1285 ? new RegExp("(^|[^a-zäöüÃ])" + klein + "([^a-zäöüÃ]|$)").test(quelle) 1286 : quelle.indexOf(klein) !== -1; 1287 if (passt && klein.length > treffer.length) treffer = klein; 1288 }); 1289 return treffer; 1290 } 1291 function naechsteFarbe() { 1292 var f = FARBEN[farbZaehler % FARBEN.length]; 1293 farbZaehler++; 1294 return f; 1295 } 1296 1297 // Rohtreffer von erkenneGemeinde() (klein geschrieben) auf eine der 1298 // 24 Filter-Gemeinden abbilden â über GEMEINDE_ALIAS, sonst direkt 1299 function gemeindeKanonisch(rohTreffer) { 1300 if (!rohTreffer) return ""; 1301 var kanon = GEMEINDE_ALIAS[rohTreffer] || rohTreffer; 1302 var treffer = ""; 1303 GEMEINDE_FILTER.forEach(function (g) { 1304 if (g.toLowerCase() === kanon) treffer = g; 1305 }); 1306 return treffer; 1307 } 1308 1309 // exakter Name (z. B. die "Datenquelle" einer Veranstaltung) auf 1310 // eine der 24 Filter-Gemeinden abbilden 1311 function gemeindeVonName(name) { 1312 var n = txt(name).toLowerCase(); 1313 if (!n) return ""; 1314 var treffer = ""; 1315 GEMEINDE_FILTER.forEach(function (g) { 1316 if (g.toLowerCase() === n) treffer = g; 1317 }); 1318 return treffer; 1319 } 1320 1321 // ist die Gemeinde eines Punkts gerade angehakt? Nicht zuordenbare 1322 // Punkte (leerer Name) bleiben immer sichtbar. 1323 function gemeindeSichtbar(gemeinde) { 1324 if (!gemeinde) return true; 1325 return GEMEINDE_STAND[gemeinde] !== false; 1326 } 1327 1328 /* ---------- Gemeindegrenzen (Polygone von Nominatim) ---------- 1329 Genauer als die Texterkennung oben, vor allem bei Kulturpunkten, 1330 deren Adresse nicht immer den Gemeindenamen enthält. Wird einmal 1331 pro Browser geladen (24 Anfragen, ca. 1 pro Sekunde wie an 1332 anderer Stelle im Code schon üblich) und lange zwischengespeichert, 1333 da sich Gemeindegrenzen praktisch nie ändern. Bis die Grenzen da 1334 sind bzw. wenn ein Punkt in keiner Grenze liegt, greift weiter 1335 die Texterkennung von oben. ---------- */ 1336 1337 // Punkt-in-Polygon nach dem Ray-Casting-Verfahren. 1338 // ring: Liste von [lng, lat]-Paaren (GeoJSON-Reihenfolge) 1339 function punktInRing(lat, lng, ring) { 1340 var innen = false; 1341 for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { 1342 var xi = ring[i][0], yi = ring[i][1]; 1343 var xj = ring[j][0], yj = ring[j][1]; 1344 var schneidet = ((yi > lat) !== (yj > lat)) && 1345 (lng < (xj - xi) * (lat - yi) / (yj - yi) + xi); 1346 if (schneidet) innen = !innen; 1347 } 1348 return innen; 1349 } 1350 1351 // polygon: [ äuÃererRing, Loch1, Loch2, ⦠] (GeoJSON "Polygon") 1352 function punktInPolygon(lat, lng, polygon) { 1353 if (!polygon || !polygon.length) return false; 1354 if (!punktInRing(lat, lng, polygon[0])) return false; 1355 for (var i = 1; i < polygon.length; i++) { 1356 if (punktInRing(lat, lng, polygon[i])) return false; // liegt in einem Loch 1357 } 1358 return true; 1359 } 1360 1361 function punktInGeometrie(lat, lng, geometrie) { 1362 if (!geometrie) return false; 1363 if (geometrie.type === "Polygon") return punktInPolygon(lat, lng, geometrie.coordinates); 1364 if (geometrie.type === "MultiPolygon") { 1365 return geometrie.coordinates.some(function (poly) { return punktInPolygon(lat, lng, poly); }); 1366 } 1367 return false; 1368 } 1369 1370 // welche der 24 Filter-Gemeinden enthält diese Koordinate? 1371 function gemeindeAusKoordinaten(lat, lng) {
1372 if (typeof lat !== "number" || typeof lng !== "number") return ""; 1373 if (isNaN(lat) || isNaN(lng)) return ""; 1374 var treffer = ""; 1375 GEMEINDE_FILTER.forEach(function (g) { 1376 if (treffer) return; 1377 if (punktInGeometrie(lat, lng, GEMEINDE_GRENZEN[g])) treffer = g; 1378 }); 1379 return treffer; 1380 } 1381 1382 /* ---------- Grenzen laden: eine einzige Sammelabfrage ---------- 1383 Statt 24 einzelner Nominatim-Anfragen im Sekundentakt (dauerte 1384 rund 30 Sekunden) holt eine einzige Overpass-Abfrage alle 1385 Gemeindegrenzen im Kartenausschnitt auf einmal. Das ist in der 1386 Regel nach wenigen Sekunden fertig. Overpass liefert je Gemeinde 1387 eine Relation aus mehreren Wegstücken (Rollen "outer"/"inner"), 1388 die hier zu geschlossenen Ringen zusammengesetzt werden. ---------- */ 1389 1390 function koordinatenGleich(a, b) { 1391 return Math.abs(a[0] - b[0]) < 1e-7 && Math.abs(a[1] - b[1]) < 1e-7; 1392 } 1393 1394 // setzt die Wegstücke einer Rolle ("outer" bzw. "inner") zu 1395 // geschlossenen Ringen zusammen ([lng,lat]-Listen) 1396 function ringeAusMembers(members, rolle) { 1397 var segmente = (members || []) 1398 .filter(function (m) { return m.type === "way" && m.role === rolle && m.geometry && m.geometry.length > 1; }) 1399 .map(function (m) { return m.geometry.map(function (p) { return [p.lon, p.lat]; }); }); 1400 1401 var ringe = []; 1402 while (segmente.length) { 1403 var ring = segmente.shift().slice(); 1404 var versuche = segmente.length + 1; 1405 while (!koordinatenGleich(ring[0], ring[ring.length - 1]) && versuche-- > 0) { 1406 var ende = ring[ring.length - 1], gefunden = -1, dreh = false; 1407 for (var i = 0; i < segmente.length; i++) { 1408 if (koordinatenGleich(segmente[i][0], ende)) { gefunden = i; dreh = false; break; } 1409 if (koordinatenGleich(segmente[i][segmente[i].length - 1], ende)) { gefunden = i; dreh = true; break; } 1410 } 1411 if (gefunden === -1) break; // keine Fortsetzung gefunden â Ring bleibt wie er ist 1412 var teil = segmente.splice(gefunden, 1)[0]; 1413 if (dreh) teil = teil.slice().reverse(); 1414 ring = ring.concat(teil.slice(1)); 1415 } 1416 if (ring.length > 3) ringe.push(ring); 1417 } 1418 return ringe; 1419 } 1420 1421 // eine Overpass-Relation (eine Gemeinde) in GeoJSON-Geometrie 1422 // übersetzen 1423 function geometrieAusRelation(relation) { 1424 var aussen = ringeAusMembers(relation.members, "outer"); 1425 if (!aussen.length) return null; 1426 var innen = ringeAusMembers(relation.members, "inner"); 1427 if (aussen.length === 1) { 1428 return { type: "Polygon", coordinates: [aussen[0]].concat(innen) }; 1429 } 1430 // mehrere AuÃenringe (z. B. Exklaven): jeder für sich, Löcher 1431 // vereinfachend ignoriert (in der Praxis bei diesen Gemeinden 1432 // ohne Belang) 1433 return { type: "MultiPolygon", coordinates: aussen.map(function (r) { return [r]; }) }; 1434 } 1435 1436 // lädt (bzw. liest aus dem Zwischenspeicher) alle 24 Grenzen auf 1437 // einmal und zeichnet danach neu 1438 function ladeGemeindeGrenzen() { 1439 var cache = speicherLesen(CACHE_GRENZEN); 1440 var jetzt = Date.now(); 1441 if (cache && cache.zeit && cache.grenzen && 1442 (jetzt - cache.zeit) < GRENZEN_TAGE * 86400000) { 1443 GEMEINDE_GRENZEN = cache.grenzen;
1444 GRENZEN_GELADEN = true; 1445 neuZeichnenAlle(); 1446 console.info("[Karte] Gemeindegrenzen aus dem Zwischenspeicher: " + 1447 Object.keys(GEMEINDE_GRENZEN).length + " von " + GEMEINDE_FILTER.length); 1448 return; 1449 } 1450 1451 var abfrage = "[out:json][timeout:25];" + 1452 "relation[\"boundary\"=\"administrative\"][\"admin_level\"=\"8\"]" + 1453 "(" + BEREICH.latMin + "," + BEREICH.lngMin + "," + 1454 BEREICH.latMax + "," + BEREICH.lngMax + ");" + 1455 "out geom;"; 1456 var url = "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(abfrage); 1457 1458 fetch(url).then(function (r) { return r.json(); }).then(function (daten) { 1459 var gefunden = {}; 1460 (daten.elements || []).forEach(function (el) { 1461 if (el.type !== "relation" || !el.tags || !el.tags.name) return; 1462 var name = gemeindeVonName(el.tags.name); 1463 if (!name || gefunden[name]) return; 1464 var geo = geometrieAusRelation(el); 1465 if (geo) gefunden[name] = geo; 1466 }); 1467 GEMEINDE_GRENZEN = gefunden;
1468 GRENZEN_GELADEN = true; 1469 speicherSchreiben(CACHE_GRENZEN, { zeit: Date.now(), grenzen: gefunden }); 1470 neuZeichnenAlle(); 1471 console.info("[Karte] Gemeindegrenzen geladen: " + 1472 Object.keys(gefunden).length + " von " + GEMEINDE_FILTER.length); 1473 }).catch(function (fehler) { 1474 console.warn("[Karte] Gemeindegrenzen konnten nicht geladen werden â " + 1475 "Zuordnung läuft weiter über Textabgleich:", fehler); 1476 }); 1477 } 1478 1479 // Eigenschaft aus einem uMap-Objekt holen (Ebene oder einzelner Punkt). 1480 // _storage_options kommt in älteren Exporten vor. 1481 function opt(o, schluessel, ersatz) { 1482 if (!o) return ersatz; 1483 var quellen = [ 1484 o._umap_options, 1485 o._storage_options, 1486 o.properties && o.properties._umap_options, 1487 o.properties && o.properties._storage_options, 1488 o.properties, 1489 o 1490 ]; 1491 for (var i = 0; i < quellen.length; i++) { 1492 var q = quellen[i]; 1493 if (q && q[schluessel] !== undefined && q[schluessel] !== null && q[schluessel] !== "") { 1494 return q[schluessel]; 1495 } 1496 } 1497 return ersatz; 1498 } 1499 function nameAus(o, ersatz) { return opt(o, "name", ersatz); } 1500 function farbeAus(o, ersatz) { return opt(o, "color", ersatz); } 1501 1502 /* ========================================================= 1503 4) FARBEN 1504 ========================================================= */ 1505 1506 function farbTeile(farbe) { 1507 var s = txt(farbe).replace(/^#/, ""); 1508 if (s.length === 3) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2]; 1509 if (!/^[0-9a-f]{6}$/i.test(s)) return null; 1510 return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)]; 1511 } 1512 // Helligkeit einer Farbe (0 = schwarz, 1 = weiÃ) 1513 function helligkeit(farbe) { 1514 var t = farbTeile(farbe); 1515 if (!t) return 0.3; // Farbnamen: als dunkel behandeln 1516 return (0.2126 * t[0] + 0.7152 * t[1] + 0.0722 * t[2]) / 255; 1517 } 1518 // Piktogrammfarbe: weià auf dunklem, schwarz auf hellem Marker 1519 function symbolFarbe(farbe) { 1520 return helligkeit(farbe) > HELLE_FARBE_AB ? "#1a1a18" : "#ffffff"; 1521 } 1522 function istDunkelSymbol(farbe) { return symbolFarbe(farbe) !== "#ffffff"; } 1523 1524 function rgba(farbe, deckung) { 1525 var t = farbTeile(farbe); 1526 if (!t) return "rgba(47,107,79," + deckung + ")"; 1527 return "rgba(" + t[0] + "," + t[1] + "," + t[2] + "," + deckung + ")"; 1528 } 1529 function abdunkeln(farbe, anteil) { 1530 var t = farbTeile(farbe); 1531 if (!t) return "#2f6b4f"; 1532 return "#" + t.map(function (v) { 1533 var n = Math.round(v * anteil); 1534 return (n < 16 ? "0" : "") + n.toString(16); 1535 }).join(""); 1536 } 1537 // helle Ebenenfarben sind als Schriftfarbe unlesbar: abdunkeln 1538 function lesbar(farbe) { 1539 var h = helligkeit(farbe); 1540 if (h > 0.72) return abdunkeln(farbe, 0.42); 1541 if (h > 0.55) return abdunkeln(farbe, 0.62); 1542 return farbe || "#2f6b4f"; 1543 } 1544 1545 /* ========================================================= 1546 5) PIKTOGRAMME 1547 ========================================================= */ 1548 1549 function serverListe() { 1550 var raus = []; 1551 [UMAP_SERVER].concat(UMAP_ERSATZSERVER).forEach(function (s) { 1552 s = txt(s).replace(/\/+$/, "").replace(/^http:/i, "https:"); 1553 if (s && raus.indexOf(s) === -1) raus.push(s); 1554 }); 1555 return raus; 1556 } 1557 1558 // alle Adressen, unter denen das Original-Piktogramm versucht wird 1559 function bildAdressen(roh) { 1560 roh = txt(roh).replace(/["'()<>\\]/g, ""); 1561 if (!roh) return []; 1562 if (/^data:/i.test(roh)) return [roh]; 1563 1564 var liste = [], pfad = ""; 1565 1566 if (/^https?:\/\//i.test(roh) || roh.indexOf("//") === 0) { 1567 var voll = roh.indexOf("//") === 0 ? "https:" + roh : roh.replace(/^http:/i, "https:"); 1568 liste.push(voll); 1569 try { pfad = new URL(voll).pathname; } catch (e) { pfad = ""; } 1570 } else if (roh.indexOf("/") !== -1 || /\.[a-z0-9]{2,4}$/i.test(roh)) { 1571 pfad = roh.charAt(0) === "/" ? roh : "/" + roh; 1572 } 1573 1574 if (pfad) { 1575 serverListe().forEach(function (server) { 1576 var u = server + pfad; 1577 if (liste.indexOf(u) === -1) liste.push(u); 1578 }); 1579 } 1580 return liste; 1581 } 1582 1583 // "/static/pictograms/tourism/museum.svg" -> "museum" 1584 function symbolAusDatei(u) { 1585 var teil = txt(u).split("?")[0].split("#")[0].split("/").pop() || ""; 1586 var n = teil.replace(/\.[a-z0-9]+$/i, "").toLowerCase(); 1587 if (!n) return ""; 1588 1589 var stufen = [n, n.replace(/[-_]?\d+$/, ""), n.replace(/[-_](15|24|18|11)$/, "")]; 1590 for (var i = 0; i < stufen.length; i++) { 1591 var s = stufen[i]; 1592 if (!s) continue; 1593 if (PIKTOGRAMME[s]) return s; 1594 if (PIKTOGRAMM_ALIASE[s] && PIKTOGRAMME[PIKTOGRAMM_ALIASE[s]]) { 1595 return PIKTOGRAMM_ALIASE[s]; 1596 } 1597 } 1598 var ganz = txt(u).toLowerCase(), treffer = "";
1599 Object.keys(PIKTOGRAMM_ALIASE).forEach(function (k) { 1600 if (k.length > 3 && ganz.indexOf(k) !== -1 && k.length > treffer.length) treffer = k; 1601 }); 1602 return treffer ? PIKTOGRAMM_ALIASE[treffer] : ""; 1603 } 1604 1605 // Symbol aus einem Klartext (Ebenen- oder Punktname) ableiten 1606 function symbolAusText(text) { 1607 var s = txt(text).toLowerCase(); 1608 if (!s) return ""; 1609 var name = "", laenge = 0; 1610 WORT_SYMBOLE.forEach(function (paar) { 1611 if (s.indexOf(paar[0]) !== -1 && paar[0].length > laenge) { 1612 laenge = paar[0].length; name = paar[1]; 1613 } 1614 }); 1615 return PIKTOGRAMME[name] ? name : ""; 1616 } 1617 1618 // vereinheitlicht Bildangaben zu { quellen: [ ⦠], grund: "â¦", fern: "â¦" } 1619 function alsBild(x) { 1620 if (!x) return null; 1621 if (typeof x === "string") return { quellen: [x], grund: "punkt" }; 1622 if (Array.isArray(x)) return x.length ? { quellen: x.slice(), grund: "punkt" } : null; 1623 if (x.quellen || x.grund) { 1624 return { quellen: (x.quellen || []).slice(), grund: x.grund || "punkt", fern: x.fern }; 1625 } 1626 if (x.quelle) { 1627 var l = [x.quelle]; 1628 if (x.ersatz) l.push(x.ersatz); 1629 return { quellen: l, grund: "punkt" }; 1630 } 1631 return null; 1632 } 1633 1634 // liefert { quellen: [ ⦠], grund: "â¦" } 1635 function iconInfo(o, vorgabe, hinweisText) { 1636 var roh = txt(opt(o, "iconUrl", "")); 1637 1638 if (!roh) { 1639 var v = alsBild(vorgabe); 1640 if (v) return v; 1641 return { quellen: [], grund: symbolAusText(hinweisText) || "punkt" }; 1642 } 1643 1644 var grund = symbolAusDatei(roh) || symbolAusText(hinweisText) || "punkt"; 1645 var quellen; 1646 if (/^data:/i.test(roh)) quellen = [roh]; 1647 else quellen = PIKTOGRAMME_VON_UMAP ? bildAdressen(roh) : []; 1648 1649 return { quellen: quellen, grund: grund }; 1650 } 1651 1652 /* ---------- Original-Piktogramme vorab prüfen ---------- 1653 Erst wenn eine Adresse nachweislich geladen wurde, wandert 1654 sie in den Marker. So ist nie ein leerer Tropfen zu sehen. */ 1655 1656 function fernLaden(quellen, fertig) { 1657 var liste = (quellen || []).filter(Boolean); 1658 if (!liste.length) { fertig(""); return; } 1659 if (/^data:/i.test(liste[0])) { fertig(liste[0]); return; } 1660 if (!PIKTOGRAMME_VON_UMAP) { fertig(""); return; } 1661 1662 var schluessel = liste[0]; 1663 if (FERN_CACHE[schluessel] !== undefined) { fertig(FERN_CACHE[schluessel]); return; } 1664 if (FERN_WARTEN[schluessel]) { FERN_WARTEN[schluessel].push(fertig); return; } 1665 FERN_WARTEN[schluessel] = [fertig]; 1666 1667 var i = 0; 1668 function ende(adresse) { 1669 FERN_CACHE[schluessel] = adresse; 1670 (FERN_WARTEN[schluessel] || []).forEach(function (f) { 1671 try { f(adresse); } catch (e) { } 1672 }); 1673 delete FERN_WARTEN[schluessel]; 1674 } 1675 (function versuch() { 1676 if (i >= liste.length) { ende(""); return; } 1677 var adresse = liste[i++]; 1678 var pruef = new Image(); 1679 pruef.referrerPolicy = "no-referrer"; 1680 pruef.onload = function () { symbolNotiz(adresse, "geladen"); ende(adresse); }; 1681 pruef.onerror = function () { symbolNotiz(adresse, "fehlt"); versuch(); }; 1682 pruef.src = adresse; 1683 })(); 1684 } 1685 1686 // holt das Original nach und meldet sich, sobald es da ist 1687 function fernNachladen(bild, fertig) { 1688 if (!bild || bild.fern !== undefined) return; 1689 if (!bild.quellen || !bild.quellen.length) return; 1690 bild.fern = undefined; 1691 fernLaden(bild.quellen, function (adresse) { 1692 bild.fern = adresse || ""; 1693 if (adresse) { try { fertig(); } catch (e) { } } 1694 }); 1695 } 1696 1697 /* ---------- Diagnose der Bildadressen ---------- */ 1698 1699 function symbolNotiz(adresse, zustand) { 1700 if (!SYMBOL_BERICHT || !adresse || /^data:/i.test(adresse)) return; 1701 if (SYMBOL_STAND[adresse] === "geladen") return; 1702 var neu = !SYMBOL_STAND[adresse]; 1703 SYMBOL_STAND[adresse] = zustand; 1704 if (zustand === "fehlt" && neu) { 1705 console.warn("[Karte] Piktogramm nicht erreichbar: " + adresse); 1706 } 1707 clearTimeout(bilanzZeit); 1708 bilanzZeit = setTimeout(symbolBilanz, 2500); 1709 } 1710 1711 function symbolBilanz() { 1712 var adressen = Object.keys(SYMBOL_STAND); 1713 if (!adressen.length) return; 1714 var zeilen = adressen.map(function (a) { 1715 return { Adresse: a, Zustand: SYMBOL_STAND[a] }; 1716 });
1717 var ok = zeilen.filter(function (z) { return z.Zustand === "geladen"; }).length; 1718 console.info("[Karte] Piktogramme von uMap: " + ok + " von " + zeilen.length + 1719 " Adressen geladen" + (ok ? "." : 1720 " â es werden die eingebauten Symbole gezeigt.")); 1721 if (console.table) console.table(zeilen); else console.log(zeilen); 1722 } 1723 1724 /* ---------- Symbol als SVG-Bestandteil ---------- 1725 Wird in das SVG des Markers bzw. des Filterpunkts 1726 hineingezeichnet: kein eigenes Element, keine Positionierung 1727 über CSS, damit die CMS-Stile nichts verschieben können. */ 1728 1729 function symbolSvg(bild, farbe, groesse, x, y) { 1730 bild = alsBild(bild); 1731 var f = symbolFarbe(farbe); 1732 1733 if (bild && bild.fern) { 1734 return '<image href="' + esc(bild.fern) + '" x="' + x + '" y="' + y + '" ' + 1735 'width="' + groesse + '" height="' + groesse + '" ' + 1736 'preserveAspectRatio="xMidYMid meet" ' + 1737 'style="filter:' + (istDunkelSymbol(farbe) ? "brightness(0)" : "brightness(0) invert(1)") + 1738 '"/>'; 1739 } 1740 1741 var name = (bild && bild.grund) || "punkt"; 1742 var inhalt = PIKTOGRAMME[name] || PIKTOGRAMME.punkt; 1743 var skala = (groesse / 24).toFixed(4); 1744 return '<g transform="translate(' + x + ',' + y + ') scale(' + skala + ')" ' + 1745 'fill="none" stroke="' + f + '" stroke-width="2" stroke-linecap="round" ' + 1746 'stroke-linejoin="round" style="color:' + f + '">' + inhalt + "</g>"; 1747 } 1748 1749 // uMap-Beschreibungen: [[Adresse|Text]], nackte Adressen und 1750 // Zeilenumbrüche in sauberes HTML übersetzen 1751 function verweis(adresse, beschriftungText) { 1752 return '<a href="' + esc(adresse) + '" target="_blank" rel="noopener">' + 1753 esc(beschriftungText) + "</a>"; 1754 } 1755 function beschreibungHtml(roh) { 1756 if (!roh) return ""; 1757 var merker = [], s = String(roh); 1758 1759 s = s.replace(/\[\[([^\]|]+)\|([^\]]*)\]\]/g, function (_, a, b) { 1760 merker.push(verweis(txt(a), txt(b) || txt(a))); 1761 return "\u0000" + (merker.length - 1) + "\u0000"; 1762 }); 1763 s = s.replace(/\[\[([^\]]+)\]\]/g, function (_, a) { 1764 merker.push(verweis(txt(a), txt(a))); 1765 return "\u0000" + (merker.length - 1) + "\u0000"; 1766 }); 1767 1768 s = esc(s); 1769 s = s.replace(/https?:\/\/[^\s<]+/g, function (u) { 1770 return '<a href="' + u + '" target="_blank" rel="noopener">' + u + "</a>"; 1771 }); 1772 s = s.replace(/\u0000(\d+)\u0000/g, function (_, i) { return merker[+i]; }); 1773 return s.replace(/\r?\n/g, "<br>"); 1774 } 1775 1776 /* ========================================================= 1777 6) MARKER, FILTERPUNKT UND POPUP 1778 ========================================================= */ 1779 1780 var PIN_PFAD = "M16 40.6C16 40.6 30.4 25.6 30.4 15.9 30.4 8 24 1.6 16 1.6S1.6 8 1.6 15.9" + 1781 "C1.6 25.6 16 40.6 16 40.6Z"; 1782 1783 var PIN_KLEIN = '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" ' + 1784 'stroke="currentColor" stroke-width="2.2" stroke-linecap="round" ' + 1785 'stroke-linejoin="round" aria-hidden="true">' + 1786 '<path d="M12 21.5S19 14.6 19 9.8A7 7 0 0 0 5 9.8c0 4.8 7 11.7 7 11.7Z"/>' + 1787 '<circle cx="12" cy="9.8" r="2.4"/></svg>'; 1788 1789 var KALENDER_KLEIN = '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" ' + 1790 'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' + 1791 'stroke-linejoin="round" aria-hidden="true">' + 1792 '<path d="M8 2.5v3M16 2.5v3M3.5 9.5h17M5 4.5h14a1.5 1.5 0 0 1 1.5 1.5v13a1.5 1.5 0 0 1' + 1793 '-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V6A1.5 1.5 0 0 1 5 4.5z"/></svg>'; 1794 1795 // Tropfen, Piktogramm und Beschriftung in einem Element. 1796 // Die Beschriftung sitzt unter der Nadelspitze (top:100%). 1797 function pinHtml(farbe, bild, name, immer) { 1798 var f = esc(farbe || "#2f6b4f"); 1799 var html = '<span class="bwk-pin">' + 1800 '<svg class="bwk-pin-form" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 42" ' + 1801 'width="32" height="42" aria-hidden="true">' + 1802 '<path d="' + PIN_PFAD + '" fill="' + f + '" stroke="#ffffff" stroke-width="1.5"/>' + 1803 symbolSvg(bild, farbe, 16, 8, 8) + 1804 "</svg>"; 1805 1806 if (txt(name)) { 1807 html += '<span class="bwk-pin-name' + (immer ? " bwk-immer" : "") + 1808 '" style="margin-top:' + BESCHRIFTUNG_ABSTAND + 'px">' + esc(txt(name)) + "</span>"; 1809 } 1810 return html + "</span>"; 1811 } 1812 1813 function pinIcon(farbe, bild, name, immer) { 1814 return L.divIcon({ 1815 className: "bwk-pin-huelle", 1816 html: pinHtml(farbe, bild, name, immer), 1817 iconSize: [32, 42], 1818 iconAnchor: [16, 41], 1819 popupAnchor: [0, -37] 1820 });
1821 } 1822 1823 function punktMarker(latlng, farbe, bild, name, immer) { 1824 var marker = L.marker(latlng, { 1825 icon: pinIcon(farbe, bild, name, immer), 1826 riseOnHover: true, 1827 title: txt(name) || undefined 1828 }); 1829 // Original-Piktogramm nachreichen, sobald es geprüft ist 1830 fernNachladen(bild, function () { 1831 try { marker.setIcon(pinIcon(farbe, bild, name, immer)); } catch (e) { } 1832 }); 1833 return marker; 1834 } 1835 1836 function popupOptionen() { 1837 return { 1838 maxWidth: POPUP_BREITE_MAX, 1839 minWidth: POPUP_BREITE_MIN, 1840 maxHeight: POPUP_HOEHE_MAX, // Leaflet scrollt den Inhalt selbst 1841 autoPanPadding: [24, 24] 1842 }; 1843 } 1844 1845 function swatchHtml(farbe, bild) { 1846 var f = esc(farbe || "#2f6b4f"); 1847 return '<span class="bwk-punkt">' + 1848 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" ' + 1849 'width="22" height="22" aria-hidden="true">' + 1850 '<circle cx="11" cy="11" r="10.4" fill="' + f + '" ' + 1851 'stroke="rgba(0,0,0,.12)" stroke-width="1"/>' + 1852 symbolSvg(bild, farbe, 14, 4, 4) + 1853 "</svg></span>"; 1854 } 1855 1856 /* ---------- Termine ---------- */ 1857 1858 // "12.09.2026" -> "12. Sep. 2026" 1859 function kurzDatum(s) { 1860 var m = String(s).match(/(\d{1,2})\.(\d{1,2})\.(\d{2,4})/); 1861 if (!m) return txt(s); 1862 var monat = MONATE[parseInt(m[2], 10) - 1] || m[2] + "."; 1863 var jahr = m[3].length === 2 ? "20" + m[3] : m[3]; 1864 return m[1].replace(/^0/, "") + ". " + monat + " " + jahr; 1865 } 1866 1867 // ein Termin: Kalendersymbol, Datumszeile, Titel 1868 function terminHtml(t) { 1869 var roh = txt(t.datum); 1870 1871 // Datumsangaben einsammeln und Dubletten entfernen 1872 // (die Liste nennt Beginn und Ende oft mit demselben Tag) 1873 var funde = roh.match(/\d{1,2}\.\d{1,2}\.\d{2,4}/g) || []; 1874 var tage = []; 1875 funde.forEach(function (f) { 1876 var k = kurzDatum(f); 1877 if (tage.indexOf(k) === -1) tage.push(k); 1878 }); 1879 1880 // was ohne die Datumsangaben übrig bleibt 1881 var rest = roh; 1882 funde.forEach(function (f) { rest = rest.split(f).join(" "); }); 1883 rest = txt(rest).replace(/^[\s,;:.â-]+/, "").replace(/[\s,;:.â-]+$/, ""); 1884 1885 // Uhrzeiten sauber setzen 1886 var zeit = ""; 1887 var uhr = rest.match(/\d{1,2}[:.]\d{2}/g); 1888 if (uhr) { 1889 var liste = []; 1890 uhr.forEach(function (z) { 1891 var n = z.replace(".", ":"); 1892 if (liste.indexOf(n) === -1) liste.push(n); 1893 }); 1894 zeit = liste.slice(0, 2).join(" â ") + " Uhr"; 1895 } else if (rest) { 1896 zeit = rest; 1897 } 1898 1899 var datum = tage.length ? tage.slice(0, 2).join(" â ") : roh; 1900 1901 var html = '<li><span class="bwk-termin-icon">' + KALENDER_KLEIN + "</span>"; 1902 html += '<span class="bwk-termin-text">'; 1903 if (datum || zeit) { 1904 html += '<span class="bwk-termin-datum">' + esc(datum); 1905 if (zeit) html += ' <span class="bwk-termin-zeit">· ' + esc(zeit) + "</span>"; 1906 html += "</span>"; 1907 } 1908 html += t.link 1909 ? '<a class="bwk-termin-titel" href="' + esc(t.link) + '">' + esc(t.titel) + "</a>" 1910 : '<span class="bwk-termin-titel">' + esc(t.titel) + "</span>"; 1911 return html + "</span></li>"; 1912 } 1913 1914 function popupInhalt(p, farbe) { 1915 var f = farbe || "#2f6b4f"; 1916 var html = '<div class="bwk-pop" style="--bwk-pop-farbe:' + esc(f) + 1917 ";--bwk-pop-text:" + esc(lesbar(f)) + 1918 ";--bwk-pop-linie:" + rgba(f, .45) + 1919 ";--bwk-pop-hell:" + rgba(f, .12) + '">'; 1920 1921 // Kopf: Titel, darunter die Adresse 1922 html += '<div class="bwk-pop-balken"></div>'; 1923 html += '<div class="bwk-pop-kopf"><p class="bwk-pop-titel">' + esc(p.name) + "</p>"; 1924 if (p.adresse) { 1925 html += '<p class="bwk-pop-adresse">' + PIN_KLEIN + "<span>" + esc(p.adresse) + "</span></p>"; 1926 } 1927 html += "</div>"; 1928 1929 // Körper: Beschreibung und darunter alle Termine 1930 var koerper = ""; 1931 if (p.info) koerper += '<div class="bwk-pop-text">' + beschreibungHtml(p.info) + "</div>"; 1932 1933 if (p.termine && p.termine.length) { 1934 koerper += '<span class="bwk-pop-marke">' + 1935 (p.termine.length === 1 ? "Termin" : p.termine.length + " Termine") + "</span>"; 1936 koerper += '<ul class="bwk-pop-liste">'; 1937 p.termine.forEach(function (t) { koerper += terminHtml(t); }); 1938 koerper += "</ul>"; 1939 } 1940 1941 if (koerper) { 1942 html += '<div class="bwk-pop-trenner"></div>'; 1943 html += '<div class="bwk-pop-koerper">' + koerper + "</div>"; 1944 } else { 1945 html += '<div style="height:12px"></div>'; 1946 } 1947 return html + "</div>"; 1948 } 1949 1950 /* ========================================================= 1951 7) KARTE UND BEDIENUNG 1952 ========================================================= */ 1953 1954 function hinweis(text) { 1955 if (!hinweisFeld || !text) return;
1956 hinweisFeld.textContent = text; 1957 hinweisFeld.classList.add("bwk-sichtbar"); 1958 clearTimeout(hinweisZeit); 1959 hinweisZeit = setTimeout(function () { 1960 hinweisFeld.classList.remove("bwk-sichtbar"); 1961 }, 1800); 1962 } 1963 function hinweisWeg() { 1964 if (!hinweisFeld) return; 1965 clearTimeout(hinweisZeit); 1966 hinweisFeld.classList.remove("bwk-sichtbar"); 1967 } 1968 1969 function bedienung(box) { 1970 // ----- Mausrad ----- 1971 if (MAUSRAD === "strg") { 1972 karte.scrollWheelZoom.disable(); 1973 var mitTaste = function (e) { 1974 if (e.ctrlKey || e.metaKey) karte.scrollWheelZoom.enable(); 1975 }; 1976 var ohneTaste = function () { if (!vollbildAn) karte.scrollWheelZoom.disable(); }; 1977 document.addEventListener("keydown", mitTaste); 1978 document.addEventListener("keyup", ohneTaste); 1979 window.addEventListener("blur", ohneTaste); 1980 box.addEventListener("wheel", function (e) { 1981 if (!vollbildAn && !e.ctrlKey && !e.metaKey) hinweis("Zum Zoomen Strg + Mausrad benutzen"); 1982 }, { passive: true }); 1983 1984 } else if (MAUSRAD === "klick") { 1985 karte.scrollWheelZoom.disable(); 1986 karte.on("click", function () { karte.scrollWheelZoom.enable(); hinweisWeg(); }); 1987 karte.on("mouseout", function () { if (!vollbildAn) karte.scrollWheelZoom.disable(); }); 1988 box.addEventListener("wheel", function () { 1989 if (!karte.scrollWheelZoom.enabled()) hinweis("Zum Zoomen in die Karte klicken"); 1990 }, { passive: true }); 1991 } 1992 // "immer": bereits beim Anlegen der Karte eingeschaltet 1993 1994 // ----- Touchgeräte: zwei Finger zum Verschieben ----- 1995 if (ZWEI_FINGER_MOBIL && L.Browser.touch && L.Browser.mobile) { 1996 box.classList.add("bwk-zweifinger"); 1997 karte.dragging.disable(); 1998 1999 box.addEventListener("touchstart", function (e) { 2000 if (vollbildAn) return; 2001 if (e.touches.length > 1) { karte.dragging.enable(); hinweisWeg(); } 2002 }, { passive: true }); 2003 2004 box.addEventListener("touchmove", function (e) { 2005 if (vollbildAn) return; 2006 if (e.touches.length === 1 && !karte.dragging.enabled()) { 2007 hinweis("Zum Verschieben zwei Finger benutzen"); 2008 } 2009 }, { passive: true }); 2010 2011 box.addEventListener("touchend", function (e) { 2012 if (vollbildAn) return; 2013 if (!e.touches.length) karte.dragging.disable(); 2014 }, { passive: true }); 2015 } 2016 } 2017 2018 /* ---------- Schaltflächen in der Karte ---------- */ 2019 2020 function knopfControl(position, klasse, titel, inhalt, aktion) { 2021 var Knopf = L.Control.extend({ 2022 options: { position: position }, 2023 onAdd: function () { 2024 var box = L.DomUtil.create("div", "leaflet-bar bwk-knopf " + klasse); 2025 var a = L.DomUtil.create("a", "", box); 2026 a.href = "#"; 2027 a.title = titel; 2028 a.setAttribute("role", "button"); 2029 a.setAttribute("aria-label", titel);
2030 a.innerHTML = inhalt; 2031 this._knopf = a; 2032 L.DomEvent.disableClickPropagation(box); 2033 L.DomEvent.on(a, "click", function (e) { 2034 L.DomEvent.preventDefault(e); 2035 L.DomEvent.stopPropagation(e); 2036 aktion(a); 2037 }); 2038 return box; 2039 } 2040 }); 2041 return new Knopf(); 2042 } 2043 2044 function svgKnopf(pfade) { 2045 return '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" ' + 2046 'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' + 2047 'stroke-linejoin="round" aria-hidden="true">' + pfade + "</svg>"; 2048 } 2049 var SVG_AUFZIEHEN = svgKnopf('<path d="M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5"/>'); 2050 var SVG_ZUZIEHEN = svgKnopf('<path d="M8 3v5H3M16 3v5h5M16 21v-5h5M8 21v-5H3"/>'); 2051 var SVG_EBENEN = svgKnopf('<path d="m12 3 9 5-9 5-9-5 9-5Z"/><path d="m3 13 9 5 9-5"/>'); 2052 function pfeilSvg() { 2053 return '<svg viewBox="0 0 20 20" width="16" height="16" fill="none" ' + 2054 'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' + 2055 'stroke-linejoin="round" aria-hidden="true"><path d="M5 7.5 10 12.5 15 7.5"/></svg>'; 2056 } 2057 2058 /* ---------- Vollbild ---------- */ 2059 2060 function vollbildAnfordern(el) { 2061 var f = el.requestFullscreen || el.webkitRequestFullscreen || 2062 el.msRequestFullscreen || el.mozRequestFullScreen; 2063 if (!f) return Promise.reject(new Error("kein Vollbild")); 2064 try { 2065 var p = f.call(el); 2066 return (p && p.then) ? p : Promise.resolve(); 2067 } catch (e) { return Promise.reject(e); } 2068 } 2069 function vollbildBeenden() { 2070 var f = document.exitFullscreen || document.webkitExitFullscreen || 2071 document.msExitFullscreen || document.mozCancelFullScreen; 2072 if (!f) return; 2073 try { f.call(document); } catch (e) { } 2074 } 2075 function nativVollbild() { 2076 var e = document.fullscreenElement || document.webkitFullscreenElement || 2077 document.msFullscreenElement || document.mozFullScreenElement; 2078 return !!e && (e === kartenbox || (kartenbox && kartenbox.contains(e))); 2079 } 2080 2081 function knopfStand() { 2082 if (!vollbildKnopf) return; 2083 vollbildKnopf.innerHTML = vollbildAn ? SVG_ZUZIEHEN : SVG_AUFZIEHEN; 2084 var titel = vollbildAn ? "Vollbild beenden" : "Vollbild"; 2085 vollbildKnopf.title = titel; 2086 vollbildKnopf.setAttribute("aria-label", titel); 2087 var box = vollbildKnopf.parentNode; 2088 if (box && box.classList) box.classList.toggle("bwk-aktiv", vollbildAn); 2089 } 2090 2091 function groesseAuffrischen() { 2092 [0, 80, 300, 700].forEach(function (ms) { 2093 setTimeout(function () { if (karte) karte.invalidateSize(); }, ms); 2094 }); 2095 } 2096 2097 function vollbildEin() { 2098 if (vollbildAn || !kartenbox) return; 2099 vollbildWechsel = true; 2100 vollbildAn = true; 2101 vollbildErsatz = false; 2102 2103 // Karte aus dem CMS-Gerüst lösen: transform/overflow der 2104 // Elternelemente würden position:fixed sonst brechen 2105 kartenHeimat = kartenbox.parentNode; 2106 kartenAnker = kartenbox.nextSibling; 2107 document.body.appendChild(kartenbox); 2108 document.documentElement.classList.add("bwk-vollbild-aktiv"); 2109 kartenbox.classList.add("bwk-vollbild"); 2110 2111 if (menuBox) { 2112 menuBox.classList.remove("bwk-zu"); 2113 kartenbox.insertBefore(menuBox, kartenbox.firstChild); 2114 if (VOLLBILD_GRUPPEN_ZU) alleGruppen.forEach(function (gr) { gruppeKlappen(gr, true); }); 2115 } 2116 2117 if (karte) { 2118 karte.scrollWheelZoom.enable(); 2119 karte.dragging.enable(); 2120 } 2121 var kartenFeld = document.getElementById("bwk-karte"); 2122 if (kartenFeld) kartenFeld.classList.remove("bwk-zweifinger"); 2123 2124 vollbildAnfordern(kartenbox).catch(function () { vollbildErsatz = true; }); 2125 2126 knopfStand(); 2127 groesseAuffrischen(); 2128 setTimeout(function () { vollbildWechsel = false; }, 300); 2129 } 2130 2131 function vollbildAus() { 2132 if (!vollbildAn || !kartenbox) return; 2133 vollbildWechsel = true; 2134 vollbildAn = false; 2135 2136 if (nativVollbild()) vollbildBeenden(); 2137 vollbildErsatz = false; 2138 2139 if (menuBox && menuHeimat) menuHeimat.insertBefore(menuBox, menuAnker); 2140 kartenbox.classList.remove("bwk-vollbild"); 2141 document.documentElement.classList.remove("bwk-vollbild-aktiv"); 2142 if (kartenHeimat) kartenHeimat.insertBefore(kartenbox, kartenAnker); 2143 2144 if (karte) { 2145 if (MAUSRAD !== "immer") karte.scrollWheelZoom.disable(); 2146 if (ZWEI_FINGER_MOBIL && L.Browser.touch && L.Browser.mobile) { 2147 karte.dragging.disable(); 2148 var kartenFeld = document.getElementById("bwk-karte"); 2149 if (kartenFeld) kartenFeld.classList.add("bwk-zweifinger"); 2150 } 2151 } 2152 2153 knopfStand();
2154 groesseAuffrischen(); 2155 setTimeout(function () { vollbildWechsel = false; }, 300); 2156 } 2157 2158 function vollbildSchalten() { 2159 if (vollbildAn) vollbildAus(); else vollbildEin(); 2160 } 2161 2162 function vollbildBeobachten() { 2163 var pruefe = function () { 2164 if (vollbildWechsel) return; 2165 if (vollbildAn && !vollbildErsatz && !nativVollbild()) vollbildAus(); 2166 }; 2167 ["fullscreenchange", "webkitfullscreenchange", "msfullscreenchange", 2168 "mozfullscreenchange"].forEach(function (n) { 2169 document.addEventListener(n, pruefe); 2170 }); 2171 document.addEventListener("keydown", function (e) { 2172 if (!vollbildAn) return; 2173 if (e.key === "Escape" || e.key === "Esc") { 2174 if (!nativVollbild()) { e.preventDefault(); vollbildAus(); } 2175 } 2176 }); 2177 } 2178 2179 /* ---------- Start ---------- */ 2180 2181 function start() { 2182 if (typeof L === "undefined") { setTimeout(start, 100); return; } 2183 if (karte) return; 2184 2185 statusFeld = document.getElementById("bwk-status"); 2186 hinweisFeld = document.getElementById("bwk-hinweis"); 2187 kartenbox = document.getElementById("bwk-kartenbox"); 2188 var box = document.getElementById("bwk-karte"); 2189 2190 if (statusFeld) statusFeld.textContent = TERMIN_HINWEIS; 2191 2192 karte = L.map("bwk-karte", { 2193 scrollWheelZoom: MAUSRAD === "immer", 2194 zoomControl: false 2195 }).setView([START.lat, START.lng], START.zoom); 2196 2197 L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { 2198 maxZoom: 19, 2199 attribution: '© <a class="extlink" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>' 2200 }).addTo(karte); 2201 2202 L.control.zoom({ position: "topright", zoomInTitle: "GröÃer", zoomOutTitle: "Kleiner" }) 2203 .addTo(karte); 2204 2205 sicher("Vollbild", function () { 2206 if (!VOLLBILD_KNOPF) return; 2207 var c = knopfControl("topright", "bwk-vollbildknopf", "Vollbild", 2208 SVG_AUFZIEHEN, function (a) { vollbildKnopf = a; vollbildSchalten(); }); 2209 c.addTo(karte); 2210 vollbildKnopf = c._knopf; 2211 knopfStand(); 2212 2213 knopfControl("topleft", "bwk-ebenenknopf", FILTER_TITEL + " ein- oder ausblenden", 2214 SVG_EBENEN, function () { 2215 if (menuBox) menuBox.classList.toggle("bwk-zu"); 2216 }).addTo(karte); 2217 2218 vollbildBeobachten(); 2219 }); 2220 2221 sicher("Bedienung", function () { bedienung(box); }); 2222 2223 karte.on("popupclose", function () { 2224 if (wartendeZeichnung) { var f = wartendeZeichnung; wartendeZeichnung = null; f(); } 2225 }); 2226 2227 sicher("Menü", baueMenu); 2228 sicher("Terminfilter", baueTerminFilterDialog); 2229 sicher("Ebenen", function () { 2230 EBENEN.forEach(function (e) { 2231 ebeneAufbauen(e); 2232 if (e.punkte && e.punkte.length) setzePunkte(e, e.punkte); 2233 }); 2234 }); 2235 sicher("Kulturdaten", ladeKultur); 2236 sicher("Veranstaltungen", starteTermine); 2237 sicher("Gemeindegrenzen", ladeGemeindeGrenzen); 2238 2239 var n = 0, iv = setInterval(function () { 2240 karte.invalidateSize(); if (++n > 10) clearInterval(iv); 2241 }, 500); 2242 if (window.ResizeObserver) { 2243 new ResizeObserver(function () { karte.invalidateSize(); }).observe(box); 2244 } 2245 } 2246 2247 function ebeneAufbauen(e) { 2248 if (layerVon[e.id]) return; 2249 layerVon[e.id] = L.layerGroup(); 2250 if (e.aktiv) layerVon[e.id].addTo(karte); 2251 } 2252 2253 function setzePunkte(e, punkte) { 2254 if (karte && karte._popup && e._gezeichnet) { 2255 wartendeZeichnung = function () { setzePunkte(e, punkte); }; 2256 return; 2257 } 2258 e.punkte = punkte || []; 2259 zeichneEbeneMarker(e); 2260 } 2261 2262 // zeichnet e.punkte neu, unter Berücksichtigung des aktuellen 2263 // Gemeinde-Filters, und zählt dabei mit, wie viele Punkte 2264 // (bzw. bei Veranstaltungen: Termine) auf welche Gemeinde entfallen 2265 function zeichneEbeneMarker(e) { 2266 var layer = layerVon[e.id]; 2267 if (!layer) return; 2268 layer.clearLayers(); 2269 2270 var gemeindeAnzahl = {}; 2271 var sichtbare = []; 2272 (e.punkte || []).forEach(function (p) { 2273 // Zeitraum-Filter: nur bei Punkten mit Terminen (Veranstaltungen), 2274 // andere Ebenen über setzePunkte sind davon nicht betroffen 2275 if (p.termine && !TERMIN_FILTER.alle) { 2276 var gefiltert = p.termine.filter(terminPasstInFilter); 2277 if (!gefiltert.length) return; 2278 var kopie = {}; 2279 for (var k in p) if (p.hasOwnProperty(k)) kopie[k] = p[k]; 2280 kopie.termine = gefiltert; 2281 p = kopie; 2282 } 2283 if (p.gemeinde) { 2284 gemeindeAnzahl[p.gemeinde] = (gemeindeAnzahl[p.gemeinde] || 0) + 2285 (p.termine ? p.termine.length : 1); 2286 } 2287 if (gemeindeSichtbar(p.gemeinde)) sichtbare.push(p); 2288 });
2289 2290 sichtbare.forEach(function (p) { 2291 var farbe = p.farbe || e.farbe; 2292 var marker = punktMarker([p.lat, p.lng], farbe, p.bild || e.bild, 2293 p.name, BESCHRIFTUNG_IMMER); 2294 marker.bindPopup(popupInhalt(p, farbe), popupOptionen()); 2295 layer.addLayer(marker); 2296 }); 2297 2298 e._gezeichnet = true; 2299 e._gemeindeAnzahl = gemeindeAnzahl; 2300 zaehlerSetzen(e, sichtbare.length); 2301 gemeindeZaehlerAktualisieren(); 2302 } 2303 2304 function zaehlerSetzen(e, anzahl) { 2305 if (e._anzahlFeld) e._anzahlFeld.textContent = anzahl ? anzahl : ""; 2306 } 2307 2308 /* ========================================================= 2309 8) FILTER (KATEGORIEN) 2310 ========================================================= */ 2311 2312 function baueMenu() { 2313 menuBox = document.getElementById("bwk-menu"); 2314 menuHeimat = menuBox.parentNode; 2315 menuAnker = menuBox.nextSibling; 2316 2317 menuBox.innerHTML = ""; 2318 2319 baueGemeindeFilter(menuBox); 2320 2321 var kopf = document.createElement("div"); 2322 kopf.className = "bwk-kopfzeile"; 2323 2324 var titel = document.createElement("p"); 2325 titel.className = "bwk-ueberschrift"; 2326 titel.textContent = FILTER_TITEL; 2327 2328 alleKnopf = document.createElement("button"); 2329 alleKnopf.type = "button"; 2330 alleKnopf.className = "bwk-alle"; 2331 alleKnopf.textContent = START_ALLE_AUS ? "Alle anzeigen" : "Alle ausblenden"; 2332 alleKnopf.addEventListener("click", alleSchalten); 2333 2334 var zu = document.createElement("button"); 2335 zu.type = "button"; 2336 zu.className = "bwk-menu-zu"; 2337 zu.title = FILTER_TITEL + " ausblenden"; 2338 zu.setAttribute("aria-label", FILTER_TITEL + " ausblenden"); 2339 zu.innerHTML = "×"; 2340 zu.addEventListener("click", function () { menuBox.classList.add("bwk-zu"); }); 2341 2342 kopf.appendChild(titel); 2343 kopf.appendChild(alleKnopf); 2344 kopf.appendChild(zu); 2345 menuBox.appendChild(kopf); 2346 2347 menuInhalt = document.createElement("div"); 2348 menuInhalt.className = "bwk-inhalt"; 2349 menuBox.appendChild(menuInhalt); 2350 2351 listeKultur = document.createElement("div"); 2352 listeKultur.style.display = "contents"; 2353 menuInhalt.appendChild(listeKultur); 2354 2355 gruppeFest = neueGruppe("Termine", null); 2356 EBENEN.forEach(function (e) { menuZeile(e, gruppeFest); }); 2357 } 2358 2359 // "Alle anzeigen" / "Alle ausblenden" 2360 function alleSchalten() { 2361 var an = EBENEN.some(function (e) { return e.aktiv; }); 2362 EBENEN.forEach(function (e) { 2363 if (e._cb) e._cb.checked = !an; 2364 schalte(e, !an); 2365 }); 2366 alleGruppen.forEach(gruppeStand); 2367 alleStand(); 2368 } 2369 function alleStand() { 2370 if (!alleKnopf) return; 2371 var an = EBENEN.some(function (e) { return e.aktiv; }); 2372 alleKnopf.textContent = an ? "Alle ausblenden" : "Alle anzeigen"; 2373 } 2374 2375 function gruppeKlappen(gr, zu) { 2376 if (!gr || !gr.box) return; 2377 if (zu) gr.box.classList.add("bwk-zugeklappt"); 2378 else gr.box.classList.remove("bwk-zugeklappt"); 2379 if (gr.auf) gr.auf.setAttribute("aria-expanded", zu ? "false" : "true"); 2380 } 2381 2382 function neueGruppe(name, behaelter) { 2383 var box = document.createElement("div"); 2384 box.className = "bwk-gruppe"; 2385 2386 var beschr = txt(name) || "Karte"; 2387 var nummer = ++gruppenZaehler; 2388 2389 var kopf = document.createElement("div"); 2390 kopf.className = "bwk-gruppen-kopf"; 2391 2392 var cb = document.createElement("input"); 2393 cb.type = "checkbox"; 2394 cb.id = "bwk-gr-" + nummer; 2395 cb.checked = !START_ALLE_AUS; 2396 2397 var lbl = document.createElement("label"); 2398 lbl.htmlFor = cb.id; 2399 lbl.textContent = beschr; 2400 2401 var auf = document.createElement("button"); 2402 auf.type = "button"; 2403 auf.className = "bwk-auf"; 2404 auf.title = "Auf- oder zuklappen"; 2405 auf.setAttribute("aria-label", "Auf- oder zuklappen"); 2406 auf.setAttribute("aria-expanded", "true"); 2407 auf.innerHTML = pfeilSvg(); 2408 2409 kopf.appendChild(cb); 2410 kopf.appendChild(lbl); 2411 kopf.appendChild(auf); 2412 box.appendChild(kopf); 2413 2414 var liste = document.createElement("div"); 2415 liste.className = "bwk-gruppen-liste"; 2416 liste.id = "bwk-liste-" + nummer; 2417 auf.setAttribute("aria-controls", liste.id); 2418 box.appendChild(liste); 2419 2420 (behaelter || menuInhalt).appendChild(box); 2421 2422 var gr = { box: box, liste: liste, cb: cb, auf: auf, ebenen: [] }; 2423 alleGruppen.push(gr); 2424 2425 cb.addEventListener("change", function () { 2426 cb.indeterminate = false;
2427 gr.ebenen.forEach(function (e) { 2428 if (e._cb) e._cb.checked = cb.checked; 2429 schalte(e, cb.checked); 2430 }); 2431 alleStand(); 2432 }); 2433 2434 auf.addEventListener("click", function () { 2435 gruppeKlappen(gr, !box.classList.contains("bwk-zugeklappt")); 2436 }); 2437 2438 return gr; 2439 } 2440 2441 function gruppeStand(gr) { 2442 if (!gr || !gr.cb || !gr.ebenen.length) return; 2443 var an = 0; 2444 gr.ebenen.forEach(function (e) { if (e.aktiv) an++; }); 2445 gr.cb.checked = an > 0; 2446 gr.cb.indeterminate = an > 0 && an < gr.ebenen.length; 2447 } 2448 2449 function gruppeEntfernen(gr) { 2450 if (!gr) return; 2451 gr.ebenen.slice().forEach(ebeneEntfernen); 2452 if (gr.box && gr.box.parentNode) gr.box.parentNode.removeChild(gr.box); 2453 var i = kulturGruppen.indexOf(gr); 2454 if (i > -1) kulturGruppen.splice(i, 1); 2455 var j = alleGruppen.indexOf(gr); 2456 if (j > -1) alleGruppen.splice(j, 1); 2457 } 2458 2459 // eine Ebene als Kästchen 2460 function menuZeile(e, gruppe) { 2461 var farbe = e.farbe || "#2f6b4f"; 2462 2463 var zeile = document.createElement("label"); 2464 zeile.className = "bwk-zeile " + (e.aktiv ? "bwk-an" : "bwk-aus"); 2465 2466 var cb = document.createElement("input"); 2467 cb.type = "checkbox"; 2468 cb.className = "bwk-haken"; 2469 cb.checked = !!e.aktiv; 2470 2471 var swatch = document.createElement("span"); 2472 swatch.className = "bwk-swatch"; 2473 swatch.innerHTML = swatchHtml(farbe, e.bild); 2474 2475 var name = document.createElement("span"); 2476 name.className = "bwk-name"; 2477 name.textContent = e.name; 2478 2479 var anzahl = document.createElement("span"); 2480 anzahl.className = "bwk-anzahl"; 2481 anzahl.textContent = e.punkte && e.punkte.length ? e.punkte.length : ""; 2482 2483 zeile.appendChild(cb); 2484 zeile.appendChild(swatch); 2485 zeile.appendChild(name); 2486 zeile.appendChild(anzahl); 2487 gruppe.liste.appendChild(zeile); 2488 gruppe.ebenen.push(e); 2489 2490 e._zeile = zeile; e._cb = cb; e._anzahlFeld = anzahl; 2491 e._swatch = swatch; e._gruppe = gruppe; 2492 2493 // Original-Piktogramm auch im Filterpunkt nachreichen 2494 fernNachladen(e.bild, function () { 2495 if (e._swatch) e._swatch.innerHTML = swatchHtml(farbe, e.bild); 2496 }); 2497 2498 cb.addEventListener("change", function () { 2499 schalte(e, cb.checked); 2500 gruppeStand(gruppe); 2501 alleStand(); 2502 }); 2503 2504 gruppeStand(gruppe); 2505 alleStand(); 2506 } 2507 2508 function schalte(e, an) { 2509 e.aktiv = an; 2510 if (e._zeile) { 2511 e._zeile.classList.toggle("bwk-an", !!an); 2512 e._zeile.classList.toggle("bwk-aus", !an); 2513 } 2514 var layer = layerVon[e.id]; 2515 if (layer) { 2516 if (an) layer.addTo(karte); else karte.removeLayer(layer); 2517 } 2518 gemeindeZaehlerAktualisieren(); 2519 if (an && e.id === "va-kalender") zeigeTerminFilter(); 2520 } 2521 2522 function ebeneEntfernen(e) { 2523 if (!e) return; 2524 if (layerVon[e.id]) { karte.removeLayer(layerVon[e.id]); delete layerVon[e.id]; } 2525 if (e._zeile && e._zeile.parentNode) e._zeile.parentNode.removeChild(e._zeile); 2526 if (e._gruppe) { 2527 var j = e._gruppe.ebenen.indexOf(e); 2528 if (j > -1) e._gruppe.ebenen.splice(j, 1); 2529 } 2530 var i = EBENEN.indexOf(e); 2531 if (i > -1) EBENEN.splice(i, 1); 2532 var k = kulturEbenen.indexOf(e); 2533 if (k > -1) kulturEbenen.splice(k, 1); 2534 } 2535 2536 /* ---------- Gemeinde-Filter ---------- 2537 Eigener, flacher Chip-Filter über den Kategorien. Wirkt wie ein 2538 zusätzliches UND: ein Punkt braucht eine angehakte Kategorie 2539 UND eine angehakte Gemeinde, um zu erscheinen. Punkte ohne 2540 erkennbare Gemeinde werden nie versteckt. ---------- */ 2541 2542 function baueGemeindeFilter(behaelter) { 2543 var box = document.createElement("div"); 2544 box.className = "bwk-gemeinden"; 2545 2546 var kopf = document.createElement("div"); 2547 kopf.className = "bwk-kopfzeile"; 2548 2549 var titel = document.createElement("p"); 2550 titel.className = "bwk-ueberschrift"; 2551 titel.textContent = "Gemeinden"; 2552 2553 gemeindeAlleKnopf = document.createElement("button"); 2554 gemeindeAlleKnopf.type = "button"; 2555 gemeindeAlleKnopf.className = "bwk-alle"; 2556 gemeindeAlleKnopf.textContent = "Alle abwählen"; 2557 gemeindeAlleKnopf.addEventListener("click", gemeindeAlleSchalten); 2558
2559 kopf.appendChild(titel); 2560 kopf.appendChild(gemeindeAlleKnopf); 2561 box.appendChild(kopf); 2562 2563 var liste = document.createElement("div"); 2564 liste.className = "bwk-gemeinde-liste"; 2565 box.appendChild(liste); 2566 2567 GEMEINDE_ANZEIGE.forEach(function (name) { 2568 GEMEINDE_STAND[name] = true; 2569 2570 var chip = document.createElement("label"); 2571 chip.className = "bwk-chip bwk-an"; 2572 2573 var cb = document.createElement("input"); 2574 cb.type = "checkbox"; 2575 cb.className = "bwk-haken"; 2576 cb.checked = true; 2577 2578 var beschriftung = document.createElement("span"); 2579 beschriftung.textContent = name; 2580 2581 var anzahl = document.createElement("span"); 2582 anzahl.className = "bwk-chip-anzahl"; 2583 2584 chip.appendChild(cb); 2585 chip.appendChild(beschriftung); 2586 chip.appendChild(anzahl); 2587 liste.appendChild(chip); 2588 2589 GEMEINDE_ZEILEN[name] = { chip: chip, cb: cb, anzahlFeld: anzahl }; 2590 2591 cb.addEventListener("change", function () { 2592 GEMEINDE_STAND[name] = cb.checked; 2593 chip.classList.toggle("bwk-an", cb.checked); 2594 chip.classList.toggle("bwk-aus", !cb.checked); 2595 gemeindeAlleStand(); 2596 neuZeichnenAlle(); 2597 gemeindeKartePassen(); 2598 }); 2599 }); 2600 2601 behaelter.appendChild(box); 2602 } 2603 2604 function gemeindeAlleSchalten() { 2605 var an = GEMEINDE_ANZEIGE.some(function (g) { return GEMEINDE_STAND[g] !== false; }); 2606 GEMEINDE_ANZEIGE.forEach(function (g) { 2607 GEMEINDE_STAND[g] = !an; 2608 var z = GEMEINDE_ZEILEN[g]; 2609 if (!z) return; 2610 z.cb.checked = !an; 2611 z.chip.classList.toggle("bwk-an", !an); 2612 z.chip.classList.toggle("bwk-aus", an); 2613 }); 2614 gemeindeAlleStand(); 2615 neuZeichnenAlle(); 2616 gemeindeKartePassen(); 2617 } 2618 2619 function gemeindeAlleStand() { 2620 if (!gemeindeAlleKnopf) return; 2621 var an = GEMEINDE_ANZEIGE.some(function (g) { return GEMEINDE_STAND[g] !== false; }); 2622 gemeindeAlleKnopf.textContent = an ? "Alle abwählen" : "Alle auswählen"; 2623 } 2624 2625 // Zähler neben jeder Gemeinde: Summe über alle gerade aktiven 2626 // Ebenen (Kategorien), unabhängig vom Gemeinde-Filter selbst â 2627 // zeigt also "was gäbe es hier", nicht "was ist gerade sichtbar" 2628 function gemeindeZaehlerAktualisieren() { 2629 var summe = {}; 2630 EBENEN.forEach(function (e) { 2631 if (!e.aktiv || !e._gemeindeAnzahl) return; 2632 Object.keys(e._gemeindeAnzahl).forEach(function (g) { 2633 summe[g] = (summe[g] || 0) + e._gemeindeAnzahl[g]; 2634 }); 2635 }); 2636 GEMEINDE_ANZEIGE.forEach(function (g) { 2637 var z = GEMEINDE_ZEILEN[g]; 2638 if (z && z.anzahlFeld) z.anzahlFeld.textContent = summe[g] || ""; 2639 }); 2640 } 2641 2642 // alle Ebenen mit dem aktuellen Gemeinde-Filter neu zeichnen 2643 // (nach einem Klick auf einen Gemeinde-Chip) 2644 function neuZeichnenAlle() { 2645 EBENEN.forEach(function (e) { 2646 if (e._roh) setzeGeojson(e, e._roh); 2647 else zeichneEbeneMarker(e); 2648 }); 2649 } 2650 2651 /* ---------- Termin-Zeitraum-Dialog ---------- 2652 Geht auf, sobald "Veranstaltungen" angehakt wird (siehe 2653 schalte()). "Alle Termine" an = kein Filter. Aus + Von/Bis 2654 gesetzt = nur Termine in diesem Zeitraum werden gezeichnet 2655 (siehe terminPasstInFilter(), verwendet in zeichneEbeneMarker()). ---------- */ 2656 2657 var terminFilterElemente = null; 2658 2659 // "12.9.2026 19:00" -> 20260912 (Tag nur aus dem Anfang der 2660 // Zeichenkette, alles danach â Uhrzeit usw. â wird ignoriert) 2661 function terminDatumWert(datumStr) { 2662 var m = txt(datumStr).match(/^(\d{1,2})\.(\d{1,2})\.(\d{2,4})/); 2663 if (!m) return null; 2664 var tag = +m[1], monat = +m[2], jahr = +m[3]; 2665 if (jahr < 100) jahr += 2000; 2666 return jahr * 10000 + monat * 100 + tag; 2667 } 2668 // "2026-09-12" (Wert eines <input type="date">) -> 20260912 2669 function eingabeDatumWert(s) { 2670 var t = txt(s).split("-"); 2671 if (t.length !== 3) return null; 2672 return (+t[0]) * 10000 + (+t[1]) * 100 + (+t[2]); 2673 } 2674 function terminPasstInFilter(t) { 2675 if (TERMIN_FILTER.alle) return true; 2676 var w = terminDatumWert(t.datum); 2677 if (w === null) return true; // kein erkennbares Datum: nicht herausfiltern 2678 var von = eingabeDatumWert(TERMIN_FILTER.von);
2679 var bis = eingabeDatumWert(TERMIN_FILTER.bis); 2680 if (von !== null && w < von) return false; 2681 if (bis !== null && w > bis) return false; 2682 return true; 2683 } 2684 2685 function baueTerminFilterDialog() { 2686 var hinter = document.createElement("div"); 2687 hinter.id = "bwk-tf-hinter"; 2688 hinter.hidden = true; 2689 2690 var box = document.createElement("div"); 2691 box.className = "bwk-tf-box"; 2692 box.setAttribute("role", "dialog"); 2693 box.setAttribute("aria-modal", "true"); 2694 2695 var schliessen = document.createElement("button"); 2696 schliessen.type = "button"; 2697 schliessen.className = "bwk-tf-schliessen"; 2698 schliessen.title = "SchlieÃen"; 2699 schliessen.setAttribute("aria-label", "SchlieÃen"); 2700 schliessen.innerHTML = "×"; 2701 schliessen.addEventListener("click", function () { hinter.hidden = true; }); 2702 2703 var titel = document.createElement("p"); 2704 titel.className = "bwk-tf-titel"; 2705 titel.textContent = "Welcher Zeitraum?"; 2706 2707 var zeile = document.createElement("div"); 2708 zeile.className = "bwk-tf-zeile"; 2709 2710 var vonLbl = document.createElement("label"); 2711 vonLbl.appendChild(document.createTextNode("Von")); 2712 var von = document.createElement("input"); 2713 von.type = "date"; 2714 vonLbl.appendChild(von); 2715 2716 var bisLbl = document.createElement("label"); 2717 bisLbl.appendChild(document.createTextNode("Bis")); 2718 var bis = document.createElement("input"); 2719 bis.type = "date"; 2720 bisLbl.appendChild(bis); 2721 2722 zeile.appendChild(vonLbl); 2723 zeile.appendChild(bisLbl); 2724 2725 var alleLbl = document.createElement("label"); 2726 alleLbl.className = "bwk-tf-haken"; 2727 var alle = document.createElement("input"); 2728 alle.type = "checkbox"; 2729 alle.checked = true; 2730 alleLbl.appendChild(alle); 2731 alleLbl.appendChild(document.createTextNode("Alle Termine anzeigen")); 2732 2733 var knoepfe = document.createElement("div"); 2734 knoepfe.className = "bwk-tf-knoepfe"; 2735 var anwenden = document.createElement("button"); 2736 anwenden.type = "button"; 2737 anwenden.className = "bwk-tf-anwenden"; 2738 anwenden.textContent = "Filter anwenden"; 2739 knoepfe.appendChild(anwenden); 2740 2741 box.appendChild(schliessen); 2742 box.appendChild(titel); 2743 box.appendChild(zeile); 2744 box.appendChild(alleLbl); 2745 box.appendChild(knoepfe); 2746 hinter.appendChild(box); 2747 // An #bwk-kartenbox hängen statt an document.body: im echten 2748 // Vollbildmodus rendert der Browser NUR den fullscreen-Container 2749 // und dessen Nachfahren â alles auÃerhalb (also auch document.body 2750 // direkt) bleibt unsichtbar, solange Vollbild aktiv ist. 2751 (kartenbox || document.body).appendChild(hinter); 2752 2753 // Die Felder bleiben immer bedienbar (ein "disabled"-Feld lässt 2754 // sich gar nicht erst anklicken â das war der eigentliche Fehler, 2755 // wegen dem der Filter "nie funktioniert" hat). Sobald ein Datum 2756 // gewählt wird, hakt "Alle Termine anzeigen" automatisch ab. 2757 von.addEventListener("change", function () { if (von.value || bis.value) alle.checked = false; }); 2758 bis.addEventListener("change", function () { if (von.value || bis.value) alle.checked = false; }); 2759 alle.addEventListener("change", function () { 2760 if (alle.checked) { von.value = ""; bis.value = ""; } 2761 }); 2762 2763 anwenden.addEventListener("click", function () { 2764 TERMIN_FILTER.alle = alle.checked; 2765 TERMIN_FILTER.von = alle.checked ? "" : von.value; 2766 TERMIN_FILTER.bis = alle.checked ? "" : bis.value; 2767 hinter.hidden = true; 2768 var ziel = findeEbene("va-kalender"); 2769 if (ziel) zeichneEbeneMarker(ziel); 2770 }); 2771 2772 hinter.addEventListener("click", function (ev) { 2773 if (ev.target === hinter) hinter.hidden = true; 2774 }); 2775 document.addEventListener("keydown", function (ev) { 2776 if (!hinter.hidden && (ev.key === "Escape" || ev.key === "Esc")) hinter.hidden = true; 2777 }); 2778 2779 terminFilterElemente = { hinter: hinter, von: von, bis: bis, alle: alle }; 2780 } 2781 2782 function zeigeTerminFilter() { 2783 if (!terminFilterElemente) return; 2784 var el = terminFilterElemente; 2785 el.von.value = TERMIN_FILTER.von || ""; 2786 el.bis.value = TERMIN_FILTER.bis || ""; 2787 el.alle.checked = TERMIN_FILTER.alle; 2788 el.hinter.hidden = false; 2789 } 2790 2791 /* ========================================================= 2792 9) KULTUREBENEN (nur aus der Datei der Medienverwaltung) 2793 ========================================================= */ 2794 2795 function neueKulturebene(name, farbe, bild, aktiv, daten, gruppe) { 2796 var e = { id: "kultur-" + EBENEN.length + "-" + Date.now() + "-" + Math.random().toString(36).slice(2,
27966), 2797 name: name, farbe: farbe, bild: bild || null, 2798 aktiv: START_ALLE_AUS ? false : (aktiv !== false), punkte: [], 2799 _roh: daten || null }; 2800 EBENEN.push(e); 2801 kulturEbenen.push(e); 2802 ebeneAufbauen(e); 2803 menuZeile(e, gruppe); 2804 if (daten) setzeGeojson(e, daten); 2805 return e; 2806 } 2807 2808 function kulturLeeren() { 2809 kulturGruppen.slice().forEach(gruppeEntfernen); 2810 kulturEbenen.slice().forEach(ebeneEntfernen); 2811 kulturGruppen = []; kulturEbenen = []; 2812 farbZaehler = 0; 2813 if (listeKultur) listeKultur.innerHTML = ""; 2814 gemeindeZaehlerAktualisieren(); 2815 } 2816 2817 function kulturAdresse() { 2818 var id = txt(KULTUR_FILEID); 2819 if (!id) return ""; 2820 var adresse = KULTUR_URL_MUSTER.replace("{id}", encodeURIComponent(id)); 2821 if (DATEI_FRISCH_LADEN) { 2822 adresse += (adresse.indexOf("?") === -1 ? "?" : "&") + "stand=" + Date.now(); 2823 } 2824 return adresse; 2825 } 2826 2827 // Ãbersicht in der Konsole: welches Symbol und welche Farbe 2828 // bekommt welche Ebene? 2829 function ebenenBericht(daten) { 2830 if (!SYMBOL_BERICHT || !daten) return; 2831 var zeilen = []; 2832 var wurzel = daten.layers || (daten.type === "FeatureCollection" ? [daten] : []); 2833 2834 (function durch(liste, gruppe) { 2835 (liste || []).forEach(function (l, i) { 2836 if (!l) return; 2837 var name = nameAus(l, "Ebene " + (i + 1)); 2838 var u = txt(opt(l, "iconUrl", "")); 2839 var farbe = farbeAus(l, ""); 2840 if (l.features && l.features.length) { 2841 zeilen.push({ 2842 Gruppe: gruppe || "â", 2843 Ebene: name, 2844 iconUrl: u || "(keine)", 2845 Symbol: (u ? symbolAusDatei(u) : "") || symbolAusText(name) || "punkt", 2846 Farbe: farbe || "(Vorgabe)", 2847 Symbolfarbe: farbe ? (istDunkelSymbol(farbe) ? "schwarz" : "weiÃ") : "weiÃ", 2848 Punkte: l.features.length 2849 }); 2850 } 2851 if (l.layers) durch(l.layers, name); 2852 }); 2853 })(wurzel, ""); 2854 2855 if (!zeilen.length) { 2856 console.warn("[Karte] Keine Ebene mit Punkten in der Datei gefunden."); 2857 return; 2858 } 2859 console.info("[Karte] Symbole der Ebenen:"); 2860 if (console.table) console.table(zeilen); else console.log(zeilen); 2861 } 2862 2863 function ladeKultur() { 2864 var adresse = kulturAdresse(); 2865 if (!adresse) { 2866 console.info("[Karte] Keine KULTUR_FILEID gesetzt â es werden nur Veranstaltungen gezeigt."); 2867 return; 2868 } 2869 2870 fetch(adresse, { credentials: "same-origin", cache: "no-store" }) 2871 .then(function (r) { 2872 if (!r.ok) throw new Error("HTTP " + r.status); 2873 return r.text(); 2874 }) 2875 .then(function (text) { 2876 try { return JSON.parse(text); } 2877 catch (e) { throw new Error("Datei ist kein gültiges JSON"); } 2878 }) 2879 .then(function (daten) { 2880 if (daten && daten.uri) { 2881 try { UMAP_SERVER = new URL(daten.uri).origin.replace(/^http:/i, "https:"); } 2882 catch (e) { } 2883 } 2884 var anzahl = kulturVerarbeiten(daten); 2885 if (!anzahl) throw new Error("keine verwertbaren Ebenen in der Datei"); 2886 console.info("[Karte] Kulturdatei geladen: " + anzahl + " Ebene(n), Symbolserver: " + 2887 serverListe().join(", ")); 2888 sicher("Ebenenbericht", function () { ebenenBericht(daten); }); 2889 }) 2890 .catch(function (fehler) { 2891 kulturLeeren(); 2892 console.warn("[Karte] Kulturdatei (fileid " + KULTUR_FILEID + ") nicht verwendbar: " + 2893 (fehler.message || fehler) + " â es werden nur Veranstaltungen gezeigt."); 2894 }); 2895 } 2896 2897 // zerlegt einen uMap-Export in Gruppen und Ebenen; gibt die Anzahl der Ebenen zurück 2898 function kulturVerarbeiten(daten) { 2899 if (!daten) return 0; 2900 2901 if (daten.type === "FeatureCollection" && !daten.layers) { 2902 if (!daten.features || !daten.features.length) return 0; 2903 var titel = nameAus(daten, "Kulturkarte"); 2904 var gr = neueGruppe("Kulturkarte", listeKultur); 2905 kulturGruppen.push(gr); 2906 neueKulturebene(titel, farbeAus(daten, naechsteFarbe()), 2907 iconInfo(daten, null, titel), true, daten, gr); 2908 return 1; 2909 } 2910 2911 return ebenenListe(daten.layers, null, ""); 2912 } 2913 2914 // Farbe einer Gruppe: eigene Farbe, sonst die erste Farbe 2915 // darin, sonst die nächste aus der Palette 2916 function gruppenFarbe(fc) { 2917 var eigen = farbeAus(fc, ""); 2918 if (eigen) return eigen; 2919 2920 var gefunden = ""; 2921 (function durch(liste) {
2922 (liste || []).forEach(function (l) { 2923 if (gefunden || !l) return; 2924 var c = farbeAus(l, ""); 2925 if (c) { gefunden = c; return; } 2926 if (l.layers) durch(l.layers); 2927 }); 2928 })(fc.layers); 2929 2930 return gefunden || naechsteFarbe(); 2931 } 2932 2933 // Reihenfolge einer Gruppe/Ebene, wie in uMap selbst festgelegt 2934 // (Feld "rank", direkt neben "properties" â opt() findet es über 2935 // den letzten Rückgriff auf das Objekt selbst). Ohne "rank" ganz 2936 // ans Ende. 2937 function rangVon(o) { 2938 var r = opt(o, "rank", null); 2939 return (typeof r === "number") ? r : 999999; 2940 } 2941 function nachRang(liste) { 2942 try { 2943 return liste.slice().sort(function (a, b) { return rangVon(a) - rangVon(b); }); 2944 } catch (fehler) { 2945 console.warn("[Karte] Sortierung nach Rang fehlgeschlagen, Reihenfolge aus der Datei wird verwendet:", fehler); 2946 return liste; 2947 } 2948 } 2949 2950 // arbeitet die (auch verschachtelten) uMap-Ebenen ab, in der 2951 // Reihenfolge, in der sie in uMap selbst angeordnet sind. 2952 // "farbe" ist die Farbe der übergeordneten Gruppe. 2953 function ebenenListe(liste, gruppe, farbe) { 2954 if (!liste || !liste.length) return 0; 2955 var anzahl = 0, ohneGruppe = gruppe; 2956 var sortiert = nachRang(liste); 2957 2958 sortiert.forEach(function (fc, i) { 2959 if (!fc) return; 2960 var name = nameAus(fc, "Ebene " + (i + 1)); 2961 var istGruppe = !!(fc.layers && fc.layers.length) || opt(fc, "group", false) === true; 2962 2963 if (istGruppe) { 2964 var gfarbe = GRUPPENFARBE ? gruppenFarbe(fc) : ""; 2965 var gr = neueGruppe(name, listeKultur); 2966 kulturGruppen.push(gr); 2967 var n = ebenenListe(fc.layers, gr, gfarbe); 2968 2969 if (fc.features && fc.features.length) { 2970 neueKulturebene(name, gfarbe || farbeAus(fc, naechsteFarbe()), 2971 iconInfo(fc, null, name), 2972 opt(fc, "displayOnLoad", true) !== false, fc, gr); 2973 n++; 2974 } 2975 if (!n) gruppeEntfernen(gr); else anzahl += n; 2976 return; 2977 } 2978 2979 if (!fc.features || !fc.features.length) return; // leere Ebenen überspringen 2980 2981 if (!ohneGruppe) { 2982 ohneGruppe = neueGruppe("Karte", listeKultur); 2983 kulturGruppen.push(ohneGruppe); 2984 } 2985 // Ebenen einer Gruppe tragen normalerweise die Farbe der 2986 // Gruppe â auÃer eine Ebene hat selbst ausdrücklich eine 2987 // eigene Farbe gesetzt, die hat dann Vorrang. 2988 var eigeneFarbe = farbeAus(fc, ""); 2989 var lfarbe = eigeneFarbe || (GRUPPENFARBE && farbe) || naechsteFarbe(); 2990 neueKulturebene(name, lfarbe, iconInfo(fc, null, name), 2991 opt(fc, "displayOnLoad", true) !== false, fc, ohneGruppe); 2992 anzahl++; 2993 }); 2994 2995 return anzahl; 2996 } 2997 2998 // fasst doppelte Einträge zusammen (gleicher Name + gleiche Koordinaten) 2999 function entdoppeln(daten) { 3000 if (!daten || !daten.features || !daten.features.length) return daten; 3001 var gesehen = {}, raus = []; 3002 3003 daten.features.forEach(function (f) { 3004 if (!f) return; 3005 var p = f.properties || {}, g = f.geometry || {}; 3006 var koord = JSON.stringify(g.coordinates === undefined ? "" : g.coordinates); 3007 var k = normalisiere(p.name || p.title || "") + "|" + (g.type || "") + "|" + koord; 3008 3009 if (gesehen[k]) { 3010 var alt = gesehen[k].properties || {}; 3011 var neuText = p.description || p.beschreibung || ""; 3012 var altText = alt.description || alt.beschreibung || ""; 3013 if (neuText.length > altText.length) { 3014 gesehen[k].properties = gesehen[k].properties || {}; 3015 gesehen[k].properties.description = neuText; 3016 } 3017 return; 3018 } 3019 gesehen[k] = f; 3020 raus.push(f); 3021 }); 3022 3023 if (raus.length === daten.features.length) return daten; 3024 return { type: "FeatureCollection", features: raus }; 3025 } 3026 3027 function istLinie(feature) { 3028 return !!(feature && feature.geometry && /LineString/.test(feature.geometry.type)); 3029 } 3030 3031 // welcher der 24 Filter-Gemeinden gehört ein Punkt-Feature an? 3032 // Reihenfolge: 1) echte Gemeindegrenze anhand der Koordinate 3033 // (genau, sobald geladen), 2) Texterkennung in Adresse/Name als 3034 // Rückfallebene. Das Ergebnis wird am Feature zwischengespeichert, 3035 // aber erst NACHDEM die Grenzen einmal geladen sind â sonst würde 3036 // ein früher (per Text geratener) Treffer nie mehr aktualisiert. 3037 function gemeindeFuerFeature(feature) {
3038 if (GRENZEN_GELADEN && feature._bwkGemeinde !== undefined) return feature._bwkGemeinde; 3039 3040 var gem = ""; 3041 var geom = feature.geometry; 3042 if (GRENZEN_GELADEN && geom && geom.type === "Point" && geom.coordinates) { 3043 gem = gemeindeAusKoordinaten(geom.coordinates[1], geom.coordinates[0]); 3044 } 3045 if (!gem) { 3046 var p = feature.properties || {}; 3047 gem = gemeindeKanonisch(erkenneGemeinde(p.adresse || p.address || "", 3048 p.name || p.title || "")); 3049 } 3050 gem = gem || GEMEINDE_AUSSERHALB; // nie leer: sonst wäre der Punkt "immer sichtbar" 3051 if (GRENZEN_GELADEN) feature._bwkGemeinde = gem; 3052 return gem; 3053 } 3054 3055 // welche der 24 Filter-Gemeinden berührt eine Linie (Route)? 3056 // Anders als bei einem Punkt kann das mehrere sein â eine Route 3057 // ist sichtbar, sobald IRGENDEINE ihrer Gemeinden angehakt ist. 3058 // Geprüft wird jeder Stützpunkt der Linie gegen die echten 3059 // Grenzen; solange die noch nicht geladen sind, greift ersatz- 3060 // weise die Texterkennung in Adresse/Name (liefert dann höchstens 3061 // eine Gemeinde). Wie bei Punkten wird das Ergebnis erst nach dem 3062 // Laden der Grenzen am Feature zwischengespeichert. 3063 function gemeindenFuerLinie(feature) { 3064 if (GRENZEN_GELADEN && feature._bwkGemeinden !== undefined) return feature._bwkGemeinden; 3065 3066 var geom = feature.geometry; 3067 var punkte = []; 3068 if (geom.type === "LineString") punkte = geom.coordinates; 3069 else if (geom.type === "MultiLineString") { 3070 geom.coordinates.forEach(function (teil) { punkte = punkte.concat(teil); }); 3071 } 3072 3073 var namen = []; 3074 if (GRENZEN_GELADEN) { 3075 var treffer = {}; 3076 punkte.forEach(function (p) { 3077 var g = gemeindeAusKoordinaten(p[1], p[0]); 3078 if (g) treffer[g] = true; 3079 }); 3080 namen = Object.keys(treffer); 3081 } 3082 if (!namen.length) { 3083 var p = feature.properties || {}; 3084 var text = gemeindeKanonisch(erkenneGemeinde(p.adresse || p.address || "", 3085 p.name || p.title || "")); 3086 if (text) namen = [text]; 3087 } 3088 if (!namen.length) namen = [GEMEINDE_AUSSERHALB]; 3089 3090 if (GRENZEN_GELADEN) feature._bwkGemeinden = namen; 3091 return namen; 3092 } 3093 3094 function setzeGeojson(e, rohdaten) { 3095 var layer = layerVon[e.id]; 3096 if (!layer) return 0; 3097 layer.clearLayers(); 3098 3099 var daten = entdoppeln(rohdaten); 3100 var dauerhaft = opt(rohdaten, "showLabel", null) === true || BESCHRIFTUNG_IMMER; 3101 var anzahl = 0; 3102 var hilfen = []; 3103 var gemeindeAnzahl = {}; 3104 3105 // bei GRUPPENFARBE zählt allein die Farbe der Ebene 3106 function punktFarbe(feature) { 3107 return GRUPPENFARBE ? e.farbe : farbeAus(feature, e.farbe); 3108 } 3109 3110 try { 3111 var geo = L.geoJSON(daten, { 3112 filter: function (feature) { 3113 if (!feature || !feature.geometry) return true; 3114 var typ = feature.geometry.type; 3115 if (typ === "Point") { 3116 var gem = gemeindeFuerFeature(feature); 3117 gemeindeAnzahl[gem] = (gemeindeAnzahl[gem] || 0) + 1; 3118 return gemeindeSichtbar(gem); 3119 } 3120 if (typ === "LineString" || typ === "MultiLineString") { 3121 return gemeindenFuerLinie(feature).some(gemeindeSichtbar); 3122 } 3123 return true; // Flächen: derzeit nicht eingeschränkt 3124 }, 3125 pointToLayer: function (feature, latlng) { 3126 var p = feature.properties || {}; 3127 var name = p.name || p.title || ""; 3128 return punktMarker(latlng, punktFarbe(feature), 3129 iconInfo(feature, e.bild, name || e.name), 3130 name, dauerhaft); 3131 }, 3132 style: function (feature) { 3133 return { 3134 color: punktFarbe(feature), 3135 weight: LINIEN_BREITE, 3136 opacity: 1, 3137 lineCap: "round", 3138 lineJoin: "round", 3139 fillOpacity: .25 3140 }; 3141 }, 3142 onEachFeature: function (feature, objekt) { 3143 var p = feature.properties || {}; 3144 var name = p.name || p.title || ""; 3145 var beschreibungRoh = p.description || p.beschreibung || ""; 3146 var inhalt = popupInhalt({ 3147 name: name || e.name, 3148 adresse: p.adresse || p.address || "", 3149 info: beschreibungRoh 3150 }, punktFarbe(feature)); 3151 3152 objekt.bindPopup(inhalt, popupOptionen()); 3153 3154 // ----- Linien leichter treffen und beschriften ----- 3155 if (istLinie(feature) && objekt.getLatLngs) { 3156 var hilfe = L.polyline(objekt.getLatLngs(), { 3157 color: punktFarbe(feature), opacity: 0, weight: KLICK_BREITE, 3158 lineCap: "round", lineJoin: "round", interactive: true 3159 }); 3160 hilfe.bindPopup(inhalt, popupOptionen()); 3161 if (txt(name)) { 3162 hilfe.bindTooltip(esc(txt(name)), { 3163 sticky: true, direction: "top", offset: [0, -8], 3164 opacity: 1, className: "bwk-linien-name" 3165 }); 3166 } 3167 hilfe.on("mouseover", function () { 3168 try { objekt.setStyle({ weight: LINIEN_BREITE_HOVER }); } catch (er) { } 3169 if (objekt.bringToFront) objekt.bringToFront(); 3170 }); 3171 hilfe.on("mouseout", function () { 3172 try { objekt.setStyle({ weight: LINIEN_BREITE }); } catch (er) { } 3173 }); 3174 hilfen.push(hilfe); 3175 } 3176 3177 anzahl++; 3178 } 3179 }); 3180 layer.addLayer(geo); 3181 // die unsichtbaren Streifen zuletzt: sie liegen dann oben 3182 // und fangen den Klick zuverlässig ab
3183 hilfen.forEach(function (h) { layer.addLayer(h); }); 3184 } catch (fehler) { 3185 console.warn("[Karte] Ebene \"" + e.name + "\" nicht zeichenbar:", fehler); 3186 } 3187 e._gemeindeAnzahl = gemeindeAnzahl; 3188 zaehlerSetzen(e, anzahl); 3189 gemeindeZaehlerAktualisieren(); 3190 return anzahl; 3191 } 3192 3193 /* ========================================================= 3194 10) LISTENSEITE DER VERANSTALTUNGEN 3195 Die Seite zeigt Karten (.bemCard--list) statt einer Tabelle 3196 und blättert über ein Formular (Pager-Feld + Klick auf 3197 "javascript:void(0)"-Links), nicht über die Adresszeile. 3198 Der Code liest darum jedes Mal live nach: 3199 - welches Feld die Seitenzahl trägt (Feldname "pager-â¦"), 3200 - wohin das Formular schickt (form.action), 3201 - ob es eine nächste Seite gibt (letztes Element der 3202 Paginierung, Attribut "disabled"). 3203 Nichts davon ist fest verdrahtet, damit spätere kleine 3204 Ãnderungen an der Liste (neue Feld-ID, anderer Wortlaut) 3205 die Karte nicht gleich wieder lahmlegen. 3206 ========================================================= */ 3207 3208 // Formularfeld einer Karte anhand seiner sichtbaren Beschriftung 3209 // (".sr-only"-Text) auslesen, unabhängig von Klassennamen 3210 function feldWert(karte, label) { 3211 var lis = karte.querySelectorAll(".bemListContainer--contactList li.bemList__item"); 3212 for (var i = 0; i < lis.length; i++) { 3213 var sr = lis[i].querySelector(".sr-only"); 3214 if (!sr || txt(sr.textContent).toLowerCase() !== label.toLowerCase()) continue; 3215 var wert = lis[i].querySelector(".bemText__value"); 3216 if (wert) return txt(wert.textContent); 3217 var link = lis[i].querySelector("a"); 3218 if (link) return txt(link.textContent); 3219 return txt(lis[i].textContent).replace(txt(sr.textContent), "").trim(); 3220 } 3221 return ""; 3222 } 3223 3224 // Koordinaten, die direkt in der Karte stehen (Feld "Entfernung 3225 // (Luftlinie)" trägt data-lat/data-lon). 0/0 heiÃt: nicht gesetzt. 3226 function koordinatenAusKarte(karte) { 3227 var li = karte.querySelector(".bemDistanceCalculation[data-lat]"); 3228 if (!li) return null; 3229 var lat = parseFloat(li.getAttribute("data-lat")); 3230 var lng = parseFloat(li.getAttribute("data-lon")); 3231 if (!lat || !lng) return null; 3232 if (!imBereich(lat, lng)) return null; 3233 return [lat, lng]; 3234 } 3235 3236 function absoluteUrl(pfad) { 3237 if (!pfad) return ""; 3238 try { return new URL(pfad, location.href).href; } catch (e) { return pfad; } 3239 } 3240 3241 // eine einzelne Veranstaltungskarte auslesen 3242 function leseKarte(karte) { 3243 var titelFeld = karte.querySelector(".bemHeaderContainer .bemHeader--h5"); 3244 var titel = titelFeld ? txt(titelFeld.textContent) : ""; 3245 if (!titel) return null; 3246 3247 var linkFeld = karte.querySelector(".bemButtonContainer a.bemLink-detail"); 3248 var link = linkFeld ? absoluteUrl(linkFeld.getAttribute("href")) : ""; 3249 3250 var datumFeld = karte.querySelector(".bemContainer--date"); 3251 var datumMatch = datumFeld ? txt(datumFeld.textContent).match(/\d{1,2}\.\d{1,2}\.\d{2,4}/) : null; 3252 var datum = datumMatch ? datumMatch[0] : ""; 3253 3254 var zeitFeld = karte.querySelector(".bemContainer--time"); 3255 var zeit = zeitFeld ? txt(txt(zeitFeld.textContent).replace(/^Uhrzeit der Veranstaltung/i, "")) : ""; 3256 3257 var quelleFeld = karte.querySelector(".card-footer .bemContainer--source"); 3258 var ort = quelleFeld ? txt(txt(quelleFeld.textContent).replace(/^Datenquelle/i, "")) : ""; 3259 3260 return { 3261 titel: titel, 3262 link: link, 3263 datum: datum, 3264 zeit: zeit, 3265 ort: ort, 3266 adresse: feldWert(karte, "Adresse"), 3267 standort: feldWert(karte, "Standort"), 3268 koordinaten: koordinatenAusKarte(karte) 3269 }; 3270 } 3271 3272 function leseKarten(doc) { 3273 var raus = []; 3274 doc.querySelectorAll(".bemCard.bemCard--list").forEach(function (karte) { 3275 var eintrag = leseKarte(karte); 3276 if (eintrag) raus.push(eintrag); 3277 }); 3278 return raus; 3279 } 3280 3281 // das Formular finden, das die Seitenzahl trägt â über das 3282 // Pager-Feld selbst, nicht über eine feste Formular-ID 3283 function pagerFormular(doc) { 3284 var pagerFeld = doc.querySelector('input[id^="pager-"]'); 3285 return pagerFeld ? pagerFeld.closest("form") : null; 3286 } 3287 3288 // Wert der "nächste Seite"-Schaltfläche (letztes Element der 3289 // Paginierung); null, wenn sie ausgegraut/nicht vorhanden ist 3290 function naechsteSeite(doc) { 3291 var elemente = doc.querySelectorAll(".pagination .page-item"); 3292 if (!elemente.length) return null; 3293 var letztes = elemente[elemente.length - 1]; 3294 if (letztes.classList.contains("disabled")) return null; 3295 var a = letztes.querySelector("a[data-filterValue]"); 3296 return a ? a.getAttribute("data-filterValue") : null; 3297 } 3298 3299 function ladeVeranstaltungsSeite(url, formularDaten) { 3300 var optionen = { credentials: "same-origin" }; 3301 if (formularDaten != null) { 3302 optionen.method = "POST"; 3303 optionen.headers = { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" }; 3304 optionen.body = formularDaten; 3305 } 3306 return fetch(url, optionen) 3307 .then(function (r) { return r.text(); }) 3308 .then(function (html) { return new DOMParser().parseFromString(html, "text/html"); }); 3309 } 3310 3311 // lädt Seite 1 und blättert dann über das Formular weiter, bis 3312 // die Paginierung keine nächste Seite mehr anbietet 3313 function ladeAlleSeiten() { 3314 return ladeVeranstaltungsSeite(VA_URL, null).then(function (doc0) { 3315 var alle = leseKarten(doc0); 3316 var form = pagerFormular(doc0); 3317 if (!form) return alle; 3318 3319 var aktionUrl = absoluteUrl(form.getAttribute("action")); 3320 var pagerFeld = form.querySelector('input[id^="pager-"]'); 3321 var pagerName = pagerFeld ? pagerFeld.getAttribute("name") : ""; 3322 3323 function weiter(wert, uebrig) { 3324 if (wert == null || !pagerName || uebrig <= 0) return Promise.resolve(); 3325 var daten = new FormData(form); 3326 daten.set(pagerName, wert); 3327 return ladeVeranstaltungsSeite(aktionUrl, new URLSearchParams(daten).toString()) 3328 .then(function (docN) { 3329 var neue = leseKarten(docN);
3330 if (!neue.length) return; 3331 alle = alle.concat(neue); 3332 return weiter(naechsteSeite(docN), uebrig - 1); 3333 }); 3334 } 3335 3336 return weiter(naechsteSeite(doc0), VA_MAX_SEITEN).then(function () { return alle; }); 3337 }).catch(function (e) { 3338 console.warn("[Karte] Veranstaltungsliste konnte nicht geladen werden:", e); 3339 return []; 3340 }); 3341 } 3342 3343 /* ========================================================= 3344 11) ORTE BESTIMMEN 3345 Viele Karten liefern die Koordinate schon direkt mit 3346 (koordinatenAusKarte). Fehlt sie, wird wie bisher zuerst 3347 die interne Detailseite (Lageplan-Link), danach eine 3348 Adresssuche über Nominatim versucht. 3349 ========================================================= */ 3350 3351 function istIntern(url) { return url && url.indexOf(location.origin) === 0; } 3352 3353 function holeDoc(url) { 3354 return fetch(url, { credentials: "same-origin" }) 3355 .then(function (r) { return r.text(); }) 3356 .then(function (html) { return new DOMParser().parseFromString(html, "text/html"); }); 3357 } 3358 3359 function ausVerzeichnis(schluessel) { 3360 if (schluessel.indexOf("ort:") !== 0) return null; 3361 var k = schluessel.slice(4); 3362 return ORTE[k] || ORTE[k.split("@")[0]] || null; 3363 } 3364 3365 function leseAdresse(doc, ortsname) { 3366 var roh = ""; 3367 var karteLink = Array.prototype.find.call(doc.querySelectorAll("a"), function (a) { 3368 return txt(a.textContent).toLowerCase() === "zur karte"; 3369 }); 3370 if (karteLink && karteLink.parentElement) { 3371 roh = txt(karteLink.parentElement.textContent).replace(/\|?\s*zur\s*Karte\s*$/i, ""); 3372 } 3373 if (!roh) { 3374 var m = txt(doc.body.textContent) 3375 .match(/([A-Za-zÃÃÃäöüÃ.\-/ ]{2,40}\s\d+[a-zA-Z]?,\s*\d{4}\s+[A-Za-zÃÃÃäöüÃ.\- ]{2,40})/); 3376 if (m) roh = txt(m[1]); 3377 } 3378 if (ortsname && roh.toLowerCase().indexOf(ortsname.toLowerCase()) === 0) { 3379 roh = txt(roh.slice(ortsname.length)); 3380 } 3381 return roh.replace(/^[,|\s]+/, ""); 3382 } 3383 3384 function koordinatenAusLageplan(doc) { 3385 var link = doc.querySelector('a[href*="digitalmaps.aspx"]'); 3386 if (!link) return Promise.resolve(null); 3387 return fetch(link.href, { credentials: "same-origin" }) 3388 .then(function (r) { return r.text(); }) 3389 .then(function (html) { 3390 var m = html.match(/(4[5-9]\.\d{4,})\D{1,25}?(\d{1,2}\.\d{4,})/); 3391 if (!m) return null; 3392 var lat = parseFloat(m[1]), lng = parseFloat(m[2]); 3393 return imBereich(lat, lng) ? [lat, lng] : null; 3394 }) 3395 .catch(function () { return null; }); 3396 } 3397 3398 function koordinatenAusAdresse(begriff) { 3399 if (!begriff) return Promise.resolve(null); 3400 var url = "https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=1" + 3401 "&countrycodes=at,de&q=" + encodeURIComponent(begriff); 3402 return fetch(url, { headers: { "Accept": "application/json" } }) 3403 .then(function (r) { return r.json(); }) 3404 .then(function (j) { 3405 if (!j || !j.length) return null; 3406 var t = j[0]; 3407 var lat = parseFloat(t.lat), lng = parseFloat(t.lon); 3408 if (!imBereich(lat, lng)) return null; 3409 if (NUR_GENAUE_ORTE) { 3410 var grob = (t.class === "place" || t.class === "boundary") && 3411 !(t.address && t.address.house_number); 3412 if (grob) return null; 3413 } 3414 return [lat, lng]; 3415 }) 3416 .catch(function () { return null; }); 3417 } 3418 3419 function ausDetailseite(g) { 3420 if (!g.detailLink) return Promise.resolve(false); 3421 return holeDoc(g.detailLink).then(function (doc) { 3422 if (!g.adresse) g.adresse = leseAdresse(doc, g.viaLink ? "" : g.name); 3423 if (g.adresse && !g.gemeinde) g.gemeinde = erkenneGemeinde(g.adresse); 3424 return koordinatenAusLageplan(doc); 3425 }).then(function (koord) { 3426 if (!koord) return false; 3427 g.ort = { name: g.name, adresse: g.adresse || "", 3428 lat: +koord[0].toFixed(6), lng: +koord[1].toFixed(6) }; 3429 return true; 3430 }).catch(function () { return false; }); 3431 } 3432 3433 function ausAdresssuche(g) { 3434 var begriffe = []; 3435 if (g.adresse) begriffe.push(g.adresse + ", Ãsterreich"); 3436 if (g.name) begriffe.push(g.name + (g.gemeinde ? ", " + g.gemeinde : ", Bregenzerwald") + ", Vorarlberg"); 3437 if (!begriffe.length) return Promise.resolve(false); 3438 3439 function versuch(i) { 3440 if (i >= begriffe.length) return Promise.resolve(false); 3441 return schlafe(PAUSE_ADRESSSUCHE) 3442 .then(function () { return koordinatenAusAdresse(begriffe[i]); }) 3443 .then(function (koord) { 3444 if (!koord) return versuch(i + 1); 3445 g.ort = { name: g.name, adresse: g.adresse || "", 3446 lat: +koord[0].toFixed(6), lng: +koord[1].toFixed(6) }; 3447 return true; 3448 }); 3449 } 3450 return versuch(0); 3451 } 3452 3453 /* ========================================================= 3454 12) ABLAUF DER VERANSTALTUNGEN 3455 Jede Karte ist bereits ein einzelner Termin (eigenes Datum, 3456 eigene Uhrzeit). Termine am selben Ort werden hier zu einem 3457 Kartenpunkt mit mehreren Terminen zusammengefasst. 3458 ========================================================= */ 3459 3460 function starteTermine() { 3461 var ziel = findeEbene("va-kalender"); 3462 if (!ziel) return; 3463 3464 var gespeichert = speicherLesen(CACHE_TERMINE); 3465 var frisch = gespeichert && gespeichert.zeit && 3466 (Date.now() - gespeichert.zeit) < CACHE_STUNDEN * 3600000; 3467 3468 if (gespeichert && gespeichert.punkte && gespeichert.punkte.length) { 3469 setzePunkte(ziel, gespeichert.punkte); 3470 if (frisch) return; 3471 var gleich = function () { aktualisiere(ziel); }; 3472 if (window.requestIdleCallback) requestIdleCallback(gleich, { timeout: 4000 }); 3473 else setTimeout(gleich, 1000); 3474 } else { 3475 aktualisiere(ziel); 3476 } 3477 } 3478 3479 // eindeutiger Schlüssel für den physischen Ort eines Termins: 3480 // Standort/Adresse (+ Gemeinde), sonst als letzter Rückgriff 3481 // die Gemeinde allein 3482 function veranstaltungsSchluessel(e) { 3483 var basis = e.standort || e.adresse || e.ort || e.titel; 3484 var gem = e.ort || erkenneGemeinde(e.adresse, e.standort, e.titel); 3485 return "ort:" + normalisiere(basis) + (gem ? "@" + normalisiere(gem) : ""); 3486 } 3487 3488 // eine der 24 Filter-Gemeinden für einen Veranstaltungseintrag: 3489 // zuerst die "Datenquelle" der Karte (exakt und zuverlässig), 3490 // dann die echte Gemeindegrenze anhand der Koordinate (falls schon 3491 // geladen und die Karte eine Koordinate mitliefert), zuletzt wie 3492 // gehabt über Adresse/Standort/Titel geraten 3493 function gemeindeFuerEintrag(e) { 3494 var exakt = gemeindeVonName(e.ort); 3495 if (exakt) return exakt;
3496 if (GRENZEN_GELADEN && e.koordinaten) { 3497 var perKoordinate = gemeindeAusKoordinaten(e.koordinaten[0], e.koordinaten[1]); 3498 if (perKoordinate) return perKoordinate; 3499 } 3500 var perText = gemeindeKanonisch(erkenneGemeinde(e.adresse, e.standort, e.titel, e.ort)); 3501 return perText || GEMEINDE_AUSSERHALB; // nie leer: sonst "immer sichtbar" 3502 } 3503 3504 function aktualisiere(ziel) { 3505 var ortsCache = speicherLesen(CACHE_ORTE) || {}; 3506 3507 ladeAlleSeiten().then(function (eintraege) { 3508 var gruppen = {}, reihenfolge = []; 3509 3510 eintraege.forEach(function (e) { 3511 var k = veranstaltungsSchluessel(e); 3512 if (!gruppen[k]) { 3513 gruppen[k] = { 3514 name: e.standort || e.ort || e.titel, 3515 viaLink: !e.standort, 3516 gemeinde: gemeindeFuerEintrag(e), 3517 detailLink: istIntern(e.link) ? e.link : "", 3518 adresse: e.adresse || "", ort: null, termine: [] 3519 }; 3520 reihenfolge.push(k); 3521 } 3522 var g = gruppen[k]; 3523 if (!g.detailLink && istIntern(e.link)) g.detailLink = e.link; 3524 if (!g.adresse && e.adresse) g.adresse = e.adresse; 3525 if (!g.gemeinde) g.gemeinde = gemeindeFuerEintrag(e); 3526 if (!g.ort && e.koordinaten) { 3527 g.ort = { name: g.name, adresse: g.adresse || "", 3528 lat: e.koordinaten[0], lng: e.koordinaten[1] }; 3529 } 3530 var terminDatum = e.datum + (e.zeit ? " " + e.zeit : ""); 3531 var schon = g.termine.some(function (t) { return t.titel === e.titel && t.datum === terminDatum; }); 3532 if (!schon) g.termine.push({ titel: e.titel, datum: terminDatum, link: e.link }); 3533 }); 3534 3535 var offeneDetail = [], jetzt = Date.now(); 3536 reihenfolge.forEach(function (k) { 3537 var g = gruppen[k]; 3538 if (g.ort) return; // Koordinate stand schon in der Liste 3539 var fest = ausVerzeichnis(k); 3540 if (fest) { g.ort = fest; return; } 3541 var bekannt = ortsCache[k]; 3542 if (bekannt && typeof bekannt.lat === "number" && 3543 (jetzt - bekannt.zeit) < ORT_TAGE * 86400000) { g.ort = bekannt; return; } 3544 if (bekannt && typeof bekannt.lat !== "number" && 3545 (jetzt - bekannt.zeit) < FEHLVERSUCH_TAGE * 86400000) { return; } 3546 offeneDetail.push(k); 3547 }); 3548 3549 zeichne(ziel, reihenfolge, gruppen); 3550 3551 return gruppenweise(offeneDetail, DETAIL_PARALLEL, function (k) { 3552 return ausDetailseite(gruppen[k]).then(function (ok) { 3553 if (ok) merke(ortsCache, k, gruppen[k]); 3554 }); 3555 }).then(function () { 3556 zeichne(ziel, reihenfolge, gruppen); 3557 speicherSchreiben(CACHE_ORTE, ortsCache); 3558 3559 var rest = offeneDetail.filter(function (k) { return !gruppen[k].ort; }) 3560 .slice(0, NEUE_ORTE_PRO_MAL); 3561 return naechster(rest); 3562 3563 function naechster(liste) { 3564 if (!liste.length) return Promise.resolve(); 3565 var k = liste.shift(); 3566 return ausAdresssuche(gruppen[k]).then(function (ok) { 3567 merke(ortsCache, k, gruppen[k]); 3568 if (ok) zeichne(ziel, reihenfolge, gruppen); 3569 speicherSchreiben(CACHE_ORTE, ortsCache); 3570 return naechster(liste); 3571 }).catch(function () { return naechster(liste); }); 3572 } 3573 }).then(function () { 3574 zeichne(ziel, reihenfolge, gruppen); 3575 speicherSchreiben(CACHE_ORTE, ortsCache); 3576 letzteOffene = reihenfolge.filter(function (k) { return !gruppen[k].ort; }) 3577 .map(function (k) { 3578 return { name: gruppen[k].name, gemeinde: gruppen[k].gemeinde || "?", 3579 termine: gruppen[k].termine.length, schluessel: k }; 3580 }); 3581 if (letzteOffene.length) { 3582 console.info("[Karte] " + letzteOffene.length + 3583 " Veranstaltungsorte ohne Koordinaten â Liste über bwkOffeneOrte()"); 3584 } 3585 }); 3586 }).catch(function (e) { 3587 console.warn("[Karte] Termine konnten nicht geladen werden:", e); 3588 }); 3589 } 3590 3591 function gruppenweise(liste, breite, arbeit) { 3592 var rest = liste.slice(); 3593 function block() { 3594 if (!rest.length) return Promise.resolve(); 3595 var teil = rest.splice(0, breite); 3596 return Promise.all(teil.map(function (x) { 3597 return arbeit(x).catch(function () { });
3598 })).then(block); 3599 } 3600 return block(); 3601 } 3602 3603 function merke(cache, k, g) { 3604 cache[k] = g.ort 3605 ? { name: g.ort.name, adresse: g.ort.adresse, lat: g.ort.lat, lng: g.ort.lng, 3606 gemeinde: g.gemeinde || "", zeit: Date.now() } 3607 : { name: g.name, gemeinde: g.gemeinde || "", zeit: Date.now() }; 3608 } 3609 3610 function zeichne(ziel, reihenfolge, gruppen) { 3611 var nachPunkt = {}, punkte = []; 3612 3613 reihenfolge.forEach(function (k) { 3614 var g = gruppen[k]; 3615 if (!g.ort) return; 3616 var pk = g.ort.lat + "|" + g.ort.lng; 3617 if (!nachPunkt[pk]) { 3618 nachPunkt[pk] = { name: g.ort.name || g.name, adresse: g.ort.adresse || "", 3619 lat: g.ort.lat, lng: g.ort.lng, gemeinde: g.gemeinde || "", 3620 termine: [] }; 3621 punkte.push(nachPunkt[pk]); 3622 } 3623 g.termine.forEach(function (t) { 3624 var schon = nachPunkt[pk].termine.some(function (x) { 3625 return x.titel === t.titel && x.datum === t.datum; 3626 }); 3627 if (!schon) nachPunkt[pk].termine.push(t); 3628 }); 3629 }); 3630 3631 setzePunkte(ziel, punkte); 3632 speicherSchreiben(CACHE_TERMINE, { zeit: Date.now(), punkte: punkte }); 3633 } 3634 3635 /* ---------- Karte zur gewählten Gemeinde bewegen ---------- 3636 Läuft bei jeder Ãnderung im Gemeinde-Filter. Nutzt die schon 3637 geladenen echten Gemeindegrenzen (GEMEINDE_GRENZEN), um die 3638 Karte auf alle gerade angehakten Gemeinden gemeinsam 3639 einzupassen. Ist noch keine Gemeinde angehakt oder liegen die 3640 Grenzen noch nicht vor, bleibt die Karte einfach, wo sie ist. ---------- */ 3641 3642 function grenzeAlsPunkte(geo) { 3643 if (!geo) return null; 3644 var punkte = []; 3645 function ausRing(ring) { ring.forEach(function (p) { punkte.push([p[1], p[0]]); }); } 3646 function ausPolygon(poly) { poly.forEach(ausRing); } 3647 if (geo.type === "Polygon") ausPolygon(geo.coordinates); 3648 else if (geo.type === "MultiPolygon") geo.coordinates.forEach(ausPolygon); 3649 return punkte.length ? punkte : null; 3650 } 3651 3652 // "AuÃerhalb vom Bregenzerwald" hat keine eigene Grenze â dafür 3653 // grob die Ausdehnung von Vorarlberg, damit die Karte dort 3654 // wenigstens sinnvoll hinauszoomt statt gar nichts zu tun 3655 var VORARLBERG_ECKEN = [[46.83, 9.47], [47.62, 10.30]]; 3656 3657 function gemeindeKartePassen() { 3658 if (!karte) return; 3659 var aktive = GEMEINDE_ANZEIGE.filter(function (g) { return GEMEINDE_STAND[g] !== false; }); 3660 if (!aktive.length) return; 3661 3662 var bounds = null; 3663 aktive.forEach(function (g) { 3664 var punkte = (g === GEMEINDE_AUSSERHALB) ? VORARLBERG_ECKEN : grenzeAlsPunkte(GEMEINDE_GRENZEN[g]); 3665 if (!punkte) return; 3666 if (!bounds) bounds = L.latLngBounds(punkte); 3667 else bounds.extend(punkte); 3668 }); 3669 if (!bounds || !bounds.isValid()) return; 3670 karte.flyToBounds(bounds, { padding: [30, 30], maxZoom: 15, duration: .6 }); 3671 } 3672 3673 /* ========================================================= 3674 13) HILFEN FÃR DIE REDAKTION (Konsole) 3675 ========================================================= */ 3676 3677 window.bwkVollbild = function (an) { 3678 if (an === false) vollbildAus(); 3679 else if (an === true) vollbildEin(); 3680 else vollbildSchalten(); 3681 return vollbildAn ? "Vollbild an" : "Vollbild aus"; 3682 }; 3683 3684 // zeigt, was in den Markern tatsächlich steckt 3685 window.bwkMarkerPruefen = function () { 3686 var pins = document.querySelectorAll(".bwk-pin"); 3687 if (!pins.length) return "Keine Marker im Dokument gefunden."; 3688 var mit = 0, ohne = 0; 3689 Array.prototype.forEach.call(pins, function (p) { 3690 if (p.querySelector("g, image")) mit++; else ohne++; 3691 }); 3692 var erste = pins[0]; 3693 var svg = erste.querySelector("svg"); 3694 var masse = svg ? svg.getBoundingClientRect() : null; 3695 console.log("Marker gesamt: " + pins.length + ", mit Symbol: " + mit + ", ohne: " + ohne); 3696 if (masse) console.log("GröÃe des ersten Markers: " + 3697 Math.round(masse.width) + " x " + Math.round(masse.height) + " px"); 3698 console.log(erste.innerHTML.slice(0, 500)); 3699 return mit + " von " + pins.length + " Markern tragen ein Symbol"; 3700 }; 3701 3702 window.bwkOrteExportieren = function () { 3703 var cache = speicherLesen(CACHE_ORTE) || {}, gefunden = {}, ohne = []; 3704 Object.keys(cache).forEach(function (k) { 3705 var s = cache[k];
3706 if (!s || typeof s.lat !== "number") { ohne.push(s && s.name ? s.name : k); return; } 3707 if (k.indexOf("ort:") !== 0) return; 3708 gefunden[k.slice(4)] = '{ name: "' + String(s.name || "").replace(/"/g, "'") + 3709 '", adresse: "' + String(s.adresse || "").replace(/"/g, "'") + 3710 '", lat: ' + s.lat + ", lng: " + s.lng + " }"; 3711 }); 3712 var zeilen = Object.keys(gefunden).sort().map(function (k) { 3713 return ' "' + k + '": ' + gefunden[k]; 3714 }).join(",\n"); 3715 var ausgabe = " var ORTE = {\n" + zeilen + "\n };"; 3716 if (ohne.length) ausgabe += "\n\n /* ohne Koordinaten:\n " + ohne.join("\n ") + "\n */"; 3717 console.log(ausgabe); 3718 try { copy(ausgabe); } catch (e) { } 3719 return Object.keys(gefunden).length + " Orte, " + ohne.length + " offen"; 3720 }; 3721 3722 window.bwkOffeneOrte = function () { 3723 if (!letzteOffene.length) return "Alles verortet (oder noch am Laden)."; 3724 console.table(letzteOffene); 3725 return letzteOffene.length + " Bezeichnungen ohne Koordinaten"; 3726 }; 3727 3728 window.bwkSymbolePruefen = function () { 3729 var adresse = kulturAdresse(); 3730 if (!adresse) return "Keine KULTUR_FILEID gesetzt."; 3731 return fetch(adresse, { credentials: "same-origin", cache: "no-store" }) 3732 .then(function (r) { return r.json(); }) 3733 .then(function (d) { 3734 if (d && d.uri) { 3735 try { UMAP_SERVER = new URL(d.uri).origin.replace(/^http:/i, "https:"); } catch (e) { } 3736 } 3737 ebenenBericht(d); 3738 var gefunden = []; 3739 (function durch(liste) { 3740 (liste || []).forEach(function (l) { 3741 var u = txt(opt(l, "iconUrl", "")); 3742 if (u && gefunden.indexOf(u) === -1) gefunden.push(u); 3743 if (l.layers) durch(l.layers); 3744 }); 3745 })(d.layers); 3746 if (!gefunden.length) { console.log("Keine iconUrl in der Datei."); return; } 3747 gefunden.forEach(function (u) { 3748 bildAdressen(u).forEach(function (adr) { 3749 if (/^data:/i.test(adr)) return; 3750 var bild = new Image(); 3751 bild.onload = function () { console.log("OK " + adr); }; 3752 bild.onerror = function () { console.warn("FEHLT " + adr); }; 3753 bild.src = adr; 3754 }); 3755 }); 3756 }); 3757 }; 3758 3759 window.bwkKulturPruefen = function () { 3760 var adresse = kulturAdresse(); 3761 if (!adresse) return "Keine KULTUR_FILEID gesetzt."; 3762 return fetch(adresse, { credentials: "same-origin", cache: "no-store" }) 3763 .then(function (r) { return r.text().then(function (t) { return { status: r.status, text: t }; }); }) 3764 .then(function (a) { 3765 console.log("HTTP " + a.status + ", " + a.text.length + " Zeichen"); 3766 try { ebenenBericht(JSON.parse(a.text)); } 3767 catch (e) { console.warn("Kein gültiges JSON:", e.message); } 3768 }); 3769 }; 3770 3771 window.bwkGrenzenPruefen = function () { 3772 var zeilen = GEMEINDE_FILTER.map(function (g) { 3773 var geo = GEMEINDE_GRENZEN[g]; 3774 var ringe = 0; 3775 if (geo && geo.type === "Polygon") ringe = geo.coordinates.length; 3776 if (geo && geo.type === "MultiPolygon") ringe = geo.coordinates.reduce(function (s, p) { return s + p.length; }, 0); 3777 return { Gemeinde: g, Grenze: geo ? geo.type : "(fehlt)", Ringe: ringe || "" }; 3778 }); 3779 if (console.table) console.table(zeilen); else console.log(zeilen); 3780 return (GRENZEN_GELADEN ? "geladen: " : "lädt noch ⦠") + 3781 Object.keys(GEMEINDE_GRENZEN).length + " von " + GEMEINDE_FILTER.length; 3782 }; 3783 3784 window.bwkGemeindenPruefen = function () { 3785 var zeilen = GEMEINDE_ANZEIGE.map(function (g) { 3786 return { Gemeinde: g, aktiv: GEMEINDE_STAND[g] !== false, 3787 Anzahl: (GEMEINDE_ZEILEN[g] && GEMEINDE_ZEILEN[g].anzahlFeld.textContent) || 0 }; 3788 }); 3789 if (console.table) console.table(zeilen); else console.log(zeilen); 3790 return zeilen.length + " Gemeinden im Filter"; 3791 }; 3792 3793 window.bwkVeranstaltungenPruefen = function () { 3794 return ladeAlleSeiten().then(function (eintraege) { 3795 var mitKoordinate = eintraege.filter(function (e) { return e.koordinaten; }).length; 3796 console.info("[Karte] " + eintraege.length + " Veranstaltungseinträge gelesen, " + 3797 mitKoordinate + " davon mit Koordinate direkt aus der Liste.");
3798 if (console.table) console.table(eintraege.slice(0, 30)); 3799 return eintraege.length + " Einträge (siehe Konsole)"; 3800 }); 3801 }; 3802 3803 window.bwkZuruecksetzen = function () { 3804 try { 3805 window.localStorage.removeItem(CACHE_ORTE); 3806 window.localStorage.removeItem(CACHE_TERMINE); 3807 } catch (e) { } 3808 return "Speicher geleert â Seite neu laden."; 3809 }; 3810 3811 if (document.readyState === "complete" || document.readyState === "interactive") start(); 3812 else document.addEventListener("DOMContentLoaded", start); 3813})(); 3814</script>
3814</div> 3815<style> 3816.karte-button { 3817 display: inline-flex !important; 3818 align-items: center !important; 3819 gap: .6rem !important; 3820 padding: .8rem 1.1rem !important; 3821 background: #fff !important; 3822 border: 1px solid rgba(38,48,39,.12) !important; 3823 border-radius: 8px !important; 3824 color: #536B45 !important; 3825 font-size: .9rem !important; 3826 font-weight: 600 !important; 3827 text-decoration: none !important; 3828 transition: all .25s ease !important; 3829} 3830 3831.karte-button:hover { 3832 background: #2a7c30 !important; 3833 border-color: #4D882a !important; 3834 color: #fff !important; 3835 transform: translateY(-3px) !important; 3836 box-shadow: 0 6px 14px rgba(38,48,39,.15) !important; 3837} 3838 3839.karte-button span { 3840 font-size: 1.1rem !important; 3841 line-height: 1 !important; 3842} 3843</style> 3844 3845<p style="position:relative;clear:both;margin:0 0 2rem 0!important;text-align:center!important;"> 3846 <a href="https://www.regiobregenzerwald.at/Karte" class="karte-button extlink"> 3847 Gesamte Karte 3848 <span>›</span> 3849 3850 </a> 3851</p></div></div><div class="box2042 section section__event"><div class="box2042 wrapper"><div class="titel"><h2> 3852 Veranstaltungen | Termine 3853 </h2><span class="titel_seperator"></span></div><div class="event"><div class="boxVeranstaltungsvorschau"> 3854 <ul> 3855 <li> 3856 <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet"> 3857 <span class="boxVeranstaltungsvorschauDatum"> 3858 <span class="boxVeranstaltungsvorschauDatumTag">02</span> 3859 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 3860 <abbr title="Oktober">Okt</abbr> 3861 </span> 3862 </span> 3863 </a>
3864 <span class="boxVeranstaltungsvorschauTextBlock"> 3865 <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet"> 3866 <span class="boxVeranstaltungsvorschauText"> 3867 <span class="boxVeranstaltungsvorschauTitel"> 3868 <span class="boxVeranstaltungsvorschauTag">Heute</span> 3869 <h2>Dorfbücherei hat geöffnet</h2> 3870 </span> 3871 </span> 3872 </a> 3873 <span class="boxVeranstaltungsvorschauOrtBlock"> 3874 <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet"> 3875 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 3876 <span class="boxVeranstaltungsvorschauTime">08:30 - 10:30 Uhr</span> 3877 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 3878 </span> 3879 </a> 3880 </span> 3881 </span> 3882 <div class="clear"> 3883 </div> 3884 </li> 3885 <li> 3886 <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige"> 3887 <span class="boxVeranstaltungsvorschauDatum"> 3888 <span class="boxVeranstaltungsvorschauDatumTag">02</span> 3889 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 3890 <abbr title="Oktober">Okt</abbr> 3891 </span> 3892 </span> 3893 </a>
3894 <span class="boxVeranstaltungsvorschauTextBlock"> 3895 <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige"> 3896 <span class="boxVeranstaltungsvorschauText"> 3897 <span class="boxVeranstaltungsvorschauTitel"> 3898 <span class="boxVeranstaltungsvorschauTag">Heute</span> 3899 <h2>AusZeit für mich - für pflegende Angehörige</h2> 3900 </span> 3901 </span> 3902 </a> 3903 <span class="boxVeranstaltungsvorschauOrtBlock"> 3904 <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige"> 3905 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 3906 <span class="boxVeranstaltungsvorschauTime">09:30 - 16:30 Uhr</span> 3907 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 3908 </span> 3909 </a> 3910 </span> 3911 </span> 3912 <div class="clear"> 3913 </div> 3914 </li> 3915 <li> 3916 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3917 <span class="boxVeranstaltungsvorschauDatum"> 3918 <span class="boxVeranstaltungsvorschauDatumTag">02</span> 3919 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 3920 <abbr title="Oktober">Okt</abbr> 3921 </span> 3922 </span> 3923 </a>
3924 <span class="boxVeranstaltungsvorschauTextBlock"> 3925 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3926 <span class="boxVeranstaltungsvorschauText"> 3927 <span class="boxVeranstaltungsvorschauTitel"> 3928 <span class="boxVeranstaltungsvorschauTag">Heute</span> 3929 <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2> 3930 </span> 3931 </span> 3932 </a> 3933 <span class="boxVeranstaltungsvorschauOrtBlock"> 3934 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3935 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 3936 <span class="boxVeranstaltungsvorschauTime">17:00 - 20:00 Uhr</span> 3937 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 3938 </span> 3939 </a> 3940 </span> 3941 </span> 3942 <div class="clear"> 3943 </div> 3944 </li> 3945 <li> 3946 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3947 <span class="boxVeranstaltungsvorschauDatum"> 3948 <span class="boxVeranstaltungsvorschauDatumTag">03</span> 3949 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 3950 <abbr title="Oktober">Okt</abbr> 3951 </span> 3952 </span> 3953 </a>
3954 <span class="boxVeranstaltungsvorschauTextBlock"> 3955 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3956 <span class="boxVeranstaltungsvorschauText"> 3957 <span class="boxVeranstaltungsvorschauTitel"> 3958 <span class="boxVeranstaltungsvorschauTag">Morgen</span> 3959 <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2> 3960 </span> 3961 </span> 3962 </a> 3963 <span class="boxVeranstaltungsvorschauOrtBlock"> 3964 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 3965 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 3966 <span class="boxVeranstaltungsvorschauTime">10:00 - 16:00 Uhr</span> 3967 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 3968 </span> 3969 </a> 3970 </span> 3971 </span> 3972 <div class="clear"> 3973 </div> 3974 </li> 3975 <li> 3976 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 3977 <span class="boxVeranstaltungsvorschauDatum"> 3978 <span class="boxVeranstaltungsvorschauDatumTag">03</span> 3979 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 3980 <abbr title="Oktober">Okt</abbr> 3981 </span> 3982 </span> 3983 </a>
3984 <span class="boxVeranstaltungsvorschauTextBlock"> 3985 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 3986 <span class="boxVeranstaltungsvorschauText"> 3987 <span class="boxVeranstaltungsvorschauTitel"> 3988 <span class="boxVeranstaltungsvorschauTag">Morgen</span> 3989 <h2>Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!"</h2> 3990 </span> 3991 </span> 3992 </a> 3993 <span class="boxVeranstaltungsvorschauOrtBlock"> 3994 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 3995 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 3996 <span class="boxVeranstaltungsvorschauTime">10:00 Uhr</span> 3997 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 3998 </span> 3999 </a> 4000 </span> 4001 </span> 4002 <div class="clear"> 4003 </div> 4004 </li> 4005 <li> 4006 <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen"> 4007 <span class="boxVeranstaltungsvorschauDatum"> 4008 <span class="boxVeranstaltungsvorschauDatumTag">03</span> 4009 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 4010 <abbr title="Oktober">Okt</abbr> 4011 </span> 4012 </span> 4013 </a>
4014 <span class="boxVeranstaltungsvorschauTextBlock"> 4015 <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen"> 4016 <span class="boxVeranstaltungsvorschauText"> 4017 <span class="boxVeranstaltungsvorschauTitel"> 4018 <span class="boxVeranstaltungsvorschauTag">Morgen</span> 4019 <h2>ORF Lange Nacht der Museen</h2> 4020 </span> 4021 </span> 4022 </a> 4023 <span class="boxVeranstaltungsvorschauOrtBlock"> 4024 <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen"> 4025 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 4026 <span class="boxVeranstaltungsvorschauTime">18:00 Uhr</span> 4027 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 4028 </span> 4029 </a> 4030 </span> 4031 </span> 4032 <div class="clear"> 4033 </div> 4034 </li> 4035 <li> 4036 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 4037 <span class="boxVeranstaltungsvorschauDatum"> 4038 <span class="boxVeranstaltungsvorschauDatumTag">04</span> 4039 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 4040 <abbr title="Oktober">Okt</abbr> 4041 </span> 4042 </span> 4043 </a>
4044 <span class="boxVeranstaltungsvorschauTextBlock"> 4045 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 4046 <span class="boxVeranstaltungsvorschauText"> 4047 <span class="boxVeranstaltungsvorschauTitel"> 4048 <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2> 4049 </span> 4050 </span> 4051 </a> 4052 <span class="boxVeranstaltungsvorschauOrtBlock"> 4053 <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung"> 4054 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 4055 <span class="boxVeranstaltungsvorschauTime">10:00 - 16:00 Uhr</span> 4056 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 4057 </span> 4058 </a> 4059 </span> 4060 </span> 4061 <div class="clear"> 4062 </div> 4063 </li> 4064 <li> 4065 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 4066 <span class="boxVeranstaltungsvorschauDatum"> 4067 <span class="boxVeranstaltungsvorschauDatumTag">04</span> 4068 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 4069 <abbr title="Oktober">Okt</abbr> 4070 </span> 4071 </span> 4072 </a>
4073 <span class="boxVeranstaltungsvorschauTextBlock"> 4074 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 4075 <span class="boxVeranstaltungsvorschauText"> 4076 <span class="boxVeranstaltungsvorschauTitel"> 4077 <h2>Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!"</h2> 4078 </span> 4079 </span> 4080 </a> 4081 <span class="boxVeranstaltungsvorschauOrtBlock"> 4082 <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Ãffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!""> 4083 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 4084 <span class="boxVeranstaltungsvorschauTime">10:00 Uhr</span> 4085 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 4086 </span> 4087 </a> 4088 </span> 4089 </span> 4090 <div class="clear"> 4091 </div> 4092 </li> 4093 <li> 4094 <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz"> 4095 <span class="boxVeranstaltungsvorschauDatum"> 4096 <span class="boxVeranstaltungsvorschauDatumTag">04</span> 4097 <span class="boxVeranstaltungsvorschauvorschauDatumMonat"> 4098 <abbr title="Oktober">Okt</abbr> 4099 </span> 4100 </span> 4101 </a>
4102 <span class="boxVeranstaltungsvorschauTextBlock"> 4103 <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz"> 4104 <span class="boxVeranstaltungsvorschauText"> 4105 <span class="boxVeranstaltungsvorschauTitel"> 4106 <h2>Wäldertanz</h2> 4107 </span> 4108 </span> 4109 </a> 4110 <span class="boxVeranstaltungsvorschauOrtBlock"> 4111 <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz"> 4112 <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock"> 4113 <span class="boxVeranstaltungsvorschauTime">14:00 - 17:00 Uhr</span> 4114 <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span> 4115 </span> 4116 </a> 4117 </span> 4118 </span> 4119 <div class="clear"> 4120 </div> 4121 </li> 4122 </ul> 4123</div> 4124<p class="boxVeranstaltungsvorschauWeitereTermine"> 4125 <a class="extlink" href="/Aktuelles/Veranstaltungen">Alle Termine</a> 4126</p> 4127<div class="clear"> 4128</div></div></div></div><div class="box2042 section section__partner"><div class="box2042 wrapper"><div class="titel"><h2> 4129 Förderprojekte 4130 </h2></div><div class="foerderprojekte"><p>In Zusammenarbeit mit <a class="extlink" href="https://www.bmluk.gv.at/themen/regionen-raumentwicklung/eu-regionalfoerderungen.html" target="_blank" rel="noopener noreferrer">Bund</a>, <a class="extlink" href="https://vorarlberg.at/-/abteilung-landwirtschaft-und-laendlicher-raum" target="_blank" rel="noopener noreferrer">Land</a> , <a class="extlink" href="https://ec.europa.eu/agriculture/rural-development-2014-2020_de" target="_blank" rel="noopener noreferrer">EU</a> und <a class="extlink" href="https://www.regio-v.at/" target="_blank" rel="noopener noreferrer">Regio V</a> wird der Ãffentliche Nahverkehr zwischen dem Allgäu, Bregenzerwald, Lindau und dem Leiblachtal ausgebaut. Im Bregenzerwald stehen zudem die Förderung von Kultur, Vielfalt, Wissen und Austausch im Mittelpunkt.</p> 4131<div class="foerderblock"> 4132 4133 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>Interegg</strong></a></p> 4134 4135 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>ÖPNV grenzenlos unterwegs (ABH013)</strong></a></p> 4136 4137 <p>Grenzüberschreitender ÃPNV zwischen dem Allgäu, Bregenzerwald, Lindau und Leiblachtal.</p> 4138</div> 4139<div class="foerderblock"> 4140 4141 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>Vernetzung /Mobilität</strong></a></p> 4142 4143 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>BA0300391</strong></a></p> 4144 4145 <p>Gemeinsames ÃPNV-Angebot zwischen dem Bregenzerwald und dem Westallgäu stärken.</p> 4146</div> 4147<div class="foerderblock"> 4148 4149 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p> 4150 4151 <p><a class="extlink" href="https://www.regio-v.at/projekte/bregenzerwald-in-vielfalt/" target="_blank" rel="noopener noreferrer"><strong>Bregenzerwald in Vielfalt</strong></a></p> 4152 4153 <p>Die Ausstellung zeigt die Zukunftsvision Bregenzerwald 2030 und lädt zur Auseinandersetzung mit Kultur, Zusammenleben und aktuellen Themen ein.</p> 4154</div> 4155<div class="foerderblock"> 4156 4157 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p> 4158 4159 <p><a class="extlink" href="https://www.regio-v.at/projekte/bbm-wissenstransfer/" target="_blank" rel="noopener noreferrer"><strong>BBM Wissenstransfer</strong></a></p> 4160 4161 <p>Das Projekt beschäftigt sich mit der Geschichte der Bregenzerwälder Barockbaumeister und ihrer wissenschaftlichen Aufarbeitung.</p> 4162</div> 4163<div class="foerderblock"> 4164 4165 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p> 4166 4167 <p><a class="extlink" href="https://www.regio-v.at/projekte/lebendige-geschichte-n/" target="_blank" rel="noopener noreferrer"><strong>Lebendige Geschichte(n)</strong></a></p> 4168 4169 <p>Bregenzerwälder Museen stärken ihre Zusammenarbeit, um Kultur einheitlich zu vermitteln.</p> 4170</div> 4171<div class="foerderblock"> 4172 4173 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p> 4174 4175 <p><a class="extlink" href="https://www.regio-v.at/projekte/nahversorgung-leben/" target="_blank" rel="noopener noreferrer"><strong>Nahversorgung leben</strong></a></p> 4176 4177 <p>Das Projekt verbindet Jugend, Politik und Betriebe, um das Bewusstsein für regionale Angebote zu stärken.</p> 4178</div> 4179<div class="foerderblock"> 4180 4181 <p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p> 4182 4183 <p><a class="extlink" href="https://www.regio-v.at/projekte/oepnv-bw-optimiert/" target="_blank" rel="noopener noreferrer"><strong>ÖPNV BW optimiert</strong></a></p> 4184 4185 <p>Das Projekt zielt darauf ab, Arbeitswege auszuarbeiten und zukunftsgerecht zu gestalten. </p> 4186</div></div><p><br></p><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/Partner_1"><img src="/system/web/getImage.ashx?fileid=1280141&mode=T&width=640&height=131&cts=1786092397" class="fr-dib width62" alt="Förderung von Land, Bund und Europäische Union"></a></p><p><br></p><p style="position:relative;clear:both;margin:0 0 2rem 0!important;text-align:center!important;"><a href="https://www.regiobregenzerwald.at/Partner_1" class="karte-button extlink">Zu den Projekten ›</a></p></div></div><div class="box2042 section section__theme"><div class="box2042 wrapper"><div class="titel"><h2> 4187 Regionale Aufgaben 4188 </h2><span class="titel_seperator"></span></div><div class="box2042 flexbox flexbox__theme"><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Gemeinden/Gemeinden"><strong>Gemeinden</strong></a></h2><p>Die Regio Bregenzerwald stärkt die Zusammenarbeit der 24 Gemeinden des Bregenzerwaldes und entwickelt gemeinsam zukunftsorientierte Lösungen für die Region.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Baurechtsverwaltung"><strong>
4188Baurechtsverwaltung</strong></a></h2><p>Durch die Baurechtsverwaltung werden die Bauverfahren der Mitgliedsgemeinden einheitlich und kompetent durchgeführt.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/bregenzerwaldarchiv"><strong>Bregenzerwald Archiv</strong></a></h2><p>Das Bregenzerwald Archiv ist das Verwaltungsarchiv von 24 Gemeinden der Region Bregenzerwald. Der Zugang zu den Archivalien ist in der Archivordnung geregelt.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Informationen"><strong>Visionen</strong></a></h2><p>Gemeinsame Zukunftsvisionen und Leitsätze der Regio Bregenzerwald haben zum Ziel, das Miteinander in der Region nachhaltig, gesund und bewusst zu stärken.</p></div><div class="titel"><h2> 4189 Themengebiete 4190 </h2></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Leben">Leben</a></h2><p>Versorgung und Lebensqualität erhalten.</p></div><div class="https://www.regiobregenzerwald.at/Leben_1"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Bewegen">Bewegen</a></h2><p>Mobilität und Freiheit fördern.</p><p><br></p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Arbeiten">Arbeiten</a></h2><p>Innovation und Qualität garantieren.</p><p><br></p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Bewahren">Bewahren</a></h2><p>Traditionen und Schützenswertes bewahren.</p></div></div></div></div><div class="box2042 section section__info"><div class="box2042 wrapper"><div class="box2042 flexbox flexbox__info"><div class="box2042 finder flexbox__item"><div class="h2"><h2> 4191 Regionale Initiativen 4192 </h2><span class="titel_seperator"></span></div><div class="gutschein"><p><a class="extlink" href="https://www.regiobregenzerwald.at/Bregenzerwald_Gutschein"><strong>Bregenzerwald Gutschein</strong></a></p><p>Schenken Sie regionale Verbundenheit und stärken Sie mit Ihrem Geschenk die heimische Wirtschaft.</p><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/ich_kauf_im_Wald"><strong>Ich kauf im Wald</strong></a></p><p>Das Bewusstsein für nachhaltige und regionale Produkte stärken.</p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/fahrradbus-2026" target="_blank" rel="noopener noreferrer"><strong>Fahrradbus</strong></a></p><p>Mit den Fahrrad-Bus-Linien 8R1 & 8R2 lässt sich das eigene Fahrrad oder E-Bike auf den Anhänger der Linienbusse aufladen und unkompliziert mitnehmen. </p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/wanderbuslinie-497-bequem-ab-damuels-unterwegs" target="_blank" rel="noopener noreferrer"><strong>Wanderbus</strong></a></p><p>Die Wanderbuslinie verbindet Damüls über das Furkajoch mit Innerlaterns und erschlieÃt damit das beliebte Wandergebiet mit dem öffentlichen Verkehr.</p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/nachtbuslinien-8n1-und-8n2" target="_blank" rel="noopener noreferrer"><strong>Nachtbus</strong></a></p><p>Die Nachtbusse 8N1 und 8N2 fahren in der Nacht von Samstag auf Sonntag, auÃer an Feiertagen. </p></div></div><div class="box2042 apps flexbox__item"><div class="h2"><h2> 4193 Empfohlene APPs 4194 </h2><span class="titel_seperator"></span></div><div class="app"><div class="app-container"><a href="/gem2go" target="newwnd" title="Mobile APP Gem2Go"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983798&mode=o&cts=1580896475" class="fr-fic fr-dii"></div><div class="app-text"><strong>Ãsterreichs einzige mobile Bürgerservice App</strong><br>Gem2Go vereint alle Gemeinden in Ãsterreich in einer App. Informationen zu Gemeinden und Regionen sind so schnell, bequem und mit einem Fingerzeig jederzeit abrufbar.</div></a></div></div><div class="app"><div class="app-container"><a href="/waelderdoc" target="newwnd" title="Anwendung Wälderdoc"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983801&mode=o&cts=1580896469"/></div><div class="app-text"><strong>Nichts geht über unsere Gesundheit<br></strong>Die WälderDoc-App bietet den Menschen in der Region und auch jenen, die im medizinischen Bereich tätig sind, eine einmalige Plattform. Kompakt, übersichtlich, informativ.</div></a></div> 4195</div><div class="app"><div class="app-container"><a href="/fairtiq" target="newwnd" title="Fairtiq"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983799&mode=o&cts=1580896457" /></div><div class="app-text"><strong>Die einfachste Fahrkarte Österreichs<br></strong>Ein Wisch am Smartphone vor dem Einsteigen und nach dem Aussteigen reicht und Sie erhalten eine gültige Fahrkarte für die zurückgelegte Strecke – zum besten verfügbaren Preis.</div></a></div> 4196</div><div class="app"><div class="app-container"><a href="/vmobil" target="newwnd" title="Clever V Mobil"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983800&mode=o&cts=1580896462" /></div><div class="app-text"><strong>Die Mobilitätsplattform für Vorarlberg<br></strong>Bus, Bahn, Fahrrad, Carsharing, Schiff und zu Fuß – mit VMOBIL haben Sie alle Mobilitätsangebote Vorarlbergs auf einen Blick.</div></a></div> 4197</div></div></div></div></div> 4198 4199 4200
4201<script type="text/javascript"> 4202//<![CDATA[ 4203var ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray = new Array('', '', '', '/system/WebResource.axd?d=Cwluxy80IT5OIlqhOMCzhxuwwtValsTsqO5DhdxS1vYWcftWceEb3uVWV0UXEIUjAjpOe-7g1ckDb8RLYyD-LZEbt-2xZcYU__u05ThJzVuStu0W0&t=639245057389592256', '/system/WebResource.axd?d=0olVLoWJ9sR5mmBD1M-qWhn4ciKUWauv7smZaFZbosTf-YRtkJ8RLKSNZfezje3wFZwSvCZh9pAWf8ERb-qTU1bjQd6npVIWz96Li8x179pWdl780&t=639245057389592256', '/system/WebResource.axd?d=i-UhIwZ8h3_WXs3cYAF-UHZSQdDOHrsAnOJ0LyrM2_yQGYEje8m7Mokgy6QWESCR1LTvxaMB_Uwz3B_kbVLn_8w6beW0G3Sjg696qHUv5syR-zOp0&t=639245057389592256'); 4204 //]]> 4205</script>
4205 4206 4207 <div class="aspNetHidden"> 4208 4209 <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="F35DDA41" /> 4210 </div> 4211 4212
4212<script type="text/javascript"> 4213 var lbsettings = {"txtImage":"Bild","txtOf":"von","sprachid":"1","imgCopyright":"Copyright","imgAltText":"Alternativtext","imgQuelle":"Quelle","imgLongDesc":"Fotobeschreibung","bildInformation":"Bildinformation","btnCloseLabel":"SchlieÃen","btnNextImage":"Nächstes Bild","btnPreviousImage":"Vorheriges Bild"}; 4214 var bslboptions = { 4215 keyboard: true, 4216 size: 'xl', 4217 target: '[data-lbgroup]', 4218 type: 'image' 4219 }; 4220 4221 if (typeof jQuery === "undefined") { 4222 document.querySelectorAll('[data-lbgroup]').forEach((el) => el.addEventListener('click', (e) => { 4223 e.preventDefault(); 4224 4225 let sprache = 1; 4226 let fileid = el.href.match(/fileid=(\d+)/i)[1]; 4227 4228 let url = `/system/web/services/files/filesinfo.asmx/GetFileInfo`; 4229 let data = { FileID : fileid, SprachId: sprache }; 4230 fetch(url, { 4231 method: 'POST', 4232 headers: { 4233 'Content-Type': 'application/json' 4234 }, 4235 body: JSON.stringify(data) 4236 }).then(response => { 4237 response.json().then(data => { 4238 if(data && data.d && data.d.Longdesc) 4239 el.dataset.description = data.d.Longdesc; 4240 4241 4242 const lightbox = new Lightbox(el, bslboptions); 4243 lightbox.show(); 4244 }); 4245 }); 4246 4247 4248 4249 })); 4250 } 4251 else { 4252 $(document).ready(function () { 4253 if (typeof Lightbox != "undefined") { 4254 document.querySelectorAll('[data-lbgroup]').forEach((el) => el.addEventListener('click', (e) => { 4255 e.preventDefault(); 4256 4257 let sprache = 1; 4258 let fileid = el.href.match(/fileid=(\d+)/i)[1]; 4259 4260 let url = `/system/web/services/files/filesinfo.asmx/GetFileInfo`; 4261 let data = { FileID : fileid, SprachId: sprache }; 4262 fetch(url, { 4263 method: 'POST', 4264 headers: { 4265 'Content-Type': 'application/json' 4266 }, 4267 body: JSON.stringify(data) 4268 }).then(response => { 4269 response.json().then(data => { 4270 if(data && data.d && data.d.Longdesc) 4271 el.dataset.description = data.d.Longdesc; 4272 4273 const lightbox = new Lightbox(el, bslboptions); 4274 lightbox.show(); 4275 }); 4276 }); 4277 4278 4279 4280 })); 4281 } 4282 else { 4283 4284 let styleEl = document.createElement("link"); 4285 styleEl.rel = "stylesheet"; 4286 styleEl.type = "text/css"; 4287 styleEl.href = "/system/web/lightboxJQuery/css/jquery.lightbox-0.5.css"; 4288 document.head.appendChild(styleEl); 4289 4290 $(function () { 4291 $('a[data-lbgroup]').lightBox(lbsettings); 4292 $('a[id*="startup"]').click(); 4293 }); 4294 4295 4296 $(function () { 4297 if (!jQuery.isFunction($('a[data-lbgroup]').lightBox)) { 4298 loadlightbox(); 4299 } 4300 $('a[rel*="lightbox"]').lightBox(lbsettings); 4301 }); 4302 } 4303 }); 4304 } 4305 4306 4307 </script>
vendor: 2 bytes, line 4307
4307
4308<script type="text/javascript"> 4309//<![CDATA[ 4310var ctl00_ctl00_ctl00_cph_header_ctl02_Data = new Object(); 4311ctl00_ctl00_ctl00_cph_header_ctl02_Data.images = ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray; 4312ctl00_ctl00_ctl00_cph_header_ctl02_Data.collapseToolTip = "Collapse {0}"; 4313ctl00_ctl00_ctl00_cph_header_ctl02_Data.expandToolTip = "Expand {0}"; 4314ctl00_ctl00_ctl00_cph_header_ctl02_Data.expandState = theForm.elements['ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState']; 4315ctl00_ctl00_ctl00_cph_header_ctl02_Data.selectedNodeID = theForm.elements['ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode']; 4316(function() { 4317 for (var i=0;i<6;i++) { 4318 var preLoad = new Image(); 4319 if (ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray[i].length > 0) 4320 preLoad.src = ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray[i]; 4321 } 4322})(); 4323//]]> 4324</script>
4324 4325</form> 4326 4327 4328 <div class="clear"></div> 4329 4330 <div id="main-content-footer"></div></div></div> 4331 4332 </div> 4333 4334 </div> 4335 4336 4337 </div> 4338 <div id="col-c" class="sidecol-c"> 4339 4340 4341 4342 </div> 4343 <div class="clear" id="em"></div> 4344 </div> 4345 4346 </div></div><div class="footer_wrapper" role="contentinfo"><div id="footer" class="clear"> 4347 4348 <div class="box2042 flexbox flexbox__footer"><div class="box2042 wrapper_gemeinden flexbox__item"><h2> 4349 Gemeinden 4350 </h2><p> 4351 <a class="extlink" href="https://www.regiobregenzerwald.at/Gemeinden/Gemeinden" rel="noopener noreferrer" title="Partnergemeinden"><img src="/system/web/getImage.ashx?fileid=1348880&mode=T&width=640&height=480&cts=1786975111" class="fr-fic fr-dii width80"></a></p> 4352 4353<p> 4354 <br> 4355</p></div><div class="box2042 wrapper_contact flexbox__item"><div class="contact flexbox__item"><h2> 4356 Kontakt 4357 </h2><p style="color: #000000;"><strong>Regio Bregenzerwald</strong><br>Loco 597 | 6863 Egg</p><p style="color: #000000;"><a href="tel:+43551226000">+43 5512 26000</a><br><a href="mailto:[email protected]">[email protected]</a></p><p style="color: #000000;"><a class="extlink" href="https://www.regiobregenzerwald.at/Kontakt">Kontaktadressen</a></p></div></div><div class="box2042 wrapper_openinghours openinghours flexbox__item"><h2> 4358 Ãffnungszeiten 4359 </h2><p class='ris_oz_ga_header'>Ãffnungszeiten</p><div class='ris_oz_ga_times'><ul class='ris_oz_list'><li class='ris_oz_listitem odd'><span class='ris_oz_days'><abbr title='Montag'>Mo</abbr>, <abbr title='Dienstag'>Di</abbr>, <abbr title='Mittwoch'>Mi</abbr>, <abbr title='Freitag'>Fr</abbr> </span><span class='ris_oz_times'>09:00 <span class="ris_oz_uhr">Uhr</span> - 12:30 <span class="ris_oz_uhr">Uhr</span></span></li><li class='ris_oz_listitem even'><span class='ris_oz_days'><abbr title='Donnerstag'>Do</abbr> </span><span class='ris_oz_times'>09:00 <span class="ris_oz_uhr">Uhr</span> - 16:00 <span class="ris_oz_uhr">Uhr</span></span></li></ul> 4360</div><p class='ris_oz_da_next ris_ga_oz_closed'>Das nächste Mal geöffnet:<br /><abbr title='Montag'>Mo</abbr>, 05.10.2026 ab 09:00 <span class="ris_oz_uhr">Uhr</span></p></div><div class="box2042 "><h2> 4361 Quicklinks 4362 </h2><p style="color: #000000;"><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald" target="_blank" rel="noopener noreferrer">Landbus Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://waelderkinder.com/" target="_blank" rel="noopener noreferrer">Kein Kind zurücklassen</a></p><p style="color: #000000;"><a class="extlink" href="https://www.bregenzerwald.at/" target="_blank" rel="noopener noreferrer">Bregenzerwald Tourismus</a></p><p style="color: #000000;"><a class="extlink" href="https://www.werkraum.at/" target="_blank" rel="noopener noreferrer">Werkraum Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://www.kaesestrasse.at/" target="_blank" rel="noopener noreferrer">KäseStrasse Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://www.ojb.at/" target="_blank" rel="noopener noreferrer">Offene Jugendarbeit</a></p><p style="color: #000000;"><a class="extlink" href="https://www.regiobregenzerwald.at/Karte">Bregenzerwald Karte</a></p></div></div></div></div><div class="box2042 section section__tray mobility1 mobility2"><div class="box2042 wrapper"><div class="hmenu tray mobility1 mobility2"><p class="TrayMenu"><a href="/Web/Datenschutz" class="schwarz-empty">Datenschutz</a><a href="/Web/Impressum" class="schwarz-empty">Impressum</a><a href="/Web/Sitemap" class="schwarz-empty">Sitemap</a><a href="/Web/Suche" class="schwarz-empty">Suche</a></p></div></div></div><div class="box2042 section section__map mobility1 mobility2"><div class="box2042 "></div></div><div class="box2042 section section__links mobility1 mobility2"></div></div><!-- CORE JS -->
4363<script src="/system/web/GetDocument.ashx?fileid=998466&cts=1604476299" type="text/javascript"></script>
vendor: 2 bytes, line 4363
4363
4364<script src="/system/web/GetDocument.ashx?fileid=983666&cts=1604476435" type="text/javascript"></script>
4364 4365 4366<!-- Matomo -->
4367<script type="text/javascript"> 4368 var _paq = window._paq = window._paq || []; 4369_paq.push(['enableLinkTracking']);_paq.push(['trackPageView']); 4370 (function() { 4371 var u="https://statistics.gem2go.page/"; 4372 if(!allowTracking) { 4373 _paq.push(['disableCookies']); 4374 _paq.push(['forgetCookieConsentGiven']); 4375 } 4376 _paq.push(['setTrackerUrl', u+'piwik.php']); 4377 _paq.push(['setSiteId', 2771]); 4378 var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; 4379 g.type='text/javascript'; g.async=true; g.src=u+'js/'; s.parentNode.insertBefore(g,s); 4380 })(); 4381try { 4382 document.addEventListener('DOMContentLoaded', function() { 4383 // Handle phone link clicks 4384 const phoneLinks = document.querySelectorAll('a[href^="tel:"]'); 4385 for (const link of phoneLinks) { 4386 link.addEventListener('click', function() { 4387 _paq.push(['trackEvent','Linkklick', 'Telefonnummer anrufen (tel:)']); 4388 }); 4389 } 4390 4391 // Handle download link clicks 4392 const downloadLinks = document.querySelectorAll('.piwik_download_tracker'); 4393 for (const link of downloadLinks) { 4394 link.addEventListener('click', function() { 4395 const currentLoc = window.location.origin; 4396 const datatyp = link.dataset.trackingtyp; 4397 let bez = link.dataset.bez; 4398 4399 if (bez === undefined) { 4400 bez = link.title; 4401 } 4402 4403 if (bez === undefined) { 4404 bez = link.textContent; 4405 } 4406 _paq.push(['trackLink',currentLoc + '/' + datatyp + '/' + bez, 'download']); 4407 }); 4408 } 4409 }); 4410} catch (err) {} 4411</script>
4411 4412<!-- End Matomo Code --> 4413
4414<script type="text/javascript"> 4415 window.piwikAsyncInit = function () {}; 4416</script>
4416 4417 4418 4419 </div></div> 4420 4421 4422 4423 4424 </div> 4425 4426
4426<script src="/cdnstatic/system/Javascriptz/ris/iFrameMessageAPI.js" type="text/javascript" async="async"></script>
4426 4427
4427<script src="/cdnstatic/system/Javascript/ris/trackNewspoolView.js?20210531T2006" type="text/javascript"></script>
4427 4428
4428<script src="/cdnstatic/meineseite/meineseite.js" type="text/javascript"></script>
4428 4429
4429<script src="/cdnstatic/muellinfoservice/muellinfoservice.js" type="text/javascript"></script>
4429 4430
4430<script src="/cdnstatic/gelbeseite/userinvite.js" type="text/javascript"></script>
4430 4431
4431<script src="/cdnstatic/nachrichtendienst/nachrichtendienst.js" type="text/javascript"></script>
4431 4432
4432<script src="/system/statV.1789655742/JavaScript/cookie.defer.js" type="text/javascript" defer="defer"></script>
4432 4433
4433<script src="/system/statV.1789655742/JavaScript/mobileAppdetector.defer.js" type="text/javascript" defer="defer"></script>
4433 4434
4434<script src="/cdnstatic/system/Javascript/flipbook/js/flipbook.init.defer.js" type="text/javascript" defer="defer"></script>
4434 4435 4436 4437</body> 4438</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.