From e7daa508e81929610ce566303cf507e2fad514cd Mon Sep 17 00:00:00 2001 From: Mattia Pezzotti Date: Tue, 18 Jun 2024 13:09:28 +0200 Subject: [PATCH] refactored how panoramax shows frames --- css/60_photos.css | 25 +-- modules/services/panoramax.js | 261 ++++++-------------------------- modules/svg/panoramax_images.js | 11 +- 3 files changed, 51 insertions(+), 246 deletions(-) diff --git a/css/60_photos.css b/css/60_photos.css index 9f0893a53..67f75c549 100644 --- a/css/60_photos.css +++ b/css/60_photos.css @@ -327,27 +327,6 @@ padding:0 6px; pointer-events: initial; } -.ideditor .panoramax-wrapper { - position: relative; - background-color: #000; - background-image: url(img/loader-black.gif); - background-position: center; - background-repeat: no-repeat; -} -#ideditor-viewer-panoramax-simple-wrap { - height: 100%; -} -#ideditor-viewer-panoramax-simple { - width: 100%; - height: 100%; - transform-origin: 0 0; -} -#ideditor-viewer-panoramax-simple img { - width: 100%; - height: 100%; - object-fit: cover; - overflow: hidden -} label.panoramax-hd { float: left; @@ -392,7 +371,8 @@ label.panoramax-hd { } .ms-wrapper .pnlm-compass.pnlm-control, -.vegbilder-wrapper .pnlm-compass.pnlm-control { +.vegbilder-wrapper .pnlm-compass.pnlm-control, +.panoramax-wrapper .pnlm-compass.pnlm-control { width: 26px; height: 26px; left: 4px; @@ -494,6 +474,7 @@ label.streetside-hires { background-image: url(img/loader-black.gif); background-position: center; background-repeat: no-repeat; + object-fit: cover; } .photoviewer .plane-frame > img.plane-photo{ diff --git a/modules/services/panoramax.js b/modules/services/panoramax.js index 960575716..621cf2779 100644 --- a/modules/services/panoramax.js +++ b/modules/services/panoramax.js @@ -1,7 +1,4 @@ import { dispatch as d3_dispatch } from 'd3-dispatch'; -import { select as d3_select } from 'd3-selection'; -import { timer as d3_timer } from 'd3-timer'; -import { zoom as d3_zoom, zoomIdentity as d3_zoomIdentity } from 'd3-zoom'; import Protobuf from 'pbf'; import RBush from 'rbush'; @@ -10,6 +7,8 @@ import { VectorTile } from '@mapbox/vector-tile'; import { utilRebind, utilTiler, utilQsString, utilStringQs, utilSetTransform, utilUniqueDomId} from '../util'; import { geoExtent, geoScaleToZoom } from '../geo'; import { t, localizer } from '../core/localizer'; +import pannellumPhotoFrame from './pannellum_photo'; +import planePhotoFrame from './plane_photo'; const apiUrl = 'https://panoramax.openstreetmap.fr/'; const tileUrl = apiUrl + 'api/map/{z}/{x}/{y}.pbf'; @@ -25,28 +24,16 @@ const sequenceLayer = 'sequences'; const minZoom = 10; const dispatch = d3_dispatch('loadedImages', 'loadedLines', 'viewerChanged'); -const imgZoom = d3_zoom() - .extent([[0, 0], [320, 240]]) - .translateExtent([[0, 0], [320, 240]]) - .scaleExtent([1, 15]); -const pannellumViewerCSS = 'pannellum/pannellum.css'; -const pannellumViewerJS = 'pannellum/pannellum.js'; -const resolution = 1080; let _cache; let _loadViewerPromise; let _pannellumViewer; let _definition = standardDefinition; let _isHD = false; -let _sceneOptions = { - showFullscreenCtrl: false, - autoLoad: true, - yaw: 0, - minHfov: 10, - maxHfov: 90, - hfov: 60, -}; -let _currScene = 0; + +let _planeFrame; +let _pannellumFrame; +let _currentFrame; let _currentScene = { currentImage : null, @@ -160,8 +147,9 @@ function loadTileDataToCache(data, tile) { acc_id: feature.properties.account_id, sequence_id: feature.properties.sequences.split("\"")[1], heading: feature.properties.heading, + image_path: "", resolution: feature.properties.resolution, - isPano: feature.properties.type === "equirectangular", + isPano: feature.properties.type == "equirectangular", model: feature.properties.model, }; cache.forImageId[d.id] = d; @@ -338,40 +326,28 @@ export default { } }, - initViewer: function () { - if (!window.pannellum) return; - if (_pannellumViewer) return; - - _currScene += 1; - const sceneID = _currScene.toString(); - const options = { - 'default': { firstScene: sceneID }, - scenes: {} - }; - options.scenes[sceneID] = _sceneOptions; - - _pannellumViewer = window.pannellum.viewer('ideditor-viewer-panoramax-pnlm', options); - }, - selectImage: function (context, id) { let that = this; - let d = this.cachedImage(id); - - this.setActiveImage(d); - - this.updateUrlImage(d.id); + let d = that.cachedImage(id); + that.setActiveImage(d); + that.updateUrlImage(d.id); let imageUrl = getImage(d.id, highDefinition); - let viewer = context.container().select('.photoviewer'); - if (!viewer.empty()) viewer.datum(d); + let viewer = context.container() + .select('.photoviewer'); + + if (!viewer.empty()) + viewer.datum(d); this.setStyles(context, null); if (!d) return this; - let wrap = context.container().select('.photoviewer .panoramax-wrapper'); + let wrap = context.container() + .select('.photoviewer .panoramax-wrapper'); + let attribution = wrap.selectAll('.photo-attribution').text(''); let line1 = attribution @@ -392,17 +368,8 @@ export default { .property('checked', _isHD) .on('click', (d3_event) => { d3_event.stopPropagation(); - _isHD = !_isHD; _definition = _isHD ? highDefinition : standardDefinition; - - let viewstate = { - yaw: _pannellumViewer.getYaw(), - pitch: _pannellumViewer.getPitch(), - hfov: _pannellumViewer.getHfov() - }; - - _sceneOptions = Object.assign(_sceneOptions, viewstate); that.selectImage(context, d.id) .showViewer(context); }); @@ -411,15 +378,6 @@ export default { .append('span') .call(t.append('panoramax.hd')); - wrap - .transition() - .duration(100) - .call(imgZoom.transform, d3_zoomIdentity); - - wrap - .selectAll('img') - .remove(); - if (d.capture_time) { attribution .append('span') @@ -449,6 +407,7 @@ export default { .text('panoramax.fr'); getImageData(d.sequence_id, d.id).then(function(data){ + _currentScene = { currentImage: null, nextImage: null, @@ -461,7 +420,8 @@ export default { _currentScene.nextImage = data.links[nextIndex]; if (prevIndex != -1) _currentScene.prevImage = data.links[prevIndex]; - _sceneOptions.panorama = _currentScene.currentImage.href; + + d.image_path = _currentScene.currentImage.href; wrap .selectAll('button.back') @@ -470,26 +430,12 @@ export default { .selectAll('button.forward') .classed('hide', _currentScene.nextImage == null); - if (d.isPano) { - _sceneOptions.type = "equirectangular"; - if (!_pannellumViewer) { - that.initViewer(); - } else { - _currScene += 1; - let sceneID = _currScene.toString(); - _pannellumViewer - .addScene(sceneID, _sceneOptions) - .loadScene(sceneID); + _currentFrame = d.isPano ? _pannellumFrame : _planeFrame; - if (_currScene > 2) { - sceneID = (_currScene - 1).toString(); - _pannellumViewer - .removeScene(sceneID); - } - } - } else { - that.initOnlyPhoto(context, imageUrl); - } + _currentFrame + .selectPhoto(d, true) + .showPhotoFrame(wrap); + }); function localeDateString(s) { @@ -503,35 +449,16 @@ export default { return this; }, - initOnlyPhoto: function(context, imageUrl) { - - if (_pannellumViewer) { - _pannellumViewer.destroy(); - _pannellumViewer = null; - } - - let wrap = context.container().select('#ideditor-viewer-panoramax-simple'); - - let imgWrap = wrap.select('img'); - - if (!imgWrap.empty()) { - imgWrap.attr('src', imageUrl); - } else { - wrap.append('img') - .attr('src', imageUrl); - } - - }, - - viewer: function() { - return _pannellumViewer; + photoFrame: function() { + return _currentFrame; }, ensureViewerLoaded: function(context) { let that = this; - let imgWrap = context.container().select('#ideditor-viewer-panoramax-simple > img'); + let imgWrap = context.container() + .select('#ideditor-viewer-panoramax-simple > img'); if (!imgWrap.empty()) { imgWrap.remove(); @@ -539,7 +466,9 @@ export default { if (_loadViewerPromise) return _loadViewerPromise; - let wrap = context.container().select('.photoviewer').selectAll('.panoramax-wrapper') + let wrap = context.container() + .select('.photoviewer') + .selectAll('.panoramax-wrapper') .data([0]); //TODO maybe all of this should be in panoramax_images? @@ -549,31 +478,9 @@ export default { .classed('hide', true) .on('dblclick.zoom', null); - let pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; - wrapEnter .append('div') - .attr('id', 'ideditor-viewer-panoramax-pnlm') - .on(pointerPrefix + 'down.panoramax', () => { - d3_select(window) - .on(pointerPrefix + 'move.panoramax', () => { - dispatch.call('viewerChanged'); - }, true); - }) - .on(pointerPrefix + 'up.panoramax pointercancel.panoramax', () => { - d3_select(window) - .on(pointerPrefix + 'move.panoramax', null); - - // continue dispatching events for a few seconds, in case viewer has inertia. - let t = d3_timer(elapsed => { - dispatch.call('viewerChanged'); - if (elapsed > 1000) { - t.stop(); - } - }); - }) - .append('div') - .attr('class', 'photo-attribution fillD'); + .attr('class', 'photo-attribution fillD'); const controlsEnter = wrapEnter .append('div') @@ -593,67 +500,16 @@ export default { .on('click.forward', step(1)) .text('►'); - wrapEnter - .append('div') - .attr('id', 'ideditor-viewer-panoramax-pnlm'); - - wrapEnter - .append('div') - .attr('id', 'ideditor-viewer-panoramax-simple-wrap') - .call(imgZoom.on('zoom', zoomPan)) - .append('div') - .attr('id', 'ideditor-viewer-panoramax-simple'); - - - // Register viewer resize handler - context.ui().photoviewer.on('resize.panoramax', () => { - if (_pannellumViewer) { - _pannellumViewer.resize(); - } - }); - - _loadViewerPromise = new Promise((resolve, reject) => { - let loadedCount = 0; - function loaded() { - loadedCount += 1; - - // wait until both files are loaded - if (loadedCount === 2) resolve(); - } - - const head = d3_select('head'); - - // load pannellum-viewercss - head.selectAll('#ideditor-panoramax-viewercss') - .data([0]) - .enter() - .append('link') - .attr('id', 'ideditor-panoramax-viewercss') - .attr('rel', 'stylesheet') - .attr('crossorigin', 'anonymous') - .attr('href', context.asset(pannellumViewerCSS)) - .on('load.servicePanoramax', loaded) - .on('error.servicePanoramax', function() { - reject(); - }); - - // load pannellum-viewerjs - head.selectAll('#ideditor-panoramax-viewerjs') - .data([0]) - .enter() - .append('script') - .attr('id', 'ideditor-panoramax-viewerjs') - .attr('crossorigin', 'anonymous') - .attr('src', context.asset(pannellumViewerJS)) - .on('load.servicePanoramax', loaded) - .on('error.servicePanoramax', function() { - reject(); - }); - }) - .catch(function() { - _loadViewerPromise = null; - }); + _loadViewerPromise = Promise.all([ + pannellumPhotoFrame.init(context, wrapEnter), + planePhotoFrame.init(context, wrapEnter) + ]).then(([pannellumPhotoFrame, planePhotoFrame]) => { + _pannellumFrame = pannellumPhotoFrame; + _pannellumFrame.event.on('viewerChanged', () => dispatch.call('viewerChanged')); + _planeFrame = planePhotoFrame; + _planeFrame.event.on('viewerChanged', () => dispatch.call('viewerChanged')); + }); //TODO: maybe this should be here (export?) function step(stepBy) { @@ -666,15 +522,7 @@ export default { else nextId = _currentScene.prevImage.id; if (!nextId) return; - - let viewstate = { - yaw: _pannellumViewer.getYaw(), - pitch: _pannellumViewer.getPitch(), - hfov: _pannellumViewer.getHfov() - }; - _sceneOptions = Object.assign(_sceneOptions, viewstate); - const nextImage = _cache.images.forImageId[nextId]; context.map().centerEase(nextImage.loc); @@ -683,56 +531,35 @@ export default { }; } - function zoomPan(d3_event) { - var t = d3_event.transform; - context.container().select('.photoviewer #ideditor-viewer-panoramax-simple') - .call(utilSetTransform, t.x, t.y, t.k); - } - return _loadViewerPromise; }, - yaw: function(yaw) { - if (typeof yaw !== 'number') return yaw; - _sceneOptions.yaw = yaw; - return this; - }, - showViewer: function (context) { let wrap = context.container().select('.photoviewer') .classed('hide', false); - let isHidden = wrap.selectAll('.photo-wrapper.panoramax-wrapper.hide').size(); - if (isHidden) { wrap .selectAll('.photo-wrapper:not(.panoramax-wrapper)') .classed('hide', true); - wrap .selectAll('.photo-wrapper.panoramax-wrapper') .classed('hide', false); } - return this; }, hideViewer: function (context) { let viewer = context.container().select('.photoviewer'); if (!viewer.empty()) viewer.datum(null); - this.updateUrlImage(null); - viewer .classed('hide', true) .selectAll('.photo-wrapper') .classed('hide', true); - context.container().selectAll('.viewfield-group, .sequence, .icon-sign') .classed('currentView', false); - this.setActiveImage(); - return this.setStyles(context, null); }, diff --git a/modules/svg/panoramax_images.js b/modules/svg/panoramax_images.js index 87b7f9a59..70d852ec4 100644 --- a/modules/svg/panoramax_images.js +++ b/modules/svg/panoramax_images.js @@ -144,11 +144,10 @@ export function svgPanoramaxImages(projection, context, dispatch) { _selectedSequence = image.sequence_id; service - .ensureViewerLoaded(context, image.id) + .ensureViewerLoaded(context) .then(function() { service .selectImage(context, image.id) - .yaw(_viewerYaw) .showViewer(context); }); @@ -252,14 +251,13 @@ export function svgPanoramaxImages(projection, context, dispatch) { } function viewerChanged() { - var service = getService(); + const service = getService(); if (!service) return; - var viewer = service.viewer(); - if (!viewer) return; + const frame = service.photoFrame(); // update viewfield rotation - _viewerYaw = viewer.getYaw(); + _viewerYaw = frame.getYaw(); // avoid updating if the map is currently transformed // e.g. during drags or easing. @@ -299,7 +297,6 @@ export function svgPanoramaxImages(projection, context, dispatch) { if (enabled) { let zoom = ~~context.map().zoom(); - console.log(zoom) if (service){ if(zoom >= imageMinZoom) { editOn();