From 324298c9d779b9cb7d4c5250aafcfa2d7fef1831 Mon Sep 17 00:00:00 2001 From: aramesh-site deploy Date: Fri, 9 Oct 2026 18:01:47 +0000 Subject: [PATCH] =?UTF-8?q?fix(map):=20=D9=85=D9=82=D8=A7=D9=88=D9=85?= =?UTF-8?q?=E2=80=8C=D8=B3=D8=A7=D8=B2=DB=8C=20=D8=B1=D8=A7=D9=87=E2=80=8C?= =?UTF-8?q?=D8=A7=D9=86=D8=AF=D8=A7=D8=B2=DB=8C=20=D9=86=D9=82=D8=B4=D9=87?= =?UTF-8?q?=20=D8=A8=D8=B1=D8=A7=DB=8C=20=D9=85=D9=88=D8=A8=D8=A7=DB=8C?= =?UTF-8?q?=D9=84=20=E2=80=94=20=D9=BE=DB=8C=D8=B4=E2=80=8C=D8=B3=D9=86?= =?UTF-8?q?=D8=AC=DB=8C=20WebGL=D8=8C=20antialias=20=D9=81=D9=82=D8=B7=20?= =?UTF-8?q?=D8=AF=D8=B1=20=D8=B5=D9=88=D8=B1=D8=AA=20=D9=BE=D8=B4=D8=AA?= =?UTF-8?q?=DB=8C=D8=A8=D8=A7=D9=86=DB=8C=D8=8C=20=D9=88=20=D8=AE=D8=B7?= =?UTF-8?q?=D8=A7=DB=8C=20=D8=B1=D9=88=D8=B4=D9=86=20=D8=A8=D9=87=E2=80=8C?= =?UTF-8?q?=D8=AC=D8=A7=DB=8C=20=D9=82=D8=A7=D8=A8=20=D8=AE=D8=A7=D9=84?= =?UTF-8?q?=DB=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/map/useMapLibre.ts | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/frontend/src/map/useMapLibre.ts b/frontend/src/map/useMapLibre.ts index 0fa64ec..556e8d9 100644 --- a/frontend/src/map/useMapLibre.ts +++ b/frontend/src/map/useMapLibre.ts @@ -53,6 +53,13 @@ export function useMapLibre({ center, zoom, scrollZoom = true, maxBounds, minZoo let readyFallback: number | undefined let dprQuery: MediaQueryList | null = null let handleDprChange: (() => void) | null = null + // آیا می‌توان کانتکست آنتی‌آلیاسه گرفت؟ (تست سبک، یک‌بار در هر ساخت نقشه) + const probeCanvas = document.createElement('canvas') + const canAntialias = Boolean( + probeCanvas.getContext('webgl2', { antialias: true }) || + probeCanvas.getContext('webgl', { antialias: true }), + ) + const controller = new AbortController() const timeoutId = window.setTimeout(() => controller.abort(), STYLE_TIMEOUT_MS) @@ -61,6 +68,16 @@ export function useMapLibre({ center, zoom, scrollZoom = true, maxBounds, minZoo // وب‌ورکر نقشه و پروتکل pmtiles باید پیش از ساخت نقشه آماده باشند؛ // وگرنه نخستین درخواست‌های کاشی در وب‌ورکر بی‌پاسخ می‌مانند + // پیش‌سنجی WebGL: برخی مرورگرهای موبایل (یا حالت ذخیرهٔ باتری/داده) کانتکست + // WebGL نمی‌دهند. بدون این بررسی، سازندهٔ مپ‌لیبر خطا می‌دهد و صفحه در حالت + // «در حال بارگذاری» گیر می‌کند — کاربر فقط یک قاب خالی می‌بیند. + const probe = document.createElement('canvas') + const gl = probe.getContext('webgl2') || probe.getContext('webgl') || probe.getContext('experimental-webgl') + if (!gl) { + setStatus('error') + return + } + Promise.all([loadMapStyle(controller.signal), ensureMapWorker()]) .then(([style]) => { if (disposed) return @@ -75,7 +92,9 @@ export function useMapLibre({ center, zoom, scrollZoom = true, maxBounds, minZoo maxZoom: FALLBACK_MAX_ZOOM, renderWorldCopies: false, // لبه‌های نرم‌تر خطوط و چندضلعی‌ها — حس لوکس رندر برداری - canvasContextAttributes: { antialias: true }, + // antialias فقط جایی که مطمئنیم پشتیبانی می‌شود — درخواست بی‌قید آن + // روی بعضی GPUهای موبایل کانتکست را رد می‌کند و نقشه ساخته نمی‌شود. + canvasContextAttributes: { antialias: canAntialias }, // کیفیت حداکثری در بزرگ‌نمایی‌های عمیق: هیچ سطحی با مقیاس‌کردن سطح // بالاتر رندر نمی‌شود و همه‌ی سطح‌ها تا maxZoom از تقسیم هندسه // می‌آیند (پیش‌فرض ۴ سطح آخر را overscale می‌کند). مبادله: کار @@ -173,7 +192,9 @@ export function useMapLibre({ center, zoom, scrollZoom = true, maxBounds, minZoo setMap(instance) }) - .catch(() => { + .catch((error) => { + // خطای ساخت/بارگذاری نقشه — وضعیت خطا با پیام قابل‌تلاش‌دوباره، نه قاب خالی + console.warn('[map] راه‌اندازی نقشه ناموفق بود:', error) if (!disposed) setStatus('error') })