// Comparison widget logic // Map model -> image path const WS_MODEL_IMAGES = { dai: '/images/comparison/car/dai.png', dsit: '/images/comparison/car/dsit.png', dsrnet: '/images/comparison/car/dsrnet.png', rdnet: '/images/comparison/car/rdnet.png', }; // 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 = $('
') .addClass('ws-hotspot') .css({ left: pos.left, top: pos.top, transform: 'translate(-50%, -50%)', }); const $arrow = $('
').addClass('ws-hotspot-arrow'); $hotspot.append($arrow); $layer.append($hotspot); }); } // Scene-based image mapping const WS_SCENE_IMAGES = { car: { original: '/images/comparison/car/original.jpg', windowseat: '/images/comparison/car/windowseat.png', dai: '/images/comparison/car/dai.png', dsit: '/images/comparison/car/dsit.png', dsrnet: '/images/comparison/car/dsrnet.png', rdnet: '/images/comparison/car/rdnet.png', }, uniqlo: { original: '/images/comparison/uniqlo/original.jpg', windowseat: '/images/comparison/uniqlo/windowseat.png', dai: '/images/comparison/uniqlo/dai.jpg', dsit: '/images/comparison/uniqlo/dsit.png', dsrnet: '/images/comparison/uniqlo/dsrnet.png', rdnet: '/images/comparison/uniqlo/rdnet.png', }, entrance: { original: '/images/comparison/entrance/original.jpg', windowseat: '/images/comparison/entrance/windowseat.png', dai: '/images/comparison/entrance/dai.jpg', dsit: '/images/comparison/entrance/dsit.png', dsrnet: '/images/comparison/entrance/dsrnet.png', rdnet: '/images/comparison/entrance/rdnet.png', }, zoo: { original: '/images/comparison/zoo/original.jpg', windowseat: '/images/comparison/zoo/windowseat.png', dai: '/images/comparison/zoo/dai.jpg', dsit: '/images/comparison/zoo/dsit.png', dsrnet: '/images/comparison/zoo/dsrnet.png', rdnet: '/images/comparison/zoo/rdnet.png', }, bakery: { original: '/images/comparison/bakery/original.jpg', windowseat: '/images/comparison/bakery/windowseat.png', dai: '/images/comparison/bakery/dai.jpg', dsit: '/images/comparison/bakery/dsit.png', dsrnet: '/images/comparison/bakery/dsrnet.png', rdnet: '/images/comparison/bakery/rdnet.png', }, museum: { original: '/images/comparison/museum/original.jpg', windowseat: '/images/comparison/museum/windowseat.png', dai: '/images/comparison/museum/dai.jpg', dsit: '/images/comparison/museum/dsit.png', dsrnet: '/images/comparison/museum/dsrnet.png', rdnet: '/images/comparison/museum/rdnet.png', }, }; function wsLoadScene(sceneName) { const sceneData = WS_SCENE_IMAGES[sceneName]; if (!sceneData) return; // Update left image (original input) $('#ws-image-left').attr('src', sceneData.original); // Update right image with current selected model const activeModel = $('.ws-model-pill[data-model].is-active').data('model') || 'dai'; $('#ws-image-right').attr('src', sceneData[activeModel]); } $(document).ready(function() { // Initialize state let currentScene = 'car'; let currentModel = 'dai'; let sliderInitialized = false; // map model keys -> readable label shown on the slider const WS_MODEL_LABELS = { dai: 'DAI', dsit: 'DSIT', dsrnet: 'DSRNet', rdnet: 'RDNet', }; // 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; }); } // Initialize the twentytwenty slider function initSlider(beforeLabel = 'Baseline') { $("#ws-comparison-slider").twentytwenty({ before_label: beforeLabel, after_label: 'WindowSeat', default_offset_pct: 0.5, }); sliderInitialized = true; // Clear any accidental zero clip applied by the plugin setTimeout(() => { $('.twentytwenty-overlay').css('clip', 'auto'); }, 50); } // Update labels on an already-initialized twentytwenty instance function wsSetSliderLabels(beforeLabel, afterLabel) { // plugin creates either "-label" or plain classes in different versions; update both $('#ws-comparison-slider .twentytwenty-before-label').attr('data-content', afterLabel); $('#ws-comparison-slider .twentytwenty-after-label').attr('data-content', beforeLabel); const $slider = $('#ws-comparison-slider'); const $api = $slider.data('twentytwenty'); if ($api) { // log something $api.adjustSlider(0.5); // reset to center } // log that labels were updated console.log('Updated slider labels to:', $wsSlider.find('.twentytwenty-before-label').attr('data-content'), $wsSlider.find('.twentytwenty-after-label').attr('data-content')); // log if $wsSlider exists console.log('Slider element exists:', $wsSlider.length > 0); } // 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.original; const windowseatUrl = sceneData.windowseat; const baselineUrl = sceneData[model]; // show light loading state if you have CSS for it $('#ws-comparison-container').addClass('ws-loading'); Promise.all([ wsPreloadImage(leftUrl), wsPreloadImage(windowseatUrl), wsPreloadImage(baselineUrl), ]).then(() => { // swap sources only after loaded $('#ws-image-left').attr('src', leftUrl); $('#ws-image-windowseat').attr('src', windowseatUrl); $('#ws-image-baseline').attr('src', baselineUrl); const modelLabel = WS_MODEL_LABELS[model] || model; // log sliderInitialized // destroy only if already initialized // if (sliderInitialized) { // $('#ws-comparison-slider').trigger('destroy'); // sliderInitialized = false; // } // small delay to allow browser layout, then init setTimeout(() => { // initSlider(modelLabel); // if the plugin was already initialized and you prefer updating labels instead of reinit: wsSetSliderLabels('WindowSeat', modelLabel); $('#ws-comparison-container').removeClass('ws-loading'); }, 60); }).catch((err) => { console.warn('Image preload failed:', err); // fallback: swap anyway and try init $('#ws-image-left').attr('src', leftUrl); $('#ws-image-windowseat').attr('src', windowseatUrl); $('#ws-image-baseline').attr('src', baselineUrl); if (sliderInitialized) $('#ws-comparison-slider').trigger('destroy'); // setTimeout(initSlider, 100); wsSetSliderLabels('WindowSeat', 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); // Remove or comment out hotspot code: /* // Hotspot toggle let hotspotsVisible = false; $('#ws-hotspots-toggle').on('click', function() { hotspotsVisible = !hotspotsVisible; if (hotspotsVisible) { wsRenderHotspots(); } else { $('#ws-hotspots-layer').empty(); } }); */ });