Spaces:
Running
Running
| // Example hotspot configuration (percent coordinates) | |
| const WS_HOTSPOTS = [ | |
| { left: '25%', top: '60%' }, | |
| { left: '60%', top: '40%' }, | |
| { left: '75%', top: '70%' }, | |
| ]; | |
| function wsRenderHotspots() { | |
| const $layer = $('#ws-hotspots-layer'); | |
| if (!$layer.length) return; | |
| $layer.empty(); | |
| WS_HOTSPOTS.forEach((pos) => { | |
| const $hotspot = $('<div/>') | |
| .addClass('ws-hotspot') | |
| .css({ | |
| left: pos.left, | |
| top: pos.top, | |
| transform: 'translate(-50%, -50%)', | |
| }); | |
| const $arrow = $('<div/>').addClass('ws-hotspot-arrow'); | |
| $hotspot.append($arrow); | |
| $layer.append($hotspot); | |
| }); | |
| } | |
| // Scene-based image mapping | |
| const WS_SCENE_IMAGES = { | |
| 215: { | |
| target: '/images/teaser_subfigures/215/tgt.png', | |
| stereospace: '/images/teaser_subfigures/215/stereospace.png', | |
| lyra: '/images/teaser_subfigures/215/lyra.png', | |
| genstereo: '/images/teaser_subfigures/215/genstereo.png', | |
| stereodiffusion: '/images/teaser_subfigures/215/stereodiffusion.png', | |
| zerostereo: '/images/teaser_subfigures/215/zerostereo.png', | |
| }, | |
| 249: { | |
| target: '/images/teaser_subfigures/249/tgt.png', | |
| stereospace: '/images/teaser_subfigures/249/stereospace.png', | |
| lyra: '/images/teaser_subfigures/249/lyra.png', | |
| genstereo: '/images/teaser_subfigures/249/genstereo.png', | |
| stereodiffusion: '/images/teaser_subfigures/249/stereodiffusion.png', | |
| zerostereo: '/images/teaser_subfigures/249/zerostereo.png', | |
| }, | |
| 252: { | |
| target: '/images/teaser_subfigures/252/tgt.png', | |
| stereospace: '/images/teaser_subfigures/252/stereospace.png', | |
| lyra: '/images/teaser_subfigures/252/lyra.png', | |
| genstereo: '/images/teaser_subfigures/252/genstereo.png', | |
| stereodiffusion: '/images/teaser_subfigures/252/stereodiffusion.png', | |
| zerostereo: '/images/teaser_subfigures/252/zerostereo.png', | |
| }, | |
| 285: { | |
| target: '/images/teaser_subfigures/285/tgt.png', | |
| stereospace: '/images/teaser_subfigures/285/stereospace.png', | |
| lyra: '/images/teaser_subfigures/285/lyra.png', | |
| genstereo: '/images/teaser_subfigures/285/genstereo.png', | |
| stereodiffusion: '/images/teaser_subfigures/285/stereodiffusion.png', | |
| zerostereo: '/images/teaser_subfigures/285/zerostereo.png', | |
| }, | |
| 297: { | |
| target: '/images/teaser_subfigures/297/tgt.png', | |
| stereospace: '/images/teaser_subfigures/297/stereospace.png', | |
| lyra: '/images/teaser_subfigures/297/lyra.png', | |
| genstereo: '/images/teaser_subfigures/297/genstereo.png', | |
| stereodiffusion: '/images/teaser_subfigures/297/stereodiffusion.png', | |
| zerostereo: '/images/teaser_subfigures/297/zerostereo.png', | |
| }, | |
| }; | |
| $(document).ready(function() { | |
| // Initialize state | |
| let currentScene = '215'; | |
| let currentModel = 'stereospace'; | |
| let sliderInitialized = false; | |
| // map model keys -> readable label shown on the slider | |
| const WS_MODEL_LABELS = { | |
| src: 'Input', | |
| tgt: 'Ground Truth', | |
| stereospace: 'StereoSpace (ours)', | |
| genstereo: 'GenStereo', | |
| lyra: 'Lyra', | |
| stereodiffusion: 'StereoDiffusion', | |
| zerostereo: 'ZeroStereo', | |
| }; | |
| // preload helper | |
| function wsPreloadImage(url) { | |
| return new Promise((resolve, reject) => { | |
| if (!url) return resolve(); | |
| // if already loaded by browser, resolve quickly | |
| const cached = Array.from(document.images).find(img => img.src && img.src.endsWith(url)); | |
| const img = new Image(); | |
| img.onload = () => resolve(url); | |
| img.onerror = () => reject(new Error('Failed to load ' + url)); | |
| img.src = url; | |
| }); | |
| } | |
| // Update labels on an already-initialized twentytwenty instance | |
| function wsSetSliderLabels(beforeLabel, afterLabel) { | |
| $('#ws-comparison-slider .twentytwenty-before-label').attr('data-content', beforeLabel); | |
| $('#ws-comparison-slider .twentytwenty-after-label').attr('data-content', afterLabel); | |
| const $slider = $('#ws-comparison-slider'); | |
| const $api = $slider.data('twentytwenty'); | |
| if ($api) { | |
| $api.adjustSlider(0.5); | |
| } | |
| } | |
| // Function to update images | |
| function updateImages(scene, model) { | |
| currentScene = scene; | |
| currentModel = model; | |
| const sceneData = WS_SCENE_IMAGES[scene]; | |
| if (!sceneData) return; | |
| // Preload all images we will use, then swap and (re)initialize slider. | |
| const leftUrl = sceneData.target; | |
| const rightUrl = sceneData[model]; | |
| // show light loading state if you have CSS for it | |
| $('#ws-comparison-container').addClass('ws-loading'); | |
| Promise.all([ | |
| wsPreloadImage(leftUrl), | |
| wsPreloadImage(rightUrl), | |
| ]).then(() => { | |
| $('#ws-image-left').attr('src', leftUrl); | |
| $('#ws-image-right').attr('src', rightUrl); | |
| const modelLabel = WS_MODEL_LABELS[model] || model; | |
| setTimeout(() => { | |
| wsSetSliderLabels('Ground Truth', modelLabel); | |
| $('#ws-comparison-container').removeClass('ws-loading'); | |
| }, 60); | |
| }).catch((err) => { | |
| console.warn('Image preload failed:', err); | |
| $('#ws-image-left').attr('src', leftUrl); | |
| $('#ws-image-right').attr('src', rightUrl); | |
| if (sliderInitialized) $('#ws-comparison-slider').trigger('destroy'); | |
| wsSetSliderLabels('Ground Truth', modelLabel); | |
| $('#ws-comparison-container').removeClass('ws-loading'); | |
| }); | |
| } | |
| // Gallery item clicks | |
| $('.ws-gallery-item').on('click', function() { | |
| $('.ws-gallery-item').removeClass('is-active'); | |
| $(this).addClass('is-active'); | |
| const scene = $(this).data('scene'); | |
| updateImages(scene, currentModel); | |
| }); | |
| // Model selector clicks | |
| $('.ws-model-pill[data-model]').on('click', function() { | |
| $('.ws-model-pill[data-model]').removeClass('is-active'); | |
| $(this).addClass('is-active'); | |
| const model = $(this).data('model'); | |
| updateImages(currentScene, model); | |
| }); | |
| // Initialize with default scene and model | |
| updateImages(currentScene, currentModel); | |
| }); |