{"id":4701,"date":"2025-09-01T20:33:34","date_gmt":"2025-09-01T20:33:34","guid":{"rendered":"https:\/\/paragliding-in-madeira.com\/weather\/?page_id=4701"},"modified":"2026-06-14T15:23:46","modified_gmt":"2026-06-14T14:23:46","slug":"freeway","status":"publish","type":"page","link":"https:\/\/paragliding-in-madeira.com\/weather\/freeway\/","title":{"rendered":"Freeway"},"content":{"rendered":"\n<figure class=\"wp-block-image alignfull size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1361\" height=\"768\" src=\"https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2026\/06\/Freeway.webp\" alt=\"Freeway\" class=\"wp-image-11225\" srcset=\"https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2026\/06\/Freeway.webp 1361w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2026\/06\/Freeway-300x169.webp 300w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2026\/06\/Freeway-1024x578.webp 1024w, https:\/\/paragliding-in-madeira.com\/weather\/wp-content\/uploads\/2026\/06\/Freeway-768x433.webp 768w\" sizes=\"auto, (max-width: 1361px) 100vw, 1361px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-a89b3969 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/\">Home<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/paragliding-in-madeira.com\/weather\/weather-info\/\">Weather info<\/a><\/div>\n<\/div>\n\n\n\n<p class=\"has-text-align-center\"><a href=\"https:\/\/paragliding-in-madeira.com\/weather\/webcams\/\" title=\"\">Live<\/a> | <a href=\"https:\/\/paragliding-in-madeira.com\/weather\/all-cams\/\" title=\"\">Pictures<\/a> | <strong>Freeway<\/strong> | <a href=\"https:\/\/paragliding-in-madeira.com\/weather\/roads\/\" title=\"\">Roads<\/a><\/p>\n\n\n\n<div style=\"height:8px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center\"><a style=\"text-decoration:none\" href=\"https:\/\/madeiracams.pt\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Check the real time status of VR1 traffic<\/a><br>Powered by <a href=\"https:\/\/www.vialitoral.com\/map\" target=\"_blank\" rel=\"noreferrer noopener\">ViaLitoral<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-default\"\/>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<!-- ViaLitoral Freeway Live images -->\n<div id=\"traffic-cam-container\">\n  <style>\n    \/* Container *\/\n    #traffic-cam-container {\n      max-width: 1344px;\n      margin: 0 auto;\n      padding: 1rem;\n      font-family: 'Inter', sans-serif;\n      background: transparent;\n    }\n    @media (min-width: 640px) { #traffic-cam-container { padding: 2rem; } }\n\n    \/* Header *\/\n    #traffic-cam-container .header { text-align: center; margin-bottom: 2rem; }\n    #traffic-cam-container .header .title { font-size: 1.7rem; font-weight: 600; color: #1f2937; margin-bottom: 0.4rem; }\n    #traffic-cam-container .header .subtitle { font-size: 0.95rem; color: #4b5563; margin-bottom: 0.9rem; }\n    \n    \/* Search Input and Filters Container *\/\n    #traffic-cam-container .search-and-filters {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      gap: 1rem;\n    }\n    \n    #traffic-cam-container .header .filter-input {\n      padding: 0.5rem 1rem;\n      width: 100%;\n      max-width: 32rem; \/* The new fix: this prevents stretching *\/\n      border: 1px solid #d1d5db;\n      border-radius: 0.25rem;\n    }\n\n    \/* Location Filter Buttons *\/\n    #traffic-cam-container .location-filters {\n      display: flex;\n      justify-content: center;\n      flex-wrap: wrap;\n      gap: 0.5rem;\n    }\n    #traffic-cam-container .location-filters button {\n      background-color: #f3f4f6;\n      color: #374151;\n      border: 1px solid #d1d5db;\n      padding: 0.5rem 1rem;\n      border-radius: 9999px; \/* Full rounded corners *\/\n      cursor: pointer;\n      transition: background-color 0.2s, color 0.2s, transform 0.2s;\n      font-weight: 500;\n    }\n    #traffic-cam-container .location-filters button:hover {\n      background-color: #e5e7eb;\n      transform: translateY(-2px);\n    }\n    #traffic-cam-container .location-filters button.active {\n      background-color: #4f46e5;\n      color: white;\n      border-color: #4f46e5;\n      transform: translateY(-2px);\n    }\n\n    \/* Grid *\/\n    #traffic-cam-container #camera-grid {\n      display: grid;\n      grid-template-columns: repeat(1, 1fr);\n      gap: 1.5rem;\n    }\n    @media (min-width: 640px) { #traffic-cam-container #camera-grid { grid-template-columns: repeat(2, 1fr); } }\n    @media (min-width: 1024px) { #traffic-cam-container #camera-grid { grid-template-columns: repeat(3, 1fr); } }\n\n    \/* Camera item *\/\n    #traffic-cam-container .camera-item {\n      position: relative;\n      border-radius: 6px;\n      box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n      transition: transform .2s;\n      cursor: default;\n      background: transparent;\n      overflow: visible; \/* important for date\/time visibility *\/\n    }\n    #traffic-cam-container .camera-item:hover { transform: translateY(-4px); }\n\n    #traffic-cam-container .camera-image {\n      width: 100%;\n      display: block;\n      min-height: 180px;\n      border-radius: 6px;\n      object-fit: contain; \/* shows full image including top-right date *\/\n    }\n\n    #traffic-cam-container .camera-title {\n      padding: .5rem .75rem;\n      font-size: 1rem;\n      text-align: center;\n      font-weight: 500;\n      color: white;\n      background-color: #4f46e5;\n      border-radius: 0 0 6px 6px;\n      margin-top: -3px;\n    }\n\n    #traffic-cam-container .refresh-btn {\n      display: block;\n      margin: 0.5rem auto;\n      font-size: 0.8rem;\n      padding: 2px 6px;\n      background: #e5e7eb;\n      color: #374151;\n      border-radius: 4px;\n      cursor: pointer;\n      transition: background 0.2s;\n    }\n    #traffic-cam-container .refresh-btn:hover { background: #d1d5db; }\n    \n\/* Inactive state for the refresh button *\/\n    #traffic-cam-container .refresh-btn:disabled,\n    #traffic-cam-container .refresh-btn:disabled:hover {\n      background: #f3f4f6;\n      color: #9ca3af;\n      cursor: default;\n    }\n\n    #traffic-cam-container .fade-in { animation: fadeIn .5s ease-in forwards; }\n    @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n  <\/style>\n\n  <header class=\"header\">\n    <h1 class=\"title\">Live Cams<\/h1>\n    <p class=\"subtitle\">Refresh activates when a new image is in<\/p>\n    <div class=\"search-and-filters\">\n        <input id=\"filterInput\" type=\"text\" placeholder=\"Filter by camera title...\" class=\"filter-input\" \/>\n        <div class=\"location-filters\">\n            <button id=\"all-btn\" class=\"active\">All<\/button>\n            <button id=\"ribeira-brava-btn\">Rib. Brava<\/button>\n            <button id=\"cam-lobos-btn\">Cam Lobos<\/button>\n            <button id=\"funchal-btn\">Funchal<\/button>\n            <button id=\"santa-cruz-btn\">Santa Cruz<\/button>\n            <button id=\"machico-btn\">Machico<\/button>\n        <\/div>\n    <\/div>\n  <\/header>\n\n  <div id=\"camera-grid\"><\/div>\n\n  <script>\n    \/\/ Camera Titles (full 156)\n    const cameraTitles = { \n      '001': 'Ribeira Brava',\n      '002': 'T\u00fanel da Ribeira Brava (Sul)',\n      '003': 'Camera 3',\n      '004': 'Camera 4',\n      '005': 'T\u00fanel da Ribeira Brava (Norte)',\n      '006': 'Camera 6',\n      '007': 'Camera 7',\n      '008': 'R.B. Ponte Ribeira dos Mel\u00f5es',\n      '009': 'R.B. Viaduto da Amoreira',\n      '010': 'Camera 10',\n      '011': 'N\u00f3 do Campan\u00e1rio',\n      '012': 'Camera 12',\n      '013': 'Camera 13',\n      '014': 'Ponte do Campan\u00e1rio',\n      '015': 'Camera 15',\n      '016': 'Camera 16',\n      '017': 'Camera 17',\n      '018': 'T\u00fanel da Quinta Grande (Sul)',\n      '019': 'Camera 19',\n      '020': 'T\u00fanel da Quinta Grande (Norte)',\n      '021': 'Camera 21',\n      '022': 'N\u00f3 da Quinta Grande',\n      '023': 'Camera 23',\n      '024': 'T\u00fanel do Cabo Gir\u00e3o (Sul)',\n      '025': 'Camera 25',\n      '026': 'T\u00fanel do Cabo Gir\u00e3o (Norte)',\n      '027': 'Camera 27',\n      '028': 'C.L. Ponte da Caldeira',\n      '029': 'Camera 29',\n      '030': 'Camera 30',\n      '031': 'Camera 31',\n      '032': 'C.L. T\u00fanel da Alforra (Norte)',\n      '033': 'Camera 33',\n      '034': 'C.L. Ponte do Vig\u00e1rio',\n      '035': 'Camera 35',\n      '036': 'C.L. Ponte dos Frades (P.Pe\u00f5es)',\n      '037': 'C.L. N\u00f3 da Ponte dos Frades',\n      '038': 'Camera 38',\n      '039': 'N\u00f3 de C\u00e2mara de Lobos',\n      '040': 'Camera 40',\n      '041': 'Camera 41',\n      '042': 'S.M. N\u00f3 das Quebradas',\n      '043': 'Camera 43',\n      '044': 'Camera 44',\n      '045': 'S.M. Mercado Abastecedor',\n      '046': 'S.M. N\u00f3 do Esmeraldo',\n      '047': 'Camera 47',\n      '048': 'Camera 48',\n      '049': 'S.M. Sa\u00edda Oeste - Dr Barreto',\n      '050': 'Cruz de Carvalho',\n      '051': 'Camera 51',\n      '052': 'S.M. Sa\u00edda Oeste - Pilar',\n      '053': 'Funchal Ponte do Ribeiro Seco',\n      '054': 'Funchal Santo Ant\u00f3nio',\n      '055': 'Camera 55',\n      '056': 'Camera 56',\n      '057': 'T\u00fanel de Jo\u00e3o Abel de Freitas (Sul)',\n      '058': 'T\u00fanel de Jo\u00e3o Abel de Freitas (Norte)',\n      '059': 'N\u00f3 de Santa Luzia',\n      '060': 'T\u00fanel dos Marmeleiros (Sul)',\n      '061': 'Camera 61',\n      '062': 'T\u00fanel da Quinta da Palmeira (Sul)',\n      '063': 'T\u00fanel da Quinta da Palmeira (Norte)',\n      '064': 'Viaduto do Comboio',\n      '065': 'N\u00f3 de Pestana J\u00fanior',\n      '066': 'Camera 66',\n      '067': 'Camera 67',\n      '068': 'Ponte Jo\u00e3o Gomes',\n      '069': 'Camera 69',\n      '070': 'Jardim Bot\u00e2nico',\n      '071': 'Camera 71',\n      '072': 'Camera 72',\n      '073': 'N\u00f3 da Boa Nova',\n      '074': 'Canto do Muro',\n      '075': 'Neves',\n      '076': 'T\u00fanel de Jo\u00e3o Abel de Freitas (Norte)',\n      '077': 'Camera 77',\n      '078': 'Camera 78',\n      '079': 'N\u00f3 do Pinheiro Grande',\n      '080': 'Camera 80',\n      '081': 'Camera 81',\n      '082': 'N\u00f3 da Cancela',\n      '083': 'Camera 83',\n      '084': 'Camera 84',\n      '085': 'T\u00fanel da Abegoaria Oeste (Norte)',\n      '086': 'T\u00fanel da Abegoaria Este (Sul)',\n      '087': 'Camera 87',\n      '088': 'Abegoaria Este',\n      '089': 'Camera 89',\n      '090': 'Cani\u00e7o (Estrada do Garajau)',\n      '091': 'N\u00f3 do Cani\u00e7o',\n      '092': 'Camera 92',\n      '093': 'Ponte do Cani\u00e7o',\n      '094': 'Camera 94',\n      '095': 'Ponte dos Reis Magos',\n      '096': 'Camera 96',\n      '097': 'T\u00fanel da M\u00e3e de Deus (Sul)',\n      '098': 'Camera 98',\n      '099': 'Camera 99',\n      '100': 'N\u00f3 do Porto Novo',\n      '101': 'Ponte do Porto Novo',\n      '102': 'Camera 102',\n      '103': 'N\u00f3 de Gaula',\n      '104': 'Gaula',\n      '105': 'Camera 105',\n      '106': 'Gaula (Este)',\n      '107': 'Camera 107',\n      '108': 'N\u00f3 da Boaventura - Gaula',\n      '109': 'N\u00f3 de S\u00e3o Pedro',\n      '110': 'Camera 110',\n      '111': 'Ponte de Santa Cruz',\n      '112': 'Camera 112',\n      '113': 'T\u00fanel de Santa Catarina (Norte)',\n      '114': 'N\u00f3 de Santa Cruz',\n      '115': 'Camera 115',\n      '116': 'Aeroporto (T.Carga)',\n      '117': 'Camera 117',\n      '118': 'N\u00f3 do Aeroporto',\n      '119': 'Camera 119',\n      '120': 'N\u00f3 do Aeroporto Leste',\n      '121': 'Viaduto do Seixo',\n      '122': 'Camera 122',\n      '123': 'N\u00f3 de \u00c1gua de Pena',\n      '124': 'Camera 124',\n      '125': 'T\u00fanel da Queimada (Sul)',\n      '126': 'Camera 126',\n      '127': 'Camera 127',\n      '128': 'N\u00f3 de Machico Sul',\n      '129': 'Torre - Machico',\n      '130': 'Camera 128',\n      '131': 'Piquinho',\n      '132': 'Camera 132',\n      '133': 'Camera 133',\n      '134': 'Camera 134',\n      '135': 'N\u00f3 de Machico (Norte)',\n      '136': 'Camera 136',\n      '137': 'T\u00fanel da Fazenda (Norte)',\n      '138': 'Camera 138',\n      '139': 'Camera 139',\n      '140': 'Camera 140',\n      '141': 'Camera 141',\n      '142': 'Camera 142',\n      '143': 'Camera 143',\n      '144': 'Camera 144',\n      '145': 'Camera 145',\n      '146': 'N\u00f3 do Cani\u00e7al',\n      '147': 'Camera 146',\n      '148': 'Camera 147',\n      '149': 'Ponte entre \u00c1guas',\n      '150': 'Camera 150',\n      '151': 'Camera 151',\n      '152': 'Camera 152',\n      '153': 'Camera 153',\n      '154': 'Camera 154',\n      '155': 'Camera 155',\n      '156': 'Rotunda Porto Cani\u00e7al'\n    };\n\n    \/\/ Location-based camera groupings\n    const locationFilters = {\n      'ribeira-brava': ['001', '002', '003', '004', '005', '006', '007', '008', '009', '010'],\n      'cam-lobos': ['011', '012', '013', '014', '015', '016', '017', '018', '019', '020', '021', '022', '023', '024', '025', '026', '027', '028', '029', '030', '031', '032', '033', '034', '035', '036', '037', '038', '039', '040', '041'],\n      'funchal': ['042', '043', '044', '045', '046', '047', '048', '049', '050', '051', '052', '053', '054', '055', '056', '057', '058', '059', '060', '061', '062', '063', '064', '065', '066', '067', '068', '069', '070', '071', '072', '073', '074', '075', '076', '077', '078', '079', '080', '081', '082', '083', '084', '085', '086', '087', '088', '089', '090'],\n      'santa-cruz': ['091', '092', '093', '094', '095', '096', '097', '098', '099', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', '117', '118', '119', '120', '121', '122', '123', '124'],\n      'machico': ['125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', '137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156']\n    };\n\n    \/\/ Cameras array\n    const cameras = Array.from({ length: 156 }, (_, i) => {\n      const id = String(i+1).padStart(3,'0');\n      return { id, title: cameraTitles[id] || `VR1 ${id}` };\n    });\n\n    \/\/ Create camera HTML\n    function createCameraElement(camera) {\n      const article = document.createElement('article');\n      article.className = 'camera-item';\n      article.dataset.id = camera.id;\n      article.dataset.title = camera.title.toLowerCase();\n      article.innerHTML = `\n        <img class=\"camera-image\" id=\"img-${camera.id}\" loading=\"lazy\" decoding=\"async\" alt=\"${camera.title}\">\n        <div class=\"camera-title\">${camera.title}<\/div>\n        <button class=\"refresh-btn\" disabled>Refresh<\/button>\n      `;\n      \n      const refreshBtn = article.querySelector('.refresh-btn');\n      refreshBtn.addEventListener('click', () => {\n        if (refreshBtn.disabled) return;\n        \n        refreshBtn.disabled = true; \/\/ Disable immediately upon click\n        const img = document.getElementById(`img-${camera.id}`);\n\n        \/\/ Updated point to proxy file\n        img.src = `https:\/\/paragliding-in-madeira.com\/weather\/proxy.php?id=${camera.id}&t=${Date.now()}`;\n      });\n      return article;\n    }\n\n    \/\/ Load cameras\n    function loadCamera(camera) {\n      const img = document.getElementById(`img-${camera.id}`);\n      const btn = img.closest('.camera-item')?.querySelector('.refresh-btn');\n\n      img.onload = () => {\n        img.closest('.camera-item')?.classList.add('fade-in');\n        \n        \/\/ Timer sequence to respect the 60-second PHP cache\n        if (btn) {\n          btn.disabled = true;\n          setTimeout(() => {\n            btn.disabled = false;\n          }, 63000); \/\/ 63 seconds\n        }\n      };\n      \n      img.onerror = () => img.closest('.camera-item')?.remove();\n\n      \/\/ Updated with the timestamp 't' to ensure fresh requests\n      img.src = `https:\/\/paragliding-in-madeira.com\/weather\/proxy.php?id=${camera.id}&t=${Date.now()}`;\n    }\n\n    \/\/ Filter cameras based on an array of IDs\n    function filterCameras(idsToShow) {\n        document.querySelectorAll('.camera-item').forEach(item => {\n            if (idsToShow === 'all' || idsToShow.includes(item.dataset.id)) {\n                item.style.display = '';\n            } else {\n                item.style.display = 'none';\n            }\n        });\n    }\n\n    \/\/ Init\n    document.addEventListener('DOMContentLoaded', () => {\n        const grid = document.getElementById('camera-grid');\n        const filterInput = document.getElementById('filterInput');\n        const locationButtons = document.querySelectorAll('.location-filters button');\n\n        let staggerIndex = 0;\n        const staggerDelay = 150; \/\/ Milliseconds interval between sequential outgoing image requests\n\n        \/\/ Create camera elements and initialize staggered queue\n        cameras.forEach(cam => {\n            \/\/ Skip No named Cameras\n            if (cam.title.startsWith('Camera')) return; \n\n            \/\/ 1. Create and add the element\n            grid.appendChild(createCameraElement(cam));\n            \n            \/\/ 2. Load the image with a minor incremental delay to regulate traffic pacing\n            setTimeout(() => {\n                loadCamera(cam);\n            }, staggerIndex * staggerDelay);\n            \n            staggerIndex++;\n        });\n\n      \/\/ Filter\/search input\n      filterInput.addEventListener('input', e => {\n        const q = e.target.value.toLowerCase();\n        locationButtons.forEach(btn => btn.classList.remove('active'));\n        if (q === '') {\n          document.getElementById('all-btn').classList.add('active');\n        }\n        document.querySelectorAll('.camera-item').forEach(item => {\n          item.style.display = item.dataset.title.includes(q) ? '' : 'none';\n        });\n      });\n\n      \/\/ Location filter buttons\n      locationButtons.forEach(button => {\n        button.addEventListener('click', () => {\n          filterInput.value = ''; \/\/ Clear search\n          locationButtons.forEach(btn => btn.classList.remove('active'));\n          button.classList.add('active');\n\n          const locationId = button.id.replace('-btn', '');\n          if (locationId === 'all') {\n            filterCameras('all');\n          } else {\n            filterCameras(locationFilters[locationId]);\n          }\n        });\n      });\n    });\n  <\/script>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Live | Pictures | Freeway | Roads Check the real time status of VR1 trafficPowered by ViaLitoral Live Cams Refresh activates when a new image is in All Rib. Brava Cam Lobos Funchal Santa Cruz Machico<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"slim_seo":{"title":"Madeira Freeway live","description":"Live images on the freeway to check the real time status of traffic. Powered by ViaLitoral"},"footnotes":""},"class_list":["post-4701","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/4701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/comments?post=4701"}],"version-history":[{"count":104,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/4701\/revisions"}],"predecessor-version":[{"id":11262,"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/pages\/4701\/revisions\/11262"}],"wp:attachment":[{"href":"https:\/\/paragliding-in-madeira.com\/weather\/wp-json\/wp\/v2\/media?parent=4701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}