if (!window.MDWNonce111) { window.MDWNonce111 = true; const selector = "[class^='mdw-curved-slider'], [class*=' mdw-curved-slider']"; const scene = [], renderer = [], camera = [], planes = [], slideAmount = [], options = [], targetPosition = [], currentSlide = [], isAnimating = [], autoplayInterval = [], isDragging = [], dragStart = [], dragCurrent = [], touchAxisLocked = [], touchIsHorizontal = []; document.addEventListener("DOMContentLoaded", function () { function getWidth(gap) { return 1 + gap / 100; } function getPlaneWidth(el, camera) { const vFov = (camera.fov * Math.PI) / 180; const height = 2 * Math.tan(vFov / 2) * camera.position.z; const aspect = el.clientWidth / el.clientHeight; const width = height * aspect; return el.clientWidth / width; } function init() { document.querySelectorAll(selector).forEach((el, index) => { const gallery = el.querySelector(".elementor-widget-image-gallery"); if (!gallery) return; const imgs = gallery.querySelectorAll(".gallery-item img"); const images = [...imgs].map((img) => img.getAttribute("src")); // Get links from image captions or alt text const links = [...imgs].map((img) => { // Try to get link from caption first const galleryItem = img.closest(".gallery-item"); const caption = galleryItem ? galleryItem.querySelector(".gallery-caption") : null; if (caption && caption.textContent.trim()) { return caption.textContent.trim(); } // If no caption, try alt attribute const alt = img.getAttribute("alt"); if (alt && alt.trim()) { return alt.trim(); } return null; }); if (!images.length) return; options[index] = { speed: 30, gap: 15, curve: 12, direction: -1, autoplay: true, autoplaySpeed: 3000, // 3 seconds }; scene[index] = new THREE.Scene(); camera[index] = new THREE.PerspectiveCamera( 75, el.clientWidth / el.clientHeight, 0.1, 20 ); camera[index].position.z = 1.4; renderer[index] = new THREE.WebGLRenderer({ alpha: true, antialias: true, }); renderer[index].setSize(el.clientWidth, el.clientHeight); renderer[index].setPixelRatio(window.devicePixelRatio); const oldCanvas = el.querySelector("canvas"); if (oldCanvas) oldCanvas.remove(); el.appendChild(renderer[index].domElement); let controls = el.querySelector(".mdw-slider-controls"); if (!controls) { controls = document.createElement("div"); controls.classList.add("mdw-slider-controls"); controls.innerHTML = ` `; el.appendChild(controls); } const geometry = new THREE.PlaneGeometry(1, 1, 20, 20); planes[index] = []; slideAmount[index] = images.length; // Start at first slide (index 0) currentSlide[index] = 0; // Create triple set of images for seamless loop const tripleImages = [...images, ...images, ...images]; const tripleLinks = [...links, ...links, ...links]; for (let i = 0; i { stopAutoplay(index); moveToPrev(index); startAutoplay(index); }; controls.querySelector(".next").onclick = () => { stopAutoplay(index); moveToNext(index); startAutoplay(index); }; // Add click event to canvas for navigation renderer[index].domElement.addEventListener('click', (event) => { // Don't navigate if was dragging if (Math.abs(dragCurrent[index]) > 5) return; stopAutoplay(index); const rect = renderer[index].domElement.getBoundingClientRect(); const x = ((event.clientX - rect.left) / rect.width) * 2 - 1; const y = -((event.clientY - rect.top) / rect.height) * 2 + 1; const raycaster = new THREE.Raycaster(); raycaster.setFromCamera({ x, y }, camera[index]); const intersects = raycaster.intersectObjects(planes[index]); if (intersects.length > 0) { const clickedMesh = intersects[0].object; const link = clickedMesh.userData.link; if (link) { window.location.href = link; } } startAutoplay(index); }); // Add pointer cursor on hover renderer[index].domElement.addEventListener('mousemove', (event) => { const rect = renderer[index].domElement.getBoundingClientRect(); const x = ((event.clientX - rect.left) / rect.width) * 2 - 1; const y = -((event.clientY - rect.top) / rect.height) * 2 + 1; const raycaster = new THREE.Raycaster(); raycaster.setFromCamera({ x, y }, camera[index]); const intersects = raycaster.intersectObjects(planes[index]); if (intersects.length > 0 && intersects[0].object.userData.link) { renderer[index].domElement.style.cursor = 'pointer'; } else { renderer[index].domElement.style.cursor = 'default'; } }); // Pause autoplay on hover renderer[index].domElement.addEventListener('mouseenter', () => { stopAutoplay(index); }); renderer[index].domElement.addEventListener('mouseleave', () => { startAutoplay(index); }); // Drag functionality renderer[index].domElement.addEventListener('mousedown', (e) => { isDragging[index] = true; dragStart[index] = { x: e.clientX, sceneX: scene[index].position.x }; dragCurrent[index] = 0; stopAutoplay(index); renderer[index].domElement.style.cursor = 'grabbing'; }); renderer[index].domElement.addEventListener('mousemove', (e) => { if (!isDragging[index]) return; const deltaX = e.clientX - dragStart[index].x; dragCurrent[index] = deltaX; const dragAmount = deltaX * 0.003; scene[index].position.x = dragStart[index].sceneX + dragAmount; renderer[index].render(scene[index], camera[index]); }); renderer[index].domElement.addEventListener('mouseup', (e) => { if (!isDragging[index]) return; isDragging[index] = false; renderer[index].domElement.style.cursor = 'grab'; const deltaX = e.clientX - dragStart[index].x; // Snap to nearest slide if dragged enough if (Math.abs(deltaX) > 50) { if (deltaX > 0) { moveToPrev(index); } else { moveToNext(index); } } else { // Snap back to current position targetPosition[index] = -currentSlide[index] * getWidth(options[index].gap); smoothMove(index, () => {}); } startAutoplay(index); }); renderer[index].domElement.addEventListener('mouseleave', (e) => { if (isDragging[index]) { isDragging[index] = false; renderer[index].domElement.style.cursor = 'grab'; // Snap back to current position targetPosition[index] = -currentSlide[index] * getWidth(options[index].gap); smoothMove(index, () => {}); startAutoplay(index); } }); // Touch support for mobile // ============ الجزء المعدّل: تفريق بين سحب أفقي (سلايدر) وسكرول عمودي (صفحة) ============ renderer[index].domElement.addEventListener('touchstart', (e) => { isDragging[index] = true; touchAxisLocked[index] = false; touchIsHorizontal[index] = false; dragStart[index] = { x: e.touches[0].clientX, y: e.touches[0].clientY, sceneX: scene[index].position.x }; dragCurrent[index] = 0; stopAutoplay(index); }, { passive: true }); renderer[index].domElement.addEventListener('touchmove', (e) => { if (!isDragging[index]) return; const deltaX = e.touches[0].clientX - dragStart[index].x; const deltaY = e.touches[0].clientY - dragStart[index].y; // أول ما الحركة تتخطى حد بسيط، نقرر: أفقي (سلايدر) ولا عمودي (سكرول صفحة) if (!touchAxisLocked[index]) { if (Math.abs(deltaX) > 6 || Math.abs(deltaY) > 6) { touchAxisLocked[index] = true; touchIsHorizontal[index] = Math.abs(deltaX) > Math.abs(deltaY); } else { return; // لسه الحركة صغيرة، منقررش حاجة } } if (touchIsHorizontal[index]) { // سحب أفقي: امنع سكرول الصفحة وحرك السلايدر e.preventDefault(); dragCurrent[index] = deltaX; const dragAmount = deltaX * 0.003; scene[index].position.x = dragStart[index].sceneX + dragAmount; renderer[index].render(scene[index], camera[index]); } else { // سكرول عمودي: سيب المتصفح يسكرول عادي وألغي حالة السحب isDragging[index] = false; } }, { passive: false }); renderer[index].domElement.addEventListener('touchend', (e) => { if (!isDragging[index]) { touchAxisLocked[index] = false; return; } isDragging[index] = false; touchAxisLocked[index] = false; const deltaX = dragCurrent[index]; // Snap to nearest slide if dragged enough if (Math.abs(deltaX) > 50) { if (deltaX > 0) { moveToPrev(index); } else { moveToNext(index); } } else { // Snap back to current position targetPosition[index] = -currentSlide[index] * getWidth(options[index].gap); smoothMove(index, () => {}); } startAutoplay(index); }); // ============ نهاية الجزء المعدّل ============ // Set initial cursor renderer[index].domElement.style.cursor = 'grab'; // Start autoplay startAutoplay(index); animate(index); }); } function startAutoplay(i) { if (!options[i].autoplay) return; stopAutoplay(i); autoplayInterval[i] = setInterval(() => { moveToNext(i); }, options[i].autoplaySpeed); } function stopAutoplay(i) { if (autoplayInterval[i]) { clearInterval(autoplayInterval[i]); autoplayInterval[i] = null; } } function moveToNext(i) { if (isAnimating[i] || isDragging[i]) return; currentSlide[i]++; targetPosition[i] -= getWidth(options[i].gap); smoothMove(i, () => { // Reset position if we're past the second set if (currentSlide[i] >= slideAmount[i] * 2) { currentSlide[i] = slideAmount[i]; targetPosition[i] = -slideAmount[i] * getWidth(options[i].gap); scene[i].position.x = targetPosition[i]; } }); } function moveToPrev(i) { if (isAnimating[i] || isDragging[i]) return; currentSlide[i]--; targetPosition[i] += getWidth(options[i].gap); smoothMove(i, () => { // Reset position if we're before the first set if (currentSlide[i] < slideAmount[i]) { currentSlide[i] = slideAmount[i] * 2 - 1; targetPosition[i] = -(slideAmount[i] * 2 - 1) * getWidth(options[i].gap); scene[i].position.x = targetPosition[i]; } }); } function smoothMove(i, callback) { isAnimating[i] = true; const duration = 600; const start = scene[i].position.x; const end = targetPosition[i]; const startTime = performance.now(); function step(now) { const elapsed = now - startTime; const progress = Math.min(elapsed / duration, 1); const ease = 1 - Math.pow(1 - progress, 3); scene[i].position.x = start + (end - start) * ease; renderer[i].render(scene[i], camera[i]); if (progress animate(i)); } init(); }); }

أفضل العروض

العلامات التجارية

Vector 8

العلامات التجارية

الاكثر مبيعاً

أحدث المنتجات

من نحن

رحلتنا نحو التميز في عالم الأجهزة المنزلي

نقدّم تجربة تسوّق متكاملة للأجهزة المنزلية، تجمع بين الجودة العالية، التصميم العصري، والخدمة الموثوقة. نؤمن أن راحتك تبدأ من التفاصيل، لذلك نحرص على تقديم منتجات أصلية من أفضل العلامات التجارية

Group 20 3

رؤيتنا

أن نكون الوجهة الأولى للأجهزة المنزلية الفاخرة

Group 1000006348 1

رسالتنا

توفير منتجات موثوقة وتجربة تسوق سهلة وآمنة

Group 1000006346 2

قيمنا

الشفافية – الجودة – الموثوقية – خدمة العملاء المتميزة

Group 1000006350 3

هدفنا

تحسين نمط الحياة داخل كل منزل بأجهزة تجمع بين الراحة والأناقة.

Group 18

من نحن

رحلتنا نحو التميز في عالم الأجهزة المنزلية

نقدّم تجربة تسوّق متكاملة للأجهزة المنزلية، تجمع بين الجودة العالية، التصميم العصري، والخدمة الموثوقة. نؤمن أن راحتك تبدأ من التفاصيل، لذلك نحرص على تقديم منتجات أصلية من أفضل العلامات التجارية

Group 18
Group 20 2

رؤيتنا

أن نكون الوجهة الأولى للأجهزة المنزلية الفاخرة

Group 1000006348

رسالتنا

توفير منتجات موثوقة وتجربة تسوق سهلة وآمنة

Group 1000006346 1

قيمنا

الشفافية – الجودة – الموثوقية – خدمة العملاء المتميزة

Group 1000006350 2

هدفنا

تحسين نمط الحياة داخل كل منزل بأجهزة تجمع بين الراحة والأناقة.

Group 1000006350 3

رؤيتنا

نحن نسعى لنكون الوجهة الأولى للأجهزة الفاخرة

Group 1000006348 1

رسالتنا

نوفر منتجات موثوقة ونضمن تجربة تسوق آمنة

Group 1000006346 2

قيمنا

قيمنا الشفافية والجودة والموثوقية مع خدمة راقية

Group 20 3

هدفنا

نطوّر نمط الحياة بأجهزة تجمع الراحة والأناقة

أهم ما يميزنا

نوفّر لك تجربة تسوّق راقية تجمع بين
الجودة، الثقة، والراحة

نوفّر لك تجربة تسوّق راقية تجمع بين الجودة، الثقة، والراحة

Group 1000006356 1

منتجات أصلية 100%

أجهزتنا موثوقة المصدر ومعتمدة رسميًا لضمان أداء قوي وثقة ثابتة تدوم دائمًا.

Group 1000006355 1

ضمان وشحن سريع

نوصل طلبك بسرعة وأمان تام مع ضمان رسمي يشمل الأعطال ويحمي راحتك.

Group 1000006354 1

عروض منافسة

نقدم أفضل الأسعار بدون مبالغة مع عروض تمنحك قيمة ممتازة لكل عملية.

Group 1000006353 5

خدمة عملاء مميزة

فريقنا جاهز دائمًا للرد على استفساراتك ودعمك في كل خطوة من تجربتك.

أراء العملاء