0 }, get firstVideoIndex() { return this.hasVideos ? this.images.length : -1 }, get total() { return this.images.length + this.productVideos.length }, modalOpen: false, modalActive: 0, // Drag/swipe state isDragging: false, wasDragging: false, startX: 0, currentX: 0, dragOffset: 0, containerWidth: 0, startY: 0, directionLocked: null, isRtl: false, imageLoading: false, // Zoom state zoomScale: 1, zoomPanX: 0, zoomPanY: 0, zoomPinching: false, zoomPanning: false, zoomInitialDistance: 0, zoomInitialScale: 1, zoomPanStartX: 0, zoomPanStartY: 0, zoomPanOffsetX: 0, zoomPanOffsetY: 0, zoomLastTap: 0, zoomLastTouchX: 0, zoomLastTouchY: 0, zoomAnimating: false, lastInputWasTouch: false, init() { this.isRtl = document.documentElement.dir === 'rtl'; this.$nextTick(() => { this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; // Handle already-cached images where x-on:load won't fire this.$el.querySelectorAll('img.lqip-placeholder').forEach(lqip => { const realImg = lqip.nextElementSibling; if (realImg && realImg.complete && realImg.naturalWidth > 0) { realImg.dataset.lqipDone = '1'; lqip.style.display = 'none'; } }); }); window.addEventListener('resize', () => { this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; }); // Preload first image of each variant for instant switching Object.values(this.variationImagesMap).forEach(variant => { if (variant.images && variant.images[0]) { new Image().src = variant.images[0]; } }); // Only the active slide may play. Clearing startedVideo also // drops the bound src, so swiping away stops the download and // not just the playback. this.$watch('active', () => { this.startedVideo = null; this.$el.querySelectorAll('video[data-product-video]').forEach(v => v.pause()); }); }, handleDragStart(e) { if (this.total <= 1) return; this.isDragging = true; this.directionLocked = null; this.startX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX; this.startY = e.type.includes('mouse') ? e.clientY : e.touches[0].clientY; this.currentX = this.startX; this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; }, handleDragMove(e) { if (!this.isDragging) return; const clientX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX; const clientY = e.type.includes('mouse') ? e.clientY : e.touches[0].clientY; if (this.directionLocked === null) { const deltaX = Math.abs(clientX - this.startX); const deltaY = Math.abs(clientY - this.startY); if (deltaX < 5 && deltaY < 5) return; if (deltaY > deltaX) { this.directionLocked = 'vertical'; this.isDragging = false; this.dragOffset = 0; return; } this.directionLocked = 'horizontal'; } if (this.directionLocked === 'vertical') return; e.preventDefault(); this.currentX = clientX; let diff = this.currentX - this.startX; // Limit drag at edges const atFirst = this.active === 0; const atLast = this.active === this.total - 1; const isAtEdge = this.isRtl ? (atFirst && diff < 0) || (atLast && diff > 0) : (atFirst && diff > 0) || (atLast && diff < 0); if (isAtEdge) { diff = diff * 0.3; // Resistance at edges } this.dragOffset = diff; }, handleDragEnd() { this.directionLocked = null; if (!this.isDragging) return; this.isDragging = false; // Mark that we just finished dragging to prevent click from opening modal if (Math.abs(this.dragOffset) > 5) { this.wasDragging = true; setTimeout(() => { this.wasDragging = false; }, 100); } const threshold = this.containerWidth * 0.2; if (Math.abs(this.dragOffset) > threshold) { if (this.isRtl) { // RTL: drag left (negative) = prev, drag right (positive) = next if (this.dragOffset < 0) { this.prev(); } else { this.next(); } } else { // LTR: drag right (positive) = prev, drag left (negative) = next if (this.dragOffset > 0) { this.prev(); } else { this.next(); } } } this.dragOffset = 0; }, getSlideTransform() { // RTL: images flow right-to-left, so we use positive offset // LTR: images flow left-to-right, so we use negative offset const baseOffset = this.isRtl ? this.active * 100 : -this.active * 100; const dragPercent = this.containerWidth > 0 ? (this.dragOffset / this.containerWidth) * 100 : 0; return `translateX(${baseOffset + dragPercent}%)`; }, next() { if (this.active < this.total - 1) { this.active = this.active + 1; } }, prev() { if (this.active > 0) { this.active = this.active - 1; } }, goTo(idx) { this.active = idx }, openModal(idx) { if (this.isDragging || this.wasDragging) return; // The lightbox is images only. Its surface is touch-action:none // with modalDragStart calling preventDefault() on every touch, // which would swallow the native video control bar - and // native fullscreen is one tap away from the inline player // anyway. Video slides simply never open it. if (this.hasVideos && idx >= this.firstVideoIndex) return; this.modalActive = idx; this.modalOpen = true; document.body.style.overflow = 'hidden'; }, closeModal() { this.resetZoom(); this.modalOpen = false; document.body.style.overflow = 'auto'; }, // Wrap on the image count, not `total`: the modal never shows a // video, so paging must not land on a video index. get modalTotal() { return Math.max(1, this.images.length) }, modalNext() { this.resetZoom(); this.modalActive = (this.modalActive + 1) % this.modalTotal }, modalPrev() { this.resetZoom(); this.modalActive = (this.modalActive - 1 + this.modalTotal) % this.modalTotal }, modalGoTo(idx) { this.resetZoom(); this.modalActive = idx }, // Modal drag/swipe modalDragging: false, modalWasDragging: false, modalStartX: 0, modalDragOffset: 0, // Zoom helpers resetZoom() { this.zoomScale = 1; this.zoomPanX = 0; this.zoomPanY = 0; this.zoomPinching = false; this.zoomPanning = false; }, getTouchDistance(touches) { return Math.hypot( touches[0].clientX - touches[1].clientX, touches[0].clientY - touches[1].clientY ); }, clampPan() { const maxPanX = Math.max(0, (this.zoomScale - 1) * window.innerWidth / 2); const maxPanY = Math.max(0, (this.zoomScale - 1) * window.innerHeight / 2); this.zoomPanX = Math.max(-maxPanX, Math.min(maxPanX, this.zoomPanX)); this.zoomPanY = Math.max(-maxPanY, Math.min(maxPanY, this.zoomPanY)); }, modalDragStart(e) { const isTouch = e.type.includes('touch'); this.lastInputWasTouch = isTouch; // Store touch position for double-tap zoom center if (isTouch && e.touches[0]) { this.zoomLastTouchX = e.touches[0].clientX; this.zoomLastTouchY = e.touches[0].clientY; } // Two fingers: start pinch-to-zoom if (isTouch && e.touches.length === 2) { this.zoomPinching = true; this.zoomInitialDistance = this.getTouchDistance(e.touches); this.zoomInitialScale = this.zoomScale; this.modalDragging = false; this.zoomPanning = false; e.preventDefault(); return; } // Single finger/mouse while zoomed: start panning if (this.zoomScale > 1) { this.zoomPanning = true; this.zoomPanStartX = isTouch ? e.touches[0].clientX : e.clientX; this.zoomPanStartY = isTouch ? e.touches[0].clientY : e.clientY; this.zoomPanOffsetX = this.zoomPanX; this.zoomPanOffsetY = this.zoomPanY; e.preventDefault(); return; } // Single finger not zoomed or mouse: existing swipe // Prevent browser double-tap-to-zoom so our custom handler works if (isTouch) { e.preventDefault(); } if (this.total <= 1) return; this.modalDragging = true; this.modalStartX = isTouch ? e.touches[0].clientX : e.clientX; this.modalDragOffset = 0; }, modalDragMove(e) { const isTouch = e.type.includes('touch'); // Pinch-to-zoom if (this.zoomPinching && isTouch && e.touches.length >= 2) { e.preventDefault(); const newDist = this.getTouchDistance(e.touches); let newScale = this.zoomInitialScale * (newDist / this.zoomInitialDistance); this.zoomScale = Math.max(1, Math.min(4, newScale)); this.clampPan(); return; } // Panning while zoomed if (this.zoomPanning) { e.preventDefault(); const px = isTouch ? e.touches[0].clientX : e.clientX; const py = isTouch ? e.touches[0].clientY : e.clientY; const dx = px - this.zoomPanStartX; const dy = py - this.zoomPanStartY; this.zoomPanX = this.zoomPanOffsetX + dx; this.zoomPanY = this.zoomPanOffsetY + dy; this.clampPan(); return; } // Existing swipe logic if (!this.modalDragging) return; e.preventDefault(); const x = isTouch ? e.touches[0].clientX : e.clientX; this.modalDragOffset = x - this.modalStartX; }, modalDragEnd(e) { const isTouch = e && e.type && e.type.includes('touch'); // End pinch if (this.zoomPinching) { this.zoomPinching = false; // Snap to 1 if nearly unzoomed if (this.zoomScale < 1.1) { this.resetZoom(); } this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); // If one finger remains after pinch, start panning if (isTouch && e.touches && e.touches.length === 1 && this.zoomScale > 1) { this.zoomPanning = true; this.zoomPanStartX = e.touches[0].clientX; this.zoomPanStartY = e.touches[0].clientY; this.zoomPanOffsetX = this.zoomPanX; this.zoomPanOffsetY = this.zoomPanY; } return; } // End pan if (this.zoomPanning) { this.zoomPanning = false; this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); // Double-tap to zoom out while panned if (isTouch) { const now = Date.now(); if (now - this.zoomLastTap < 300) { this.zoomAnimating = true; setTimeout(() => { this.zoomAnimating = false; }, 300); this.resetZoom(); this.zoomLastTap = 0; } else { this.zoomLastTap = now; } } return; } // Existing swipe end logic const wasDragging = this.modalDragging; if (this.modalDragging) { this.modalDragging = false; const absDrag = Math.abs(this.modalDragOffset); if (absDrag > 5) { this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); } const threshold = 80; if (absDrag > threshold) { if (this.isRtl) { this.modalDragOffset < 0 ? this.modalPrev() : this.modalNext(); } else { this.modalDragOffset > 0 ? this.modalPrev() : this.modalNext(); } this.modalDragOffset = 0; this.zoomLastTap = 0; return; } this.modalDragOffset = 0; } // Double-tap detection (works for both zoomed and not zoomed) if (isTouch) { const now = Date.now(); if (now - this.zoomLastTap < 300) { this.zoomAnimating = true; setTimeout(() => { this.zoomAnimating = false; }, 300); this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 200); if (this.zoomScale > 1) { this.resetZoom(); } else { const cx = this.zoomLastTouchX - window.innerWidth / 2; const cy = this.zoomLastTouchY - window.innerHeight / 2; this.zoomScale = 2.5; this.zoomPanX = -cx * (this.zoomScale - 1) / this.zoomScale; this.zoomPanY = -cy * (this.zoomScale - 1) / this.zoomScale; this.clampPan(); } this.zoomLastTap = 0; return; } this.zoomLastTap = now; // Single tap on backdrop: close modal (touch equivalent of @click.self) if (e.target === e.currentTarget) { this.closeModal(); } } }, switchToVariation(attrValueId) { const varImages = this.variationImagesMap[attrValueId]; let newImages, newLargeImages, newLqipImages; if (varImages && varImages.images && varImages.images.length > 0) { newImages = varImages.images; newLargeImages = varImages.largeImages || varImages.images; newLqipImages = varImages.lqipImages || []; } else { newImages = this.defaultImages; newLargeImages = this.defaultLargeImages; newLqipImages = this.defaultLqipImages; } // Show loading state while first image loads this.imageLoading = true; const firstImg = new Image(); firstImg.onload = () => { this.localImages = newImages; this.localLargeImages = newLargeImages; this.localLqipImages = newLqipImages; this.active = 0; this.modalActive = 0; this.imageLoading = false; }; firstImg.onerror = () => { this.localImages = newImages; this.localLargeImages = newLargeImages; this.localLqipImages = newLqipImages; this.active = 0; this.modalActive = 0; this.imageLoading = false; }; firstImg.src = newImages[0]; // If already cached, onload fires synchronously or near-instantly } }" x-on:keydown.escape.window="closeModal()" x-on:keydown.arrow-left.window="modalOpen && modalPrev()" x-on:keydown.arrow-right.window="modalOpen && modalNext()" x-on:switch-variation-images.window="switchToVariation($event.detail.attrValueId ?? $event.detail[0]?.attrValueId)">
/

محبس الكرة المدمج المتميز "HYDRO uPVC Compact Ball Valve"

محبس الكرة المدمج المتميز من ماركة هايدرو العالمية "HYDRO uPVC Compact Ball Valve"، المصنوع من البولي فينيل كلورايد غير الملدن عالي الجودة، هو الحل الهندسي والتقني المعتمد للتحكم السلس والآمن في تدفق المياه داخل شبكات الري الحديثة، خطوط الأنابيب الزراعية، وأنظمة توزيع السوائل. يتميز بتصميمه المدمج (Compact) المتكامل ومقاومته الفائقة للأملاح والمواد الكيميائية، مما يضمن كفاءة تشغيلية ممتازة وعمراً افتراضياً طويلاً بدون أي تسريب.

إليك المواصفات والدليل الإرشادي الكامل للمنتج:
✨ مميزات المنتج
  • إغلاق محكم ومنع تسريب تام: مزود بكرة داخلية مصقولة هندسياً مع جوان إغلاق عالي الجودة من HYDRO، يضمن قفل تدفق المياه بالكامل وبدون أي تنقيط حتى تحت الضغوط التشغيلية المختلفة.
  • حصانة كاملة ضد التآكل والصدأ: خامات uPVC المعتمدة من HYDRO تمنح المحبس مقاومة مطلقة للأكسدة والأملاح، وتمنع تأثره بالأسمدة الكيماوية والمبيدات المذابة في مياه الري.
  • تصميم مدمج وخفيف الوزن (Compact Design): يأتي الهيكل كقطعة واحدة مدمجة ومتينة، مما يسهل تركيبه في الأماكن الضيقة ويوفر مساحة ممتازة داخل غرف التحكم ومحطات التوزيع.
  • مقبض مريح وسلس التشغيل: مقبض علوي باللون الأحمر الزاهي، مصمم هندسياً لتوفير قبضة يد مريحة وعزم دوران خفيف لفتح وإغلاق المحبس بربع لفة فقط (90 درجة).
🧪 المواصفات الفنية والفيزيائية
  • العلامة التجارية (Brand): هايدرو (HYDRO) الرائدة في حلول شبكات ومستلزمات الري المتطورة.
  • نوع المنتج: محبس كرة بلاستيكي مدمج (uPVC Compact Ball Valve).
  • المادة والتركيب (Material): بولي فينيل كلورايد غير ملدن (uPVC) نقي ومقاوم للأشعة فوق البنفسجية (UV).
  • نوع التوصيل (Connection Type): وصلات لصق داخلي أملس (Socket/Sleeve) لربطه مباشرة مع الأنابيب باستخدام غراء uPVC المخصص، مما يضمن دمجاً ثابتاً ودائماً.
  • الاستدامة: خامات متينة ومصممة بدقة لتحمل ظروف الاستخدام الشاق في المزارع المكشوفة والبيئات الصحراوية الحارة.
📅 دليل الاستخدام والتطبيق السريع
  • طرق التركيب والتطبيق:
    1. التنظيف: قم بتنظيف السطح الخارجي للأنبوب والسطح الداخلي للمحبس جيداً من الأتربة والرطوبة باستخدام منظف uPVC مخصص.
    2. وضع الغراء: ضع طبقة متساوية من غراء الأنابيب uPVC عالي الجودة على كلا السطحين.
    3. التثبيت: ادفع الأنبوب داخل المحبس بسرعة مع تدويره ربع لفة لضمان توزيع الغراء، ثم ثبته يدوياً لعدة ثوانٍ حتى يتماسك اللحام البارد.
  • الاستخدامات المستهدفة: خطوط توزيع مياه الري بالتنقيط والرش، البيوت المحمية (الصوب)، أنظمة الفلترة والتحكم، وخطوط نقل المياه الرئيسية والفرعية في المشاريع الزراعية.
⚠️ إرشادات التخزين والسلامة
  • التخزين: يُحفظ في مكان جاف وبعيداً عن الأتربة قبل التركيب لضمان نظافة المجرى الداخلي وحماية الكرة الداخلية من الخدوش التي قد تؤثر على إحكام الإغلاق.
  • توصية HYDRO التشغيلية: اترك الوصلات المغراة تجف تماماً للمدة الموصى بها على عبوة الغراء قبل تشغيل المياه وضخ الضغط في الشبكة، ويُنصح بفتح وإغلاق المحبس ببطء في الخطوط ذات التدفق العالي لتجنب ظاهرة المطرقة المائية.

 
0 (0 reviews)

No reviews yet. Be the first to review this product!

Login to write a review

Related Products

AED 50
About Us
  • نحن نقدم منتجات عالية الجودة بأسعار منافسة. هدفنا هو جعل التسوق عبر الإنترنت سهلاً وممتعًا.
Categories
Quick Links
Contact Us
  • الاتصال بنا لأي أستفسارات أو دعم 971504454518+

© {1994} {شركة الطبق الطائر}. جميع الحقوق محفوظة.

Online store designed and built by Trinavo

الطبق الطائر للمواد الزراعية

Add our store to your home screen

  1. 1 Tap the Share button in the browser bar
  2. 2 Choose Add to Home Screen