{"id":4189,"date":"2025-06-03T17:59:11","date_gmt":"2025-06-03T15:59:11","guid":{"rendered":"https:\/\/www.saccent.net\/articles-fr\/virtual-leather-swatch-viewer\/"},"modified":"2025-06-05T15:52:07","modified_gmt":"2025-06-05T13:52:07","slug":"virtual-leather-swatch-viewer","status":"publish","type":"post","link":"https:\/\/www.saccent.net\/fr\/virtual-leather-swatch-viewer\/","title":{"rendered":"Visualiseur virtuel d\u2019\u00e9chantillons de cuir"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"4189\" class=\"elementor elementor-4189 elementor-3794\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3c54f09 e-flex e-con-boxed e-con e-parent\" data-id=\"3c54f09\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b30eb03 elementor-widget elementor-widget-html\" data-id=\"b30eb03\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Visualiseur d'\u00c9chantillons de Cuir Virtuel<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <style>\n        body {\n            font-family: 'Inter', sans-serif;\n            background-color: #FFFFFF; \n            color: #1f2937; \n            margin: 0; \n            padding: 0; \n            overflow-x: hidden; \n        }\n\n        .app-container {\n            background-color: white;\n            width: 100%; \n            display: flex;\n            flex-direction: column;\n        }\n\n        .title-header {\n             margin-bottom: 1rem; \n             text-align: center;\n             padding-top: 1rem; \n        }\n\n        .title-header h1 {\n            font-size: 1.875rem; \n            font-weight: 700; \n            color: #FF9900; \n        }\n        \n        .main-content-area {\n            display: flex;\n            gap: 1rem; \n            width: 100%;\n            padding: 0 1rem; \n        }\n\n        .sidebar {\n            width: 150px; \n            flex-shrink: 0;\n            background-color: #f9fafb; \n            border-radius: 0.5rem; \n            padding: 0.75rem; \n            height: calc(100vh - 220px); \n            max-height: 500px; \n            overflow-y: auto;\n            display: flex;\n            flex-direction: column;\n            gap: 0.5rem; \n            border: 1px solid #e5e7eb; \n        }\n\n        .sidebar-title {\n            font-size: 0.875rem; \n            font-weight: 600; \n            color: #4b5563; \n            text-align: center;\n            margin-bottom: 0.5rem;\n            padding-bottom: 0.5rem;\n            border-bottom: 1px solid #e5e7eb; \n        }\n\n        .sidebar .thumbnail-item {\n            width: 100%;\n            aspect-ratio: 4 \/ 3; \n            border-radius: 0.375rem; \n            cursor: pointer;\n            border: 2px solid transparent;\n            transition: border-color 0.2s ease-in-out, transform 0.2s ease-in-out;\n            overflow: hidden; \n            position: relative; \n        }\n        .sidebar .thumbnail-item img {\n            width: 100%;\n            height: 100%;\n            object-fit: cover;\n            display: block; \n        }\n\n        .sidebar .thumbnail-name {\n            position: absolute;\n            bottom: 0;\n            left: 0;\n            right: 0;\n            background-color: rgba(0, 0, 0, 0.6); \n            color: white;\n            font-size: 0.75rem; \n            padding: 0.25rem 0.5rem; \n            text-align: center;\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis; \n            border-bottom-left-radius: 0.25rem; \n            border-bottom-right-radius: 0.25rem;\n        }\n\n        .sidebar .thumbnail-item:hover {\n            border-color: #FFBB33; \n            transform: scale(1.05);\n        }\n        .sidebar .thumbnail-item.active {\n            border-color: #FF9900; \n            box-shadow: 0 0 0 2px #FF9900; \n            transform: scale(1.03);\n        }\n\n        .image-comparison-container {\n            position: relative;\n            flex-grow: 1; \n            max-width: 700px; \n            min-width: 300px; \n            margin: 0 auto; \n            border-radius: 0.5rem; \n            overflow: hidden;  \n            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); \n            user-select: none; \n            height: 500px; \n        }\n\n        .image-compare { \n            position: relative;\n            width: 100%;\n            height: 100%; \n        }\n\n        .image-compare img, \n        .image-compare-overlay img {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            object-fit: cover; \n        }\n\n        #imageLeft { \n            border-top-left-radius: 0px;\n            border-bottom-left-radius: 0px;\n            border-top-right-radius: 0.5rem; \n            border-bottom-right-radius: 0.5rem; \n        }\n\n        #imageRight { \n            border-top-left-radius: 0.5rem; \n            border-bottom-left-radius: 0.5rem; \n            border-top-right-radius: 0px;\n            border-bottom-right-radius: 0px;\n        }\n\n        .image-compare-overlay { \n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 50%; \n            height: 100%;\n            overflow: hidden; \n            z-index: 10;\n            box-sizing: border-box;\n        }\n        \n        #dragHandle { \n            position: absolute;\n            top: 50%;\n            transform: translate(-50%, -50%); \n            width: 40px;\n            height: 40px;\n            background-color: #FF9900; \n            border-radius: 50%;\n            cursor: ew-resize;\n            z-index: 20; \n            display: flex;\n            align-items: center;\n            justify-content: center;\n            box-shadow: 0 0 10px rgba(0,0,0,0.3);\n            border: 2px solid white;\n        }\n\n        #dragHandle svg {\n            width: 22px; \n            height: 22px; \n            fill: white; \n            pointer-events: none; \n        }\n        \n        .loading-indicator {\n            display: none; \n            position: absolute;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%);\n            font-size: 1rem;\n            color: #FF9900; \n            z-index: 30; \n        }\n        .image-compare.loading .loading-indicator {\n            display: block;\n        }\n        .image-compare.loading img {\n            opacity: 0.3;\n        }\n\n        .fallback-text {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            width: 100%;\n            height: 100%;\n            background-color: #e5e7eb; \n            color: #6b7280; \n            font-size: 0.875rem; \n            border-radius: 0.5rem; \n            position: absolute;\n            top:0; left:0;\n        }\n        \n        .swatch-comparison-details {\n            background-color: #f9fafb; \n            padding: 1rem; \n            border-radius: 0.5rem; \n            margin: 1.5rem 1rem 1rem; \n            border: 1px solid #e5e7eb; \n        }\n        .swatch-comparison-details h3 {\n            font-size: 1.125rem; \n            font-weight: 600; \n            margin-bottom: 0.75rem; \n            text-align: center;\n            color: #FF9900; \n        }\n        .comparison-text-container {\n            font-size: 0.875rem; \n            line-height: 1.6; \n            color: #374151; \n        }\n        .comparison-text-container strong {\n            font-weight: 600;\n            color: #4b5563; \n        }\n         .comparison-text-container .swatch-name-highlight {\n            color: #FF9900; \n            font-weight: bold;\n        }\n\n\n        .footer-text {\n            margin-top: 1rem; \n            text-align: center;\n            font-size: 0.875rem; \n            color: #6b7280; \n            width: 100%;\n            padding-bottom: 1rem; \n        }\n        \n        @media (max-width: 768px) {\n            .main-content-area {\n                flex-direction: column;\n                align-items: center;\n                padding: 0 0.5rem; \n            }\n            .sidebar {\n                width: 100%;\n                max-width: none; \n                height: 150px; \n                flex-direction: row; \n                overflow-x: auto; \n                overflow-y: hidden;\n                padding: 0.5rem;\n            }\n            .sidebar .thumbnail-item {\n                width: 100px; \n                height: 75px; \n                flex-shrink: 0; \n            }\n             .sidebar .thumbnail-name {\n                font-size: 0.65rem; \n                padding: 0.15rem 0.3rem;\n            }\n            .sidebar-title {\n                display: none; \n            }\n            .image-comparison-container {\n                width: 100%;\n                height: 400px; \n            }\n            .swatch-comparison-details {\n                 margin: 1.5rem 0.5rem 1rem; \n            }\n        }\n\n    <\/style>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n<\/head>\n<body>\n    <div class=\"app-container\">\n        <header class=\"title-header\">\n            <h1>Visualiseur d'\u00c9chantillons de Cuir Virtuel<\/h1>\n        <\/header>\n\n        <div class=\"main-content-area\">\n            <aside id=\"leftSidebar\" class=\"sidebar\">\n                <div class=\"sidebar-title\">\u00c9chantillons Gauche<\/div>\n            <\/aside>\n\n            <section class=\"image-comparison-container\" id=\"imageComparisonContainer\">\n                <div class=\"image-compare\" id=\"imageCompareWrapper\">\n                    <img decoding=\"async\" id=\"imageLeft\" src=\"https:\/\/placehold.co\/800x600\/E2E8F0\/4A5568?text=Chargement...\" alt=\"\u00c9chantillon de Cuir - Base\" onerror=\"this.style.display='none'; this.nextElementSibling.style.display='flex';\">\n                    <div class=\"fallback-text\" style=\"display:none;\">Image de base indisponible<\/div>\n\n                    <div class=\"image-compare-overlay\" id=\"imageCompareOverlay\">\n                        <img decoding=\"async\" id=\"imageRight\" src=\"https:\/\/placehold.co\/800x600\/CBD5E0\/2D3748?text=Chargement...\" alt=\"\u00c9chantillon de Cuir - Superposition\" onerror=\"this.style.display='none'; this.nextElementSibling.style.display='flex';\">\n                        <div class=\"fallback-text\" style=\"display:none;\">Image de superposition indisponible<\/div>\n                    <\/div>\n                    <div id=\"dragHandle\">\n                        <svg viewBox=\"0 0 24 24\"> \n                            <path fill=\"currentColor\" d=\"M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z\"><\/path>\n                        <\/svg>\n                    <\/div>\n                    <div class=\"loading-indicator\">Chargement des \u00e9chantillons...<\/div>\n                <\/div>\n            <\/section>\n\n            <aside id=\"rightSidebar\" class=\"sidebar\">\n                <div class=\"sidebar-title\">\u00c9chantillons Droite<\/div>\n            <\/aside>\n        <\/div>\n\n        <section class=\"swatch-comparison-details\">\n            <h3>Comparaison des \u00c9chantillons<\/h3>\n            <div id=\"comparisonTextContainer\" class=\"comparison-text-container\">\n                <p>S\u00e9lectionnez des \u00e9chantillons dans les barres lat\u00e9rales pour voir leur comparaison ici.<\/p>\n            <\/div>\n        <\/section>\n\n        <footer class=\"footer-text\">\n            <p>Faites glisser la poign\u00e9e circulaire pour comparer les vues. S\u00e9lectionnez les \u00e9chantillons dans les barres lat\u00e9rales.<\/p>\n        <\/footer>\n    <\/div>\n\n    <script>\n        const leatherSwatches = [\n            { \n                name: \"Pleine Fleur\", \n                id: \"full_grain\", \n                imageLeft: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/05\/full-grain-leather.jpeg\", \n                imageRight: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/05\/full-grain-leather.jpeg\",\n                description: \"Le cuir Pleine Fleur est la qualit\u00e9 la plus \u00e9lev\u00e9e. Il provient de la couche sup\u00e9rieure de la peau et conserve tout le grain naturel, gardant sa robustesse et ses imperfections inh\u00e9rentes. Il d\u00e9veloppe une belle patine avec le temps.\"\n            },\n            { \n                name: \"Fleur Corrig\u00e9e\", \/\/ Top Grain\n                id: \"top_grain\",\n                imageLeft: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/top-grain-leather.jpg\", \n                imageRight: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/top-grain-leather.jpg\",\n                description: \"Le cuir Fleur Corrig\u00e9e (Top Grain) est la deuxi\u00e8me meilleure qualit\u00e9. La surface a \u00e9t\u00e9 ponc\u00e9e et une couche de finition appliqu\u00e9e, ce qui lui donne un aspect plus uniforme. Il est plus r\u00e9sistant aux taches que le cuir pleine fleur mais moins durable.\"\n            },\n            { \n                name: \"Cro\u00fbte Velours\", \/\/ Split Suede\n                id: \"suede\",\n                imageLeft: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/05\/suede-leather.jpg\", \n                imageRight: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/05\/suede-leather.jpg\",\n                description: \"Le su\u00e8de (Cro\u00fbte Velours) est fabriqu\u00e9 \u00e0 partir de la couche interne de la peau (la refente ou cro\u00fbte). Il a une surface duveteuse, est plus doux et moins durable que le cuir pleine fleur ou fleur corrig\u00e9e. Souvent utilis\u00e9 pour des articles d\u00e9licats.\"\n            },\n            { \n                name: \"Cuir Reconstitu\u00e9\", \/\/ Bonded\n                id: \"bonded\",\n                imageLeft: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/Bonded-Leather.jpg\", \n                imageRight: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/Bonded-Leather.jpg\",\n                description: \"Le cuir reconstitu\u00e9 (Bonded) est fabriqu\u00e9 \u00e0 partir de chutes de cuir d\u00e9chiquet\u00e9es et agglom\u00e9r\u00e9es avec du polyur\u00e9thane ou du latex sur une feuille de fibres. C'est la qualit\u00e9 la plus basse et la moins durable.\"\n            },\n            { \n                name: \"Nubuck\", \n                id: \"nubuck\",\n                imageLeft: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/Nubuk-leather.jpg\", \n                imageRight: \"https:\/\/www.saccent.net\/wp-content\/uploads\/2025\/06\/Nubuk-leather.jpg\",\n                description: \"Le Nubuck est un cuir de bovin de type fleur corrig\u00e9e qui a \u00e9t\u00e9 ponc\u00e9 ou poli c\u00f4t\u00e9 fleur pour obtenir un l\u00e9ger duvet de fibres prot\u00e9iques courtes, produisant une surface semblable \u00e0 du velours. Il est plus durable que le su\u00e8de mais peut se tacher facilement.\"\n            }\n        ];\n\n        const pairwiseComparisons = {\n            \"full_grain_top_grain\": \"Bien que le <span class='swatch-name-highlight'>Pleine Fleur<\/span> et la <span class='swatch-name-highlight'>Fleur Corrig\u00e9e<\/span> soient des cuirs de haute qualit\u00e9, le Pleine Fleur conserve la surface naturelle compl\u00e8te, offrant une durabilit\u00e9 maximale et une patine unique avec le temps. La Fleur Corrig\u00e9e est l\u00e9g\u00e8rement trait\u00e9e pour une apparence plus uniforme et une r\u00e9sistance aux taches, mais est un peu moins robuste que le Pleine Fleur.\",\n            \"full_grain_suede\": \"Le <span class='swatch-name-highlight'>Pleine Fleur<\/span> est pris\u00e9 pour sa r\u00e9sistance et son aspect naturel, \u00e9tant la couche la plus externe de la peau. La <span class='swatch-name-highlight'>Cro\u00fbte Velours<\/span> (Su\u00e8de), issue d'une couche interne, est beaucoup plus douce avec une finition duveteuse, id\u00e9ale pour le confort mais moins r\u00e9sistante \u00e0 l'usure et aux taches.\",\n            \"bonded_full_grain\": \"Il y a une diff\u00e9rence significative : le <span class='swatch-name-highlight'>Pleine Fleur<\/span> est le cuir premium, le plus naturel et durable. Le <span class='swatch-name-highlight'>Cuir Reconstitu\u00e9<\/span> (Bonded), fabriqu\u00e9 \u00e0 partir de chutes, offre une apparence similaire au cuir \u00e0 moindre co\u00fbt mais manque de la r\u00e9sistance et de la long\u00e9vit\u00e9 du Pleine Fleur.\",\n            \"full_grain_nubuck\": \"Le <span class='swatch-name-highlight'>Pleine Fleur<\/span> met en valeur la surface naturelle de la peau. Le <span class='swatch-name-highlight'>Nubuck<\/span> est \u00e9galement un cuir de type fleur corrig\u00e9e mais il est poli pour cr\u00e9er un toucher doux et velout\u00e9, similaire au su\u00e8de mais g\u00e9n\u00e9ralement plus durable. Les deux sont de haute qualit\u00e9, diff\u00e9rant principalement par la texture et la finition.\",\n            \"suede_top_grain\": \"Le cuir <span class='swatch-name-highlight'>Fleur Corrig\u00e9e<\/span> offre une surface lisse et finie avec une bonne durabilit\u00e9. La <span class='swatch-name-highlight'>Cro\u00fbte Velours<\/span> (Su\u00e8de) procure une texture douce et duveteuse et est plus flexible, mais elle est moins r\u00e9sistante aux salissures et \u00e0 l'usure par rapport \u00e0 la Fleur Corrig\u00e9e.\",\n            \"bonded_top_grain\": \"La <span class='swatch-name-highlight'>Fleur Corrig\u00e9e<\/span> est un cuir v\u00e9ritable et durable avec une finition corrig\u00e9e. Le <span class='swatch-name-highlight'>Cuir Reconstitu\u00e9<\/span> (Bonded) est un mat\u00e9riau composite fabriqu\u00e9 \u00e0 partir de fibres de cuir, significativement moins durable et non consid\u00e9r\u00e9 comme du vrai cuir de peau comme la Fleur Corrig\u00e9e.\",\n            \"nubuck_top_grain\": \"La <span class='swatch-name-highlight'>Fleur Corrig\u00e9e<\/span> et le <span class='swatch-name-highlight'>Nubuck<\/span> proviennent tous deux de la couche sup\u00e9rieure de la peau. La Fleur Corrig\u00e9e a typiquement une finition pigment\u00e9e et lisse. Le Nubuck est poli pour obtenir une texture douce et velout\u00e9e, ce qui le rend luxueux mais n\u00e9cessite plus d'entretien que la Fleur Corrig\u00e9e standard.\",\n            \"bonded_suede\": \"La <span class='swatch-name-highlight'>Cro\u00fbte Velours<\/span> (Su\u00e8de) est un cuir v\u00e9ritable issu d'une refente int\u00e9rieure de la peau, connu pour sa douceur. Le <span class='swatch-name-highlight'>Cuir Reconstitu\u00e9<\/span> (Bonded) est un produit manufactur\u00e9 \u00e0 partir de chutes de cuir, offrant un prix inf\u00e9rieur mais beaucoup moins de durabilit\u00e9 et un toucher diff\u00e9rent de celui du Su\u00e8de.\",\n            \"bonded_nubuck\": \"Le <span class='swatch-name-highlight'>Nubuck<\/span> est un cuir de qualit\u00e9 de type fleur corrig\u00e9e avec une surface douce et polie. Le <span class='swatch-name-highlight'>Cuir Reconstitu\u00e9<\/span> (Bonded) est un mat\u00e9riau reconstitu\u00e9, non comparable en termes de qualit\u00e9, de durabilit\u00e9 ou de toucher naturel au Nubuck.\",\n            \"nubuck_suede\": \"Le <span class='swatch-name-highlight'>Nubuck<\/span> et la <span class='swatch-name-highlight'>Cro\u00fbte Velours<\/span> (Su\u00e8de) ont tous deux une finition douce et duveteuse. Le Nubuck est fabriqu\u00e9 en pon\u00e7ant le c\u00f4t\u00e9 fleur du cuir fleur corrig\u00e9e, ce qui le rend g\u00e9n\u00e9ralement plus durable que le Su\u00e8de, qui provient du c\u00f4t\u00e9 chair ou d'une refente. Les deux n\u00e9cessitent un entretien pour maintenir leur apparence.\"\n        };\n\n        const imageLeftElement = document.getElementById('imageLeft'); \n        const imageRightElement = document.getElementById('imageRight'); \n        \n        const leftSidebar = document.getElementById('leftSidebar');\n        const rightSidebar = document.getElementById('rightSidebar');\n\n        const imageCompareOverlay = document.getElementById('imageCompareOverlay');\n        const imageCompareWrapper = document.getElementById('imageCompareWrapper');\n        const dragHandle = document.getElementById('dragHandle');\n\n        const comparisonTextContainer = document.getElementById('comparisonTextContainer');\n        \n        let currentLeftSwatchIndex = 0;  \n        let currentRightSwatchIndex = 1; \n        let imagesCurrentlyLoading = 0;\n\n        function updateLoadingIndicator() {\n            if (imagesCurrentlyLoading > 0) {\n                imageCompareWrapper.classList.add('loading');\n            } else {\n                imageCompareWrapper.classList.remove('loading');\n            }\n        }\n        \n        function loadMainImage(index, side) {\n            if (index < 0 || index >= leatherSwatches.length) {\n                console.error(\"Index d'\u00e9chantillon invalide :\", index, \"pour le c\u00f4t\u00e9 :\", side);\n                return;\n            }\n\n            const swatch = leatherSwatches[index];\n            const imageElement = side === 'left' ? imageRightElement : imageLeftElement; \n            const imageToDisplay = swatch.imageLeft; \n\n            imageElement.style.display = 'block';\n            const fallbackElement = imageElement.nextElementSibling;\n            if (fallbackElement && fallbackElement.classList.contains('fallback-text')) {\n                fallbackElement.style.display = 'none';\n            }\n\n            imagesCurrentlyLoading++;\n            updateLoadingIndicator();\n\n            imageElement.onload = () => {\n                imagesCurrentlyLoading--;\n                updateLoadingIndicator();\n            };\n            imageElement.onerror = () => {\n                imagesCurrentlyLoading--;\n                updateLoadingIndicator();\n                imageElement.style.display = 'none';\n                if (fallbackElement && fallbackElement.classList.contains('fallback-text')) {\n                    fallbackElement.style.display = 'flex';\n                }\n                if (imageElement === imageLeftElement) {\n                    imageElement.src = `https:\/\/placehold.co\/800x600\/E2E8F0\/4A5568?text=${swatch.name.replace(\/\\s\/g, '+')}+Base+Indisponible`;\n                } else {\n                    imageElement.src = `https:\/\/placehold.co\/800x600\/CBD5E0\/2D3748?text=${swatch.name.replace(\/\\s\/g, '+')}+Superposition+Indisponible`;\n                }\n                imageElement.style.display = 'block'; \n            };\n\n            imageElement.src = imageToDisplay;\n            const imageRole = (imageElement === imageLeftElement) ? \"Base\" : \"Superposition\";\n            imageElement.alt = `${swatch.name} - Vue ${imageRole}`;\n            \n            updateActiveThumbnail(index, side);\n            updateComparisonDetails(); \n        }\n\n        function populateSidebar(sidebarElement, side) {\n            const titleElement = sidebarElement.querySelector('.sidebar-title');\n            sidebarElement.innerHTML = ''; \n            if (titleElement) { \n                 sidebarElement.appendChild(titleElement);\n            }\n\n            leatherSwatches.forEach((swatch, index) => {\n                const thumbContainer = document.createElement('div');\n                thumbContainer.classList.add('thumbnail-item');\n                thumbContainer.dataset.index = index; \n                thumbContainer.setAttribute('role', 'button');\n                thumbContainer.setAttribute('tabindex', '0'); \n                thumbContainer.setAttribute('aria-label', `S\u00e9lectionner ${swatch.name}`);\n\n                const thumbImg = document.createElement('img');\n                thumbImg.src = swatch.imageLeft; \n                thumbImg.alt = `Miniature de ${swatch.name}`;\n                thumbImg.onerror = function() { \n                    thumbContainer.innerHTML = `<div class=\"fallback-text\" style=\"font-size:0.7em; display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:#ccc;\">Miniature N\/A<\/div>`;\n                    this.onerror=null; \n                    this.src=`https:\/\/placehold.co\/120x90\/cccccc\/999999?text=Erreur`;\n                }\n                thumbContainer.appendChild(thumbImg);\n\n                const nameOverlay = document.createElement('div');\n                nameOverlay.classList.add('thumbnail-name');\n                nameOverlay.textContent = swatch.name;\n                thumbContainer.appendChild(nameOverlay);\n                \n                thumbContainer.addEventListener('click', () => handleThumbnailClick(index, side));\n                thumbContainer.addEventListener('keydown', (event) => {\n                    if (event.key === 'Enter' || event.key === ' ') {\n                        event.preventDefault();\n                        handleThumbnailClick(index, side);\n                    }\n                });\n                sidebarElement.appendChild(thumbContainer);\n            });\n        }\n\n        function handleThumbnailClick(index, side) {\n            if (side === 'left') {\n                currentLeftSwatchIndex = index; \n            } else { \n                currentRightSwatchIndex = index; \n            }\n            loadMainImage(index, side); \n        }\n        \n        function updateActiveThumbnail(activeIndex, side) {\n            const sidebarElement = side === 'left' ? leftSidebar : rightSidebar;\n            const thumbnails = sidebarElement.querySelectorAll('.thumbnail-item');\n            thumbnails.forEach((thumb) => { \n                if (parseInt(thumb.dataset.index) === activeIndex) {\n                    thumb.classList.add('active');\n                    thumb.setAttribute('aria-pressed', 'true');\n                } else {\n                    thumb.classList.remove('active');\n                    thumb.setAttribute('aria-pressed', 'false');\n                }\n            });\n        }\n\n        function getComparisonKey(id1, id2) {\n            return [id1, id2].sort().join('_');\n        }\n\n        function updateComparisonDetails() {\n            const leftSwatch = leatherSwatches[currentLeftSwatchIndex]; \n            const rightSwatch = leatherSwatches[currentRightSwatchIndex]; \n\n            let htmlContent = \"\";\n\n            if (leftSwatch && rightSwatch) {\n                if (leftSwatch.id === rightSwatch.id) {\n                    htmlContent = `<p>Vous visualisez deux instances de <span class=\"swatch-name-highlight\">${leftSwatch.name}<\/span>. ${leftSwatch.description}<\/p>`;\n                } else {\n                    const comparisonKey = getComparisonKey(leftSwatch.id, rightSwatch.id);\n                    const comparisonText = pairwiseComparisons[comparisonKey];\n                    if (comparisonText) {\n                        htmlContent = `<p>${comparisonText}<\/p>`;\n                    } else {\n                        \/\/ Fallback if a specific pairwise comparison isn't defined\n                        htmlContent = `\n                            <p><span class=\"swatch-name-highlight\">${leftSwatch.name} (Image Sup\u00e9rieure\/Superpos\u00e9e):<\/span> ${leftSwatch.description}<\/p>\n                            <hr class=\"my-2 border-gray-300\">\n                            <p><span class=\"swatch-name-highlight\">${rightSwatch.name} (Image Inf\u00e9rieure\/Base):<\/span> ${rightSwatch.description}<\/p>\n                            <p class=\"mt-2 text-xs text-gray-500\"><i>La comparaison sp\u00e9cifique pour cette paire n'est pas encore disponible. Affichage des descriptions individuelles.<\/i><\/p>\n                        `;\n                    }\n                }\n            } else {\n                htmlContent = \"<p>S\u00e9lectionnez des \u00e9chantillons dans les deux barres lat\u00e9rales pour voir leur comparaison ici.<\/p>\";\n            }\n            comparisonTextContainer.innerHTML = htmlContent;\n        }\n\n\n        let isDragging = false;\n        let startX, initialOverlayWidthPercent;\n\n        function setOverlayAndHandleWidth(percent) {\n            percent = Math.max(0, Math.min(100, percent)); \n            imageCompareOverlay.style.width = percent + '%';\n            dragHandle.style.left = percent + '%';\n        }\n\n        function startDrag(clientX) {\n            isDragging = true;\n            startX = clientX;\n            const overlayRect = imageCompareOverlay.getBoundingClientRect();\n            const containerRect = document.getElementById('imageComparisonContainer').getBoundingClientRect(); \n            if (containerRect.width === 0) { \n                 initialOverlayWidthPercent = 50;\n            } else {\n                initialOverlayWidthPercent = (overlayRect.width \/ containerRect.width) * 100;\n            }\n            document.getElementById('imageComparisonContainer').style.cursor = 'ew-resize';\n            document.body.style.cursor = 'ew-resize';\n        }\n\n        function onDrag(clientX) {\n            if (!isDragging) return;\n            const dx = clientX - startX;\n            const containerRect = document.getElementById('imageComparisonContainer').getBoundingClientRect();\n            \n            if (containerRect.width === 0) return; \n\n            const dxPercent = (dx \/ containerRect.width) * 100;\n            let newWidthPercent = initialOverlayWidthPercent + dxPercent;\n            setOverlayAndHandleWidth(newWidthPercent);\n        }\n\n        function stopDrag() {\n            if (!isDragging) return;\n            isDragging = false;\n            document.getElementById('imageComparisonContainer').style.cursor = 'default';\n            document.body.style.cursor = 'default';\n        }\n\n        dragHandle.addEventListener('mousedown', (e) => { e.preventDefault(); startDrag(e.clientX); });\n        dragHandle.addEventListener('touchstart', (e) => { e.preventDefault(); startDrag(e.touches[0].clientX); }, { passive: false });\n        document.addEventListener('mousemove', (e) => { onDrag(e.clientX); });\n        document.addEventListener('touchmove', (e) => { if (isDragging) { e.preventDefault(); onDrag(e.touches[0].clientX);}}, { passive: false });\n        document.addEventListener('mouseup', stopDrag);\n        document.addEventListener('touchend', stopDrag);\n        document.addEventListener('mouseleave', stopDrag); \n\n        document.addEventListener('DOMContentLoaded', () => {\n            if (leatherSwatches.length > 0) {\n                if (currentLeftSwatchIndex >= leatherSwatches.length) currentLeftSwatchIndex = 0;\n                if (leatherSwatches.length === 1) {\n                     currentRightSwatchIndex = 0;\n                } else {\n                    if (currentRightSwatchIndex >= leatherSwatches.length) currentRightSwatchIndex = 0; \n                    if (currentRightSwatchIndex === currentLeftSwatchIndex) {\n                         currentRightSwatchIndex = (currentLeftSwatchIndex + 1) % leatherSwatches.length;\n                    }\n                }\n\n                populateSidebar(leftSidebar, 'left');\n                populateSidebar(rightSidebar, 'right');\n                \n                loadMainImage(currentLeftSwatchIndex, 'left'); \n                loadMainImage(currentRightSwatchIndex, 'right'); \n            } else {\n                leftSidebar.innerHTML = '<p class=\"text-center text-gray-500 text-sm\">Aucun \u00e9chantillon<\/p>';\n                rightSidebar.innerHTML = '<p class=\"text-center text-gray-500 text-sm\">Aucun \u00e9chantillon<\/p>';\n                imageCompareWrapper.classList.remove('loading');\n                dragHandle.style.display = 'none';\n                document.querySelector('.swatch-comparison-details').style.display = 'none';\n            }\n            setOverlayAndHandleWidth(50); \n        });\n    <\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Visualiseur d&rsquo;\u00c9chantillons de Cuir Virtuel Visualiseur d&rsquo;\u00c9chantillons de Cuir Virtuel \u00c9chantillons Gauche Image de base indisponible Image de superposition indisponible Chargement des \u00e9chantillons&#8230; \u00c9chantillons Droite Comparaison des \u00c9chantillons S\u00e9lectionnez des \u00e9chantillons dans les barres lat\u00e9rales pour voir leur comparaison ici. Faites glisser la poign\u00e9e circulaire pour comparer les vues. S\u00e9lectionnez les \u00e9chantillons dans les barres [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"elementor_header_footer","format":"standard","meta":{"_acf_changed":false,"slim_seo":{"title":"Visualiseur virtuel d\u2019\u00e9chantillons de cuir - Saccent","description":"Visualiseur d'\u00c9chantillons de Cuir Virtuel Visualiseur d'\u00c9chantillons de Cuir Virtuel \u00c9chantillons Gauche Image de base indisponible Image de superposition indi"},"footnotes":""},"categories":[84],"tags":[],"class_list":["post-4189","post","type-post","status-publish","format-standard","hentry","category-outils"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/posts\/4189","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/comments?post=4189"}],"version-history":[{"count":5,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/posts\/4189\/revisions"}],"predecessor-version":[{"id":4194,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/posts\/4189\/revisions\/4194"}],"wp:attachment":[{"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/media?parent=4189"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/categories?post=4189"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.saccent.net\/fr\/wp-json\/wp\/v2\/tags?post=4189"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}