feat: Add geocoding functionality and implement pan/zoom for the family tree view.

This commit is contained in:
Eivind Røsstad Skeie 2025-11-28 00:05:31 +01:00
parent 216385b638
commit bf5a0876b6
3 changed files with 119 additions and 1 deletions

View file

@ -116,7 +116,10 @@
<div class="form-group">
<label>Sted</label>
<div style="display: flex; gap: 10px;">
<input type="text" id="location" placeholder="F.eks. Kristiansand">
<button type="button" id="geocodeBtn" class="icon-btn" title="Finn koordinater">📍</button>
</div>
</div>
<div class="form-row">

View file

@ -196,6 +196,25 @@ memberForm.addEventListener('submit', (e) => {
}
});
// Geocoding
document.getElementById('geocodeBtn').addEventListener('click', () => {
const location = document.getElementById('location').value;
if (!location) return;
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': location }, (results, status) => {
if (status === 'OK') {
const lat = results[0].geometry.location.lat();
const lng = results[0].geometry.location.lng();
document.getElementById('lat').value = lat.toFixed(6);
document.getElementById('lng').value = lng.toFixed(6);
} else {
alert('Kunne ikke finne koordinater for dette stedet: ' + status);
}
});
});
// --- Feature: Family Tree ---
function renderTree() {
@ -490,3 +509,78 @@ function renderHistory() {
list.appendChild(item);
});
}
// --- Feature: Family Tree Navigation (Pan/Zoom) ---
let treeState = {
scale: 1,
panning: false,
pointX: 0,
pointY: 0,
startX: 0,
startY: 0
};
function setupPanZoom() {
const treeTab = document.getElementById('tree-tab');
const treeContainer = document.getElementById('tree-container');
// Zoom (Wheel)
treeTab.addEventListener('wheel', (e) => {
e.preventDefault();
const xs = (e.clientX - treeState.pointX) / treeState.scale;
const ys = (e.clientY - treeState.pointY) / treeState.scale;
const delta = -e.deltaY;
(delta > 0) ? (treeState.scale *= 1.1) : (treeState.scale /= 1.1);
// Limit zoom
treeState.scale = Math.min(Math.max(0.1, treeState.scale), 5);
treeState.pointX = e.clientX - xs * treeState.scale;
treeState.pointY = e.clientY - ys * treeState.scale;
setTransform();
});
// Pan (Mouse)
treeTab.addEventListener('mousedown', (e) => {
if (e.target.closest('.family-card') || e.target.closest('.fab')) return; // Don't drag if clicking card/button
e.preventDefault();
treeState.startX = e.clientX - treeState.pointX;
treeState.startY = e.clientY - treeState.pointY;
treeState.panning = true;
});
treeTab.addEventListener('mousemove', (e) => {
if (!treeState.panning) return;
e.preventDefault();
treeState.pointX = e.clientX - treeState.startX;
treeState.pointY = e.clientY - treeState.startY;
setTransform();
});
treeTab.addEventListener('mouseup', () => {
treeState.panning = false;
});
treeTab.addEventListener('mouseleave', () => {
treeState.panning = false;
});
function setTransform() {
treeContainer.style.transform = `translate(${treeState.pointX}px, ${treeState.pointY}px) scale(${treeState.scale})`;
}
// Initial center (approx)
treeState.pointX = (window.innerWidth - 1000) / 2; // Assuming 1000px content width
treeState.pointY = 50;
setTransform();
}
// Initialize PanZoom when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
setupPanZoom();
});

View file

@ -377,3 +377,24 @@ input[type="radio"] {
width: auto;
margin: 0;
}
/* Pan and Zoom Styles */
#tree-tab {
overflow: hidden; /* Hide scrollbars, we use custom pan */
position: relative;
cursor: grab;
}
#tree-tab:active {
cursor: grabbing;
}
#tree-container {
transform-origin: 0 0; /* Zoom from top-left */
position: absolute;
top: 0;
left: 0;
/* Ensure it has size */
min-width: 100%;
min-height: 100%;
}