diff --git a/index.html b/index.html
index 7a116df..cc985b9 100644
--- a/index.html
+++ b/index.html
@@ -47,7 +47,11 @@
}
#media-container img.zoomed {
- cursor: zoom-out;
+ cursor: grab;
+ }
+
+ #media-container img.zoomed:active {
+ cursor: grabbing;
}
#media-container video {
@@ -571,18 +575,102 @@
}
});
+ // Mouse/Touch panning for zoomed images
+ this.container.addEventListener('mousedown', (e) => {
+ const currentMedia = this.mediaFiles[this.currentIndex];
+ if (currentMedia && currentMedia.type === 'image' && this.zoom > 1) {
+ const img = this.container.querySelector('img');
+ if (img && e.target === img) {
+ e.preventDefault();
+ this.isPanning = true;
+ this.panStart = { x: e.clientX - this.panOffset.x, y: e.clientY - this.panOffset.y };
+ img.style.cursor = 'grabbing';
+ }
+ }
+ });
+
+ this.container.addEventListener('mousemove', (e) => {
+ if (this.isPanning) {
+ e.preventDefault();
+ const img = this.container.querySelector('img');
+ if (img) {
+ this.panOffset = {
+ x: e.clientX - this.panStart.x,
+ y: e.clientY - this.panStart.y
+ };
+ img.style.transform = `scale(${this.zoom}) translate(${this.panOffset.x}px, ${this.panOffset.y}px)`;
+ }
+ }
+ });
+
+ this.container.addEventListener('mouseup', () => {
+ if (this.isPanning) {
+ this.isPanning = false;
+ const img = this.container.querySelector('img');
+ if (img && this.zoom > 1) {
+ img.style.cursor = 'grab';
+ }
+ }
+ });
+
+ this.container.addEventListener('mouseleave', () => {
+ if (this.isPanning) {
+ this.isPanning = false;
+ const img = this.container.querySelector('img');
+ if (img && this.zoom > 1) {
+ img.style.cursor = 'grab';
+ }
+ }
+ });
+
+ // Touch support for mobile devices
+ this.container.addEventListener('touchstart', (e) => {
+ const currentMedia = this.mediaFiles[this.currentIndex];
+ if (currentMedia && currentMedia.type === 'image' && this.zoom > 1) {
+ const img = this.container.querySelector('img');
+ if (img && e.target === img && e.touches.length === 1) {
+ e.preventDefault();
+ this.isPanning = true;
+ this.panStart = {
+ x: e.touches[0].clientX - this.panOffset.x,
+ y: e.touches[0].clientY - this.panOffset.y
+ };
+ }
+ }
+ });
+
+ this.container.addEventListener('touchmove', (e) => {
+ if (this.isPanning && e.touches.length === 1) {
+ e.preventDefault();
+ const img = this.container.querySelector('img');
+ if (img) {
+ this.panOffset = {
+ x: e.touches[0].clientX - this.panStart.x,
+ y: e.touches[0].clientY - this.panStart.y
+ };
+ img.style.transform = `scale(${this.zoom}) translate(${this.panOffset.x}px, ${this.panOffset.y}px)`;
+ }
+ }
+ });
+
+ this.container.addEventListener('touchend', () => {
+ this.isPanning = false;
+ });
+
// Click to zoom toggle
this.container.addEventListener('click', (e) => {
- if (e.target.tagName === 'IMG' && !e.target.closest('#virtual-screen')) {
+ if (e.target.tagName === 'IMG' && !e.target.closest('#virtual-screen') && !this.isPanning) {
if (this.zoom > 1) {
this.zoom = 1;
this.panOffset = { x: 0, y: 0 };
e.target.classList.remove('zoomed');
e.target.style.transform = 'scale(1) translate(0, 0)';
+ e.target.style.cursor = 'zoom-in';
} else {
this.zoom = 2;
e.target.classList.add('zoomed');
e.target.style.transform = `scale(${this.zoom})`;
+ e.target.style.cursor = 'grab';
}
}
});
@@ -663,37 +751,60 @@
const url = URL.createObjectURL(media.file);
img.onload = async () => {
- // Extract EXIF data
- EXIF.getData(img, async () => {
- const exifData = EXIF.getAllTags(img);
- let dateStr = '';
- let geoLink = '';
+ // Try to extract EXIF data
+ let dateStr = '';
+ let geoLink = '';
- // Try to get date from EXIF
- if (exifData.DateTimeOriginal) {
- dateStr = this.formatExifDate(exifData.DateTimeOriginal);
- } else if (exifData.DateTime) {
- dateStr = this.formatExifDate(exifData.DateTime);
+ try {
+ // Check if EXIF library is available
+ if (typeof EXIF !== 'undefined') {
+ EXIF.getData(img, async () => {
+ try {
+ const exifData = EXIF.getAllTags(img);
+
+ // Try to get date from EXIF
+ if (exifData.DateTimeOriginal) {
+ dateStr = this.formatExifDate(exifData.DateTimeOriginal);
+ } else if (exifData.DateTime) {
+ dateStr = this.formatExifDate(exifData.DateTime);
+ } else {
+ // Use file modification date
+ dateStr = this.formatFileDate(media.file.lastModified);
+ }
+
+ // Check for GPS data
+ const lat = exifData.GPSLatitude;
+ const lon = exifData.GPSLongitude;
+ const latRef = exifData.GPSLatitudeRef;
+ const lonRef = exifData.GPSLongitudeRef;
+
+ if (lat && lon) {
+ const latDecimal = this.convertDMSToDD(lat, latRef);
+ const lonDecimal = this.convertDMSToDD(lon, lonRef);
+ geoLink = `https://www.google.com/maps/place/${latDecimal},${lonDecimal}/@${latDecimal},${lonDecimal},15z/data=!3m1!1e3`;
+ }
+
+ // Show info overlay
+ this.showInfoOverlay(dateStr, geoLink);
+ } catch (error) {
+ console.warn('Error reading EXIF data:', error);
+ // Fallback to file date
+ dateStr = this.formatFileDate(media.file.lastModified);
+ this.showInfoOverlay(dateStr, null);
+ }
+ });
} else {
- // Use file modification date
+ // EXIF library not available, use file date
+ console.warn('EXIF library not available, using file timestamp');
dateStr = this.formatFileDate(media.file.lastModified);
+ this.showInfoOverlay(dateStr, null);
}
-
- // Check for GPS data
- const lat = exifData.GPSLatitude;
- const lon = exifData.GPSLongitude;
- const latRef = exifData.GPSLatitudeRef;
- const lonRef = exifData.GPSLongitudeRef;
-
- if (lat && lon) {
- const latDecimal = this.convertDMSToDD(lat, latRef);
- const lonDecimal = this.convertDMSToDD(lon, lonRef);
- geoLink = `https://www.google.com/maps/place/${latDecimal},${lonDecimal}/@${latDecimal},${lonDecimal},15z/data=!3m1!1e3`;
- }
-
- // Show info overlay
- this.showInfoOverlay(dateStr, geoLink);
- });
+ } catch (error) {
+ console.error('Error accessing EXIF library:', error);
+ // Fallback to file date
+ dateStr = this.formatFileDate(media.file.lastModified);
+ this.showInfoOverlay(dateStr, null);
+ }
};
img.src = url;