Adding an Interactive Web App to Highlight Your Data Deposit!
The Workshop: https://bit.ly/InteractiveSDR
These Slides: https://slides.com/staceymaples/hacksdr_app
This workshop really boils down to learning how and when to use TWO THINGS:
Absolute Paths
&
Relative Paths
Absolute Paths start from the root of a file system or a complete URL:
https://stacks.stanford.edu/file/druid:vb564st1676/graduation-stanford.tif
https://stacks.stanford.edu/file/druid:vb564st1676/graduation-stanford.tif
https://
stacks.stanford.edu/
file/druid:vb564st1676/
graduation-stanford.tif
Relative Paths are relative to the current file's location. So if you have index.html in a folder:
So that if all of our digital content is in the same place on the SDR:
https://stacks.stanford.edu/file/druid:vb564st1676/index.html
We can address each of the files from index.html using relative paths:
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
</body>
</html>Step 1: The HTML Boilerplate
<!DOCTYPE html>
<html lang="en">
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Stanford Campus Map - Step 1: Basic HTML</title>
</head>
<body>
<h1>Stanford Public Art Map</h1>
<p>Step 1: Basic HTML structure with map container</p>
<div id="map" style="width: 600px; height: 400px;"></div>
</body>
</html>Step 2: Make a Map Container
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<style>
html, body {
height: 100%;
margin: 0;
}
.leaflet-container {
height: 400px;
width: 600px;
max-width: 100%;
max-height: 100%;
}
</style>
</head>
<body>
<h1>Stanford Public Art Map</h1>
<p>Step 2: Initialize Leaflet map with OpenStreetMap basemap</p>
<div id="map" style="width: 600px; height: 400px;"></div>
<script>
// Initialize map centered on Stanford campus
const map = L.map('map').setView([37.427, -122.169], 15);
// Add OpenStreetMap tile layer
const tiles = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
</script>Step 3: Initialize the Map
// Load GeoJSON data
fetch('../stanford_public_art.geojson')
.then(response => response.json())
.then(data => {
// Add GeoJSON layer with custom circle markers
const artworkLayer = L.geoJSON(data, {
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng, {
radius: 6,
color: 'blue',
weight: 2,
fillColor: 'blue',
fillOpacity: 0.7
});
}
}).addTo(map);
// Zoom to fit all markers
map.fitBounds(artworkLayer.getBounds());
})
.catch(error => console.error('Error loading GeoJSON:', error));
Step 4: Adding a Geojson Layer
onEachFeature: function(feature, layer) {
const props = feature.properties || {};
const title = props.name || 'Artwork';
const artist = props.artist_name;
const type = props.artwork_type;
// Build popup content
let popupContent = '<div style="min-width:200px;">';
popupContent += '<b>' + title + '</b><br>';
if (artist) popupContent += '<b>Artist:</b> ' + artist + '<br>';
if (type) popupContent += '<b>Type:</b> ' + type;
popupContent += '</div>';
layer.bindPopup(popupContent);
}
Step 4: Creating Popups
// URL to the COG file - using relative path
var url_to_geotiff_file = new URL("collection/stanford_campus_irg.tif", window.location.href).href;
// Parse and display the COG
parseGeoraster(url_to_geotiff_file).then(georaster => {
console.log("georaster:", georaster);Step 4: Adding the COG
// URL to the COG file - using relative path
var url_to_geotiff_file = new URL("collection/stanford_campus_irg.tif", window.location.href).href;
// Parse and display the COG
parseGeoraster(url_to_geotiff_file).then(georaster => {
console.log("georaster:", georaster);Step 4: Adding the COG