Da die Erstellung der 360°-Fotos relativ gut funktioniert und ich davon in Zukunft mehr erstellen werde, habe ich meinen Shortcode sphere erweitert.

Der Shortcode sorgt dafür, dass ein zusammengefügtes 360°-Foto in einem virtuellen Raum angezeigt wird, Details hier.

Ich habe den Shortcode nun erweitert und zusätzlich zum Bildbetrachter gibt weitere Informationen:

  • Ein Link zur Markierung auf einer Karte bei OpenStreetMap, an dem das “Foto” 1 entstanden ist.
  • Ein Link zum Originalfoto mit der Angabe der Dateigröße. Im Gegenzug habe ich den Download-Button aus den Bedienelementen entfernt.
  • Eine Karte kann unter dem Foto nachgeladen werden, jedoch erst nach einem Klick auf “Karte von OpenStreetMap nachladen …”, zuvor werden Infos zum Datenschutz angezeigt, da die Karte von einer externen Website nachgeladen wird.
Update
Update 1 (2023-09-11): Es gibt eine neue Variante des Shortcodes, der auch mit mehreren Einbindungen pro Blogbeitrag umgehen kann (bis auf die Karte), siehe hier.

iframe via Webserver erlauben

Damit das neue iframe geladen wird, musste ich in meiner nginx-Konfiguration im Bereich add_header Content-Security-Policy hinzufügen:

frame-src https://www.openstreetmap.org/export/embed.html

Der erweiterte Shortcode

Hugo-Shortcode

Hier der Quelltext der erweiterten Shortcodes sphere.html:

{{- $img := (.Page.Resources.ByType "image").GetMatch (printf "*%s" (.Get "src")) -}}
{{- $caption := "" -}}{{ if isset .Params "caption" }}{{ $caption = (.Get "caption" | markdownify ) }}{{ end }}
{{- $osmurl := "" -}}{{ if isset .Params "osmurl" }}{{ $osmurl = (.Get "osmurl" ) }}{{ end }}
{{- $osmembedurl := "" -}}{{ if isset .Params "osmembedurl" }}{{ $osmembedurl = (.Get "osmembedurl" ) }}{{ end }}
{{- $imgsize := "" -}}{{ if isset .Params "imgsize" }}{{ $imgsize = (.Get "imgsize" ) }}{{ end }}
<head>
    <!-- for optimal display on high DPI devices -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" href="/my_css/sphere/index.min.css" />
</head>
<script src="/my_js/sphere/three.min.js"></script>
<script src="/my_js/sphere/index.min.js"></script>

<!-- the viewer container must have a defined size -->
<div id="viewer" style="width: 100%; height: 60vh;"></div>

<script>
    const viewer = new PhotoSphereViewer.Viewer({
        container: document.querySelector('#viewer'),
        panorama: '{{- $img -}}',
        caption: '{{- $caption -}}',
        fisheye: true,
        lang: {
            zoom: 'Zoomen',
            zoomOut: 'Heraus zommen',
            zoomIn: 'Hinein zoomen',
            moveUp: 'Nach oben',
            moveDown: 'Nach unten',
            moveLeft: 'Nach links',
            moveRight: 'Nach rechts',
            download: 'Herunterladen',
            fullscreen: 'Vollbild',
            menu: 'Menü',
            close: 'Schließen',
            twoFingers: 'Benutze 2 Finger zum Navigieren.',
            ctrlZoom: 'Benutze Strg und das Mausrad, um im Bild zu zoomen.',
            loadError: 'Das Panorama kann nicht geladen werden.',
          }

    });
    viewer.navbar.getButton('download').hide();
</script>

<div class="shortcode-sphere">
<p class="untertitel">{{- if ( $osmurl ) -}}<a href="{{ $osmurl }}">Standort</a> (bei OpenStreetMap), {{ end -}}<a href="{{- $img -}}">Originalfoto</a>{{- if ( $imgsize ) }} ({{ $imgsize }} MiB){{- end -}}</p>
<!-- Optional einfügen, dass das Bild erst mit nem Click geladen wird, weil groß. -->

<!-- Optional einfügen hier im Shortcode, dass unter dem Bild auch eine Karte dargestellt wird, die auch Klick hin geladen wird mit Infos zum Datenschutz -->

<!-- Von https://photo-sphere-viewer.js.org/guide/#your-first-viewer -->

<!-- Konfiguration: https://photo-sphere-viewer.js.org/guide/config.html#standard-options -->

{{- if ( $osmembedurl ) }}
<div id="osmiframe" data-osmembedurl="{{ $osmembedurl }}">
  <div id="iframe-content">
    <p>Es gibt die Möglichkeit, eine Karte von OpenStreetMap mit dem Standort, an dem das Foto entstanden ist, hier anzuzeigen. Dabei werden Daten an OpenStreetMap.org übertragen. Informationen zum Datenschutz des Anbieters siehe <a href="https://wiki.osmfoundation.org/wiki/Privacy_Policy">https://wiki.osmfoundation.org/wiki/Privacy_Policy</a>.</p>
    <button id="load-iframe" class="btn btn-sm btn-primary">Karte von OpenStreetMap.org nachladen …</button>
  </div>
  <noscript><p>Du benötigst JavaScript, um das iframe mit der Karte nachzuladen.</p></noscript>
  <script src="/my_js/sphere/iframe.js"></script>
</div>
</div>
{{- end -}}

JavaScript

Das JavaScript habe ich per Copy&Paste von einem anderen Script umgemodelt und nach vielen Versuchen hat es dann funktioniert. Ich habe ja von solchen Dingen keine Ahnung.

Hier das iframe.js:

document.getElementById('load-iframe').addEventListener('click', init);

function init() {
    const iframeWrapper = document.getElementById('osmiframe');
    const osmembedurl = iframeWrapper.dataset.osmembedurl;

    loadComment(osmembedurl);
}

function loadComment(osmembedurl) {
    var iframe = "<iframe width='100%' height='400' frameborder='0' scrolling='no' marginheight='0' marginwidth='0' src='" + osmembedurl + "' style='border: 1px solid black'></iframe>";

    document.getElementById('iframe-content').innerHTML = iframe;
};

SCSS

Und das zugehörige SCSS:

.shortcode-sphere {
	#iframe-content {
		border-style: dotted;
		margin: 0.5em;
		padding: 0.5em;
	}
	
	.untertitel {
	    margin-top: 0.5em;
    	margin-bottom: 1em;
    	margin-right: 0.5em;
    	text-align: right;
    	font-style: italic;
    	font-size: smaller;
	}

    .btn a {
		color: white;
    }
}

Beispiel

Im Blogbeitrag 360°-Foto: Neuhausen (Enzkreis) wird z. B. dieser Shortcode verwendet:

{{< sphere src="2023-02-24-neuhausen-1-small.webp" caption="Landschaft nördlich von Neuhausen (Enzkreis)" osmurl="https://www.openstreetmap.org/?mlat=48.80035&mlon=8.77323#map=15/48.8010/8.7731" imgsize="8,6" osmembedurl="https://www.openstreetmap.org/export/embed.html?bbox=8.755288124084474%2C48.79391687059584%2C8.79112243652344%2C48.8067645369292&amp;layer=mapnik&amp;marker=48.800341115118435%2C8.773205280303955" >}}

Das Ergebnis sieht so aus (ohne geladene Karte):

Mit geladener Karte:


  1. Es sind ja eigentlich sehr viele Einzelfotos, gemeint ist hier aber das Ergebnis. ↩︎