window.AcrossNorwayGPXReady = (async function () { function loadCSS(href) { const exists = Array.from( document.querySelectorAll('link[rel="stylesheet"]') ) .some(link => link.href === href); if (exists) { return; } const link = document.createElement("link"); link.rel = "stylesheet"; link.href = href; document.head.appendChild( link ); } function loadScript( src, isReady ) { return new Promise( (resolve, reject) => { if (isReady()) { resolve(); return; } const existing = Array.from( document.scripts ) .find( script => script.src === src ); if (existing) { existing.addEventListener( "load", resolve, { once: true } ); existing.addEventListener( "error", reject, { once: true } ); return; } const script = document.createElement( "script" ); script.src = src; script.async = true; script.onload = resolve; script.onerror = reject; document.head.appendChild( script ); } ); } /* Leaflet */ loadCSS( "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" ); /* Leaflet Fullscreen */ loadCSS( "https://unpkg.com/leaflet.fullscreen@5.3.3/dist/Control.FullScreen.css" ); await loadScript( "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js", function () { return ( typeof window.L !== "undefined" ); } ); await loadScript( "https://unpkg.com/leaflet.fullscreen@5.3.3/dist/Control.FullScreen.umd.js", function () { return !!( window.L && L.Control && L.Control.FullScreen ); } ); /* Chart.js */ await loadScript( "https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js", function () { return ( typeof window.Chart !== "undefined" ); } ); return true; })();
Sogndalstrand Kulturhotell

Sogndalstrand Kulturhotell

Bo midt i historien – unikt opphold i Sogndalstrand

Overnatting med sjel
Sogndalstrand Kulturhotell byr på 29 individuelt innredede rom fordelt på historiske trehus fra 1800- og 1900-tallet. Hvert rom kombinerer autentisk atmosfære med moderne komfort som eget bad, Wi‑Fi og mørkleggingsgardiner. Her bor du som en del av det sjarmerende gamle tettstedet, omgitt av hus som Krambua og Skredderhuset – alle en del av hotellopplevelsen.

Fasiliteter og aktiviteter
Hotellet har egne selskaps- og møtelokaler, ideelle for både små og større grupper. Nyt måltider i restauranten med lokale råvarer, eller slapp av i puben som holder til i det gamle fengselet. Oppholdet kan kombineres med kulturvandringer, båtturer og kunstutstillinger – perfekt for en minnerik helg ved havet.

Location

Information
Åpent hele året
Parking
Gratis parkering for gjester

Reviews

No reviews yet

Similar listings in category

(async function () { /* ========================================================= ACROSSNORWAY GPX v1 Directify + Kartverket + GPX + elevation profile ========================================================= */ try { if ( window.AcrossNorwayGPXReady ) { await window .AcrossNorwayGPXReady; } } catch (error) { console.error( "AcrossNorway GPX: Libraries could not be loaded", error ); return; } /* ========================================================= LANGUAGE ========================================================= */ const htmlLang = ( document.documentElement.lang || "en" ).toLowerCase(); const norwegian = htmlLang.startsWith("no") || htmlLang.startsWith("nb") || htmlLang.startsWith("nn"); const labels = norwegian ? { distance: "Lengde", ascent: "Stigning", highest: "Høyeste punkt", lowest: "Laveste punkt", profile: "Høydeprofil", distanceAxis: "Distanse (km)", elevationAxis: "Høyde (m)", start: "Start", end: "Slutt", fullscreen: "Vis kart i fullskjerm", fullscreenExit: "Avslutt fullskjerm", elevationUnit: "moh" } : { distance: "Distance", ascent: "Ascent", highest: "Highest point", lowest: "Lowest point", profile: "Elevation profile", distanceAxis: "Distance (km)", elevationAxis: "Elevation (m)", start: "Start", end: "Finish", fullscreen: "View map fullscreen", fullscreenExit: "Exit fullscreen", elevationUnit: "m a.s.l." }; /* ========================================================= DISTANCE CALCULATION ========================================================= */ function haversine( lat1, lon1, lat2, lon2 ) { const R = 6371; const rad = value => value * Math.PI / 180; const dLat = rad( lat2 - lat1 ); const dLon = rad( lon2 - lon1 ); const a = Math.sin( dLat / 2 ) ** 2 + Math.cos( rad(lat1) ) * Math.cos( rad(lat2) ) * Math.sin( dLon / 2 ) ** 2; return ( R * 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1 - a) ) ); } function formatKm( value ) { let result = value.toFixed(1); if (norwegian) { result = result.replace( ".", "," ); } return result; } /* ========================================================= REDUCE CHART POINTS ========================================================= */ function sampleData( data, maxPoints = 1200 ) { if ( data.length <= maxPoints ) { return data; } const step = Math.ceil( data.length / maxPoints ); return data.filter( (item, index) => index % step === 0 || index === data.length - 1 ); } /* ========================================================= FIND GPX LINKS ========================================================= */ function getGPXLinks() { return Array .from( document.querySelectorAll( 'a[href]' ) ) .filter( link => { try { const url = new URL( link.href, window.location.href ); return ( url.pathname .toLowerCase() .endsWith( ".gpx" ) ); } catch { return false; } } ); } /* ========================================================= CREATE GPX WIDGET ========================================================= */ async function buildWidget( link, index ) { if ( link.dataset .anGpxProcessed === "1" || link.dataset .anGpxBusy === "1" ) { return; } link.dataset .anGpxBusy = "1"; const gpxUrl = link.href; const unique = Date.now() + "-" + index + "-" + Math.random() .toString(36) .slice(2, 7); const mapId = "an-gpx-map-" + unique; const statsId = "an-gpx-stats-" + unique; const chartId = "an-gpx-chart-" + unique; const profileId = "an-gpx-profile-" + unique; const widget = document.createElement( "section" ); widget.className = "an-gpx-widget"; widget.innerHTML = `
${labels.profile}

The GPX track is for guidance only and may contain errors. Use at your own risk.
– Always check maps, weather and conditions before your hike.

`; /* Widget is inserted directly before Directify's existing Download File button */ if ( !link.parentNode ) { delete link.dataset .anGpxBusy; return; } link.parentNode .insertBefore( widget, link ); try { /* ===================================================== LOAD GPX ===================================================== */ const response = await fetch( gpxUrl, { credentials: "omit" } ); if ( !response.ok ) { throw new Error( "GPX could not be loaded. HTTP " + response.status ); } const text = await response.text(); const xml = new DOMParser() .parseFromString( text, "application/xml" ); if ( xml.querySelector( "parsererror" ) ) { throw new Error( "Invalid GPX/XML" ); } /* ===================================================== TRACK SEGMENTS ===================================================== */ const trackSegments = Array.from( xml.getElementsByTagName( "trkseg" ) ); let segments = []; trackSegments.forEach( segment => { const segmentPoints = []; const nodes = Array.from( segment .getElementsByTagName( "trkpt" ) ); nodes.forEach( node => { const lat = parseFloat( node.getAttribute( "lat" ) ); const lon = parseFloat( node.getAttribute( "lon" ) ); const eleNode = node .getElementsByTagName( "ele" )[0]; const ele = eleNode ? parseFloat( eleNode .textContent ) : null; if ( Number.isFinite( lat ) && Number.isFinite( lon ) ) { segmentPoints .push({ lat: lat, lon: lon, ele: Number.isFinite( ele ) ? ele : null }); } } ); if ( segmentPoints .length ) { segments.push( segmentPoints ); } } ); /* ===================================================== FALLBACK FOR GPX ROUTES ===================================================== */ if ( !segments.length ) { const nodes = Array.from( xml.getElementsByTagName( "rtept" ) ); const routePoints = []; nodes.forEach( node => { const lat = parseFloat( node.getAttribute( "lat" ) ); const lon = parseFloat( node.getAttribute( "lon" ) ); const eleNode = node .getElementsByTagName( "ele" )[0]; const ele = eleNode ? parseFloat( eleNode .textContent ) : null; if ( Number.isFinite( lat ) && Number.isFinite( lon ) ) { routePoints .push({ lat: lat, lon: lon, ele: Number.isFinite( ele ) ? ele : null }); } } ); if ( routePoints .length ) { segments.push( routePoints ); } } if ( !segments.length ) { throw new Error( "No GPX track points found" ); } /* ===================================================== STATISTICS + ELEVATION ===================================================== */ let totalDistance = 0; let ascent = 0; let minElevation = Infinity; let maxElevation = -Infinity; const elevationData = []; segments.forEach( segment => { segment.forEach( (current, i) => { if ( i > 0 ) { const previous = segment[ i - 1 ]; totalDistance += haversine( previous.lat, previous.lon, current.lat, current.lon ); if ( current.ele !== null && previous.ele !== null ) { const diff = current.ele - previous.ele; if ( diff > 0 ) { ascent += diff; } } } if ( current.ele !== null ) { minElevation = Math.min( minElevation, current.ele ); maxElevation = Math.max( maxElevation, current.ele ); elevationData .push({ x: totalDistance, y: current.ele, lat: current.lat, lon: current.lon }); } } ); } ); /* ===================================================== MAP ===================================================== */ const map = L.map( mapId, { scrollWheelZoom: true, preferCanvas: false } ); /* ===================================================== KARTVERKET ===================================================== */ L.tileLayer( "https://cache.kartverket.no/v1/wmts/1.0.0/topo/default/webmercator/{z}/{y}/{x}.png", { maxZoom: 18, attribution: '© Kartverket' } ).addTo( map ); /* ===================================================== FULLSCREEN ===================================================== */ if ( L.Control && L.Control.FullScreen ) { new L.Control .FullScreen({ position: "topleft", title: labels .fullscreen, titleCancel: labels .fullscreenExit, forceSeparateButton: true }) .addTo( map ); map.on( "enterFullscreen", function () { setTimeout( function () { map.invalidateSize(); }, 150 ); } ); map.on( "exitFullscreen", function () { setTimeout( function () { map.invalidateSize(); }, 150 ); } ); } /* ===================================================== ROUTE PANE ===================================================== */ map.createPane( "acrossNorwayRoute" ); map.getPane( "acrossNorwayRoute" ) .style .zIndex = "650"; const routeRenderer = L.svg({ pane: "acrossNorwayRoute", padding: 0.5 }); routeRenderer.addTo( map ); const routeGroup = L.featureGroup() .addTo( map ); /* ===================================================== GPX TRACK ===================================================== */ segments.forEach( segment => { const latLngs = segment.map( point => [ point.lat, point.lon ] ); if ( latLngs.length < 2 ) { return; } /* White outline */ L.polyline( latLngs, { renderer: routeRenderer, pane: "acrossNorwayRoute", className: "an-route-outline", color: "#ffffff", weight: 7, opacity: 1, interactive: false, smoothFactor: 0 } ).addTo( routeGroup ); /* Red route */ L.polyline( latLngs, { renderer: routeRenderer, pane: "acrossNorwayRoute", className: "an-route", color: "#e31b23", weight: 4, opacity: 1, interactive: false, smoothFactor: 0 } ).addTo( routeGroup ); } ); /* ===================================================== START / FINISH ===================================================== */ const first = segments[0][0]; const lastSegment = segments[ segments.length - 1 ]; const last = lastSegment[ lastSegment.length - 1 ]; const startIcon = L.divIcon({ className: "", html: '
', iconSize: [16, 16], iconAnchor: [8, 8] }); const endIcon = L.divIcon({ className: "", html: '
', iconSize: [16, 16], iconAnchor: [8, 8] }); L.marker( [ first.lat, first.lon ], { icon: startIcon } ) .addTo( map ) .bindTooltip( labels.start ); L.marker( [ last.lat, last.lon ], { icon: endIcon } ) .addTo( map ) .bindTooltip( labels.end ); /* ===================================================== ELEVATION HOVER MARKER ===================================================== */ const hoverIcon = L.divIcon({ className: "", html: '
', iconSize: [18, 18], iconAnchor: [9, 9] }); const hoverMarker = L.marker( [ first.lat, first.lon ], { icon: hoverIcon, interactive: false, zIndexOffset: 1000 } ); let hoverMarkerVisible = false; /* ===================================================== FIT MAP ===================================================== */ const bounds = routeGroup .getBounds(); if ( bounds.isValid() ) { map.fitBounds( bounds, { padding: [30, 30], maxZoom: 14 } ); } /* ===================================================== STATISTICS ===================================================== */ document .getElementById( statsId ) .innerHTML = `
${formatKm(totalDistance)} km ${labels.distance}
${Math.round(ascent)} m ${labels.ascent}
${ Number.isFinite( maxElevation ) ? Math.round( maxElevation ) + " " + labels .elevationUnit : "–" } ${labels.highest}
${ Number.isFinite( minElevation ) ? Math.round( minElevation ) + " " + labels .elevationUnit : "–" } ${labels.lowest}
`; /* ===================================================== ELEVATION PROFILE ===================================================== */ if ( elevationData.length > 1 ) { const chartData = sampleData( elevationData ); const canvas = document .getElementById( chartId ); new Chart( canvas.getContext( "2d" ), { type: "line", data: { datasets: [{ data: chartData, parsing: false, borderColor: "#e31b23", backgroundColor: "rgba(227,27,35,.13)", borderWidth: 2, pointRadius: 0, pointHoverRadius: 5, pointHitRadius: 15, fill: true, tension: 0.12 }] }, options: { responsive: true, maintainAspectRatio: false, animation: false, interaction: { mode: "nearest", intersect: false, axis: "x" }, onHover: function ( event, activeElements, chart ) { if ( !activeElements .length ) { return; } const pointIndex = activeElements[0] .index; const point = chart .data .datasets[0] .data[ pointIndex ]; if ( !point || !Number.isFinite( point.lat ) || !Number.isFinite( point.lon ) ) { return; } hoverMarker .setLatLng( [ point.lat, point.lon ] ); if ( !hoverMarkerVisible ) { hoverMarker .addTo( map ); hoverMarkerVisible = true; } }, plugins: { legend: { display: false }, tooltip: { displayColors: false, callbacks: { title: function ( items ) { if ( !items.length ) { return ""; } let value = items[0] .parsed .x .toFixed( 1 ); if ( norwegian ) { value = value.replace( ".", "," ); } return ( value + " km" ); }, label: function ( context ) { return ( Math.round( context .parsed .y ) + " " + labels .elevationUnit ); } } } }, scales: { x: { type: "linear", beginAtZero: true, title: { display: true, text: labels .distanceAxis } }, y: { title: { display: true, text: labels .elevationAxis } } } } } ); canvas.addEventListener( "mouseleave", function () { if ( hoverMarkerVisible ) { map.removeLayer( hoverMarker ); hoverMarkerVisible = false; } } ); } else { document .getElementById( profileId ) .style .display = "none"; } /* ===================================================== IMPORTANT: WE DO NOT HIDE DIRECTIFY'S DOWNLOAD FILE LINK ===================================================== */ link.dataset .anGpxProcessed = "1"; delete link.dataset .anGpxBusy; /* ===================================================== REFLOW ===================================================== */ setTimeout( function () { map.invalidateSize(); if ( bounds.isValid() ) { map.fitBounds( bounds, { padding: [30, 30], maxZoom: 14 } ); } }, 400 ); } catch (error) { console.error( "AcrossNorway GPX:", error ); /* GPX widget removed if something fails. Directify Download File remains untouched. */ widget.remove(); delete link.dataset .anGpxBusy; } } /* ========================================================= INITIALIZE ========================================================= */ async function initAcrossNorwayGPX() { const links = getGPXLinks(); for ( let i = 0; i < links.length; i++ ) { await buildWidget( links[i], i ); } } if ( document.readyState === "loading" ) { document.addEventListener( "DOMContentLoaded", initAcrossNorwayGPX, { once: true } ); } else { initAcrossNorwayGPX(); } /* Directify may render some fields slightly later */ setTimeout( initAcrossNorwayGPX, 1200 ); })();