From c7cc7008b87be16c7975e260d5e4d2e1e83b6f43 Mon Sep 17 00:00:00 2001 From: Atul Patil <67235572+0xatulpatil@users.noreply.github.com> Date: Wed, 12 Mar 2025 01:50:38 +0530 Subject: [PATCH] Feature: add prev/next button to viewer for georeferenced photos (#10865) --- CHANGELOG.md | 8 ++++++-- css/60_photos.css | 15 +++++++++++++++ modules/svg/local_photos.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 709981776..c52f5712f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,10 +41,11 @@ _Breaking developer changes, which may affect downstream projects or sites that * Allow searching for coordinates in localized number format in search box ([#10805]) #### :scissors: Operations #### :camera: Street-Level +* Add prev/next button to viewer for local georeferenced photos ([#10852], thanks [@0xatulpatil]) #### :white_check_mark: Validation #### :bug: Bugfixes -* fix some direction cones not appearing on railway tracks ([#10843], thanks [@k-yle]) -* better handling of rate limited API calls and other API errors ([#10299]) +* Fix some direction cones not appearing on railway tracks ([#10843], thanks [@k-yle]) +* Better handling of rate limited API calls and other API errors ([#10299]) #### :earth_asia: Localization #### :hourglass: Performance #### :mortar_board: Walkthrough / Help @@ -53,6 +54,9 @@ _Breaking developer changes, which may affect downstream projects or sites that [#10805]: https://github.com/openstreetmap/iD/pull/10805 [#10299]: https://github.com/openstreetmap/iD/issues/10299 [#10843]: https://github.com/openstreetmap/iD/pull/10843 +[#10852]: https://github.com/openstreetmap/iD/issues/10852 +[@0xatulpatil]: https://github.com/0xatulpatil + # 2.32.0 diff --git a/css/60_photos.css b/css/60_photos.css index 71611febc..22cba8377 100644 --- a/css/60_photos.css +++ b/css/60_photos.css @@ -681,3 +681,18 @@ label.streetside-hires { cursor: pointer; } +.photo-controls-local { + display: flex; + align-items: center; + justify-content: center; + gap: 4px; +} +.photo-controls-local button { + padding:0 6px; + pointer-events: initial; +} + +.photo-controls-local button:disabled { + background: rgba(255,255,255,.25); +} + diff --git a/modules/svg/local_photos.js b/modules/svg/local_photos.js index 33094125e..414cda283 100644 --- a/modules/svg/local_photos.js +++ b/modules/svg/local_photos.js @@ -17,6 +17,7 @@ export function svgLocalPhotos(projection, context, dispatch) { let _photos = []; let _idAutoinc = 0; let _photoFrame; + let _activePhotoIdx; function init() { if (_initialized) return; // run once @@ -66,14 +67,43 @@ export function svgLocalPhotos(projection, context, dispatch) { .append('div') .attr('class', 'photo-attribution photo-attribution-dual fillD'); + const controlsEnter = viewerEnter + .append('div') + .attr('class', 'photo-controls-wrap') + .append('div') + .attr('class', 'photo-controls-local'); + + controlsEnter + .append('button') + .classed('back', true) + .on('click.back', () => stepPhotos(-1)) + .text('◀'); + + controlsEnter + .append('button') + .classed('forward', true) + .on('click.forward', () => stepPhotos(1)) + .text('▶'); + return planePhotoFrame.init(context, viewerEnter) .then(planePhotoFrame => { _photoFrame = planePhotoFrame; }); } + function stepPhotos(stepBy){ + if (!_photos || _photos.length === 0) return; + if (_activePhotoIdx === undefined) _activePhotoIdx = 0; + + const newIndex = _activePhotoIdx + stepBy; + _activePhotoIdx = Math.max(0, Math.min(_photos.length - 1, newIndex)); + + click(null, _photos[_activePhotoIdx], false); + } + // opens the image at bottom left function click(d3_event, image, zoomTo) { + _activePhotoIdx = _photos.indexOf(image); ensureViewerLoaded(context).then(() => { const viewer = context.container().select('.photoviewer') .datum(image) @@ -82,6 +112,13 @@ export function svgLocalPhotos(projection, context, dispatch) { const viewerWrap = viewer.select('.local-photos-wrapper') .classed('hide', false); + const controlsWrap = viewer.select('.photo-controls-wrap'); + + controlsWrap.select('.back') + .attr('disabled', _activePhotoIdx <= 0 ? true: null); + controlsWrap.select('.forward') + .attr('disabled', _activePhotoIdx >= _photos.length - 1 ? true: null); + const attribution = viewerWrap.selectAll('.photo-attribution').text(''); if (image.date) {