تجسم خود را به سرعت شروع کنید: بر روی یک لایه ۲ بعدی سفارشی موجود بسازید

 

تجسم خود را به سرعت شروع کنید: بر روی یک لایه ۲ بعدی سفارشی موجود بسازید

 

قبل از اینکه ارسال FlowRenderer را به عنوان بخشی از ArcGIS API برای جاوا اسکریپت (JS API) شروع کنیم، یک مقاله وبلاگ و یک نسخه آزمایشی TypeScript منبع باز (repo animated-flow-ts در GitHub) منتشر کردیم که نسخه ساده شده ای از تجسم مشابه را پیاده سازی کرد. یک لایه WebGL سفارشی این تلاش با استقبال خوبی از سوی خوانندگان ما مواجه شد و آنها شروع به آزمایش کد برای تطبیق آن با موارد استفاده خود کردند. امروزه، رایج‌ترین موارد استفاده از تجسم جریان توسط FlowRenderer رسمی انجام می‌شود ، اما مخزن منبع باز اصلی animated-flow-ts هنوز یک نقطه شروع ارزشمند است اگر نیاز به برآورده کردن یک مورد خاص دارید. در این مقاله نحوه انجام این کار را توضیح می دهیماز کد موجود و لایه های WebGL سفارشی برای ایجاد تجسم های جدید استفاده کنید .

آنچه را که خواهیم ساخت

هدف این مقاله توضیح نحوه عملکرد برنامه jumpstart.ts (نمایشگر زنده ) در مخزن منبع باز است. این برنامه ۳ لایه مختلف WebGL سفارشی را بسته بندی می کند و امکان جابجایی بین آنها را با استفاده از ویجت LayerList فراهم می کند.

این مقاله آشنایی با WebGL را فرض می کند. داشتن تجربه با BaseLayerViewGL2D می تواند برای به دست آوردن درک عمیق تر از پایگاه کد مفید باشد، اما این یک پیش نیاز نیست. کدی که امروز می‌خواهیم بنویسیم، BaseLayerViewGL2D را وارد نمی‌کند و کاملاً از این واقعیت بی‌اطلاع است که در پشت صحنه، نقطه ورود همه عملیات‌های رندر ۲ بعدی WebGL است.

یک تجدید کننده در لایه های سفارشی

این بخش به طور خلاصه نحوه ایجاد لایه های سفارشی را از ابتدا پوشش می دهد. ما آن را برای کامل بودن و ارائه زمینه درج کردیم، اما برای درک بقیه مقاله لازم نیست. اگر امروز تمرکز شما بر ایجاد سریع تجسم های جدید است، به راحتی به بخش بعدی بروید .

در Esri، ما معتقدیم که شما شایسته بهترین ابزار برای پروژه های خود هستید. به همین دلیل است که JS API با بسیاری از لایه‌های از پیش تعریف‌شده ، آماده استفاده و پشتیبانی شده توسط ارائه ابری ما ارسال می‌شود.

اما ما همچنین می دانیم که شما و تیم شما ممکن است نیازمندی های منحصر به فردی داشته باشید که خواستار یک راه حل یکپارچه سفارشی هستید. به همین دلیل، API 4x JS با پشتیبانی از رندرهای خارجی سه بعدی از زمان آغاز به کارش در سال ۲۰۱۶، و لایه های ۲ بعدی سفارشی با استفاده از BaseLayerView2D و BaseLayerViewGL2D به ترتیب از نسخه های ۴٫۸ و ۴٫۱۱ عرضه شده است. این مقاله بر روی لایه‌های WebGL سفارشی تمرکز می‌کند، لایه‌هایی که برای رندر ۲ بعدی MapView به BaseLayerViewGL2D متکی هستند .

یک نمونه/آموزش رسمی SDK وجود دارد که نحوه ایجاد لایه های WebGL سفارشی را توضیح می دهد. به طور خلاصه، مراحل زیر شامل می شود.

  • یک نمای لایه ۲ بعدی WebGL سفارشی را از BaseLayerViewGL2D به ارث ببرید
  • برای ایجاد منابع WebGL و سایر اشیاء مورد نیاز قبل از شروع رندر، روش BaseLayerViewGL2D.attach() را لغو کنید. این متد به عنوان سازنده عمل می کند و زمانی که لایه سفارشی به نقشه اضافه می شود توسط MapView فراخوانی می شود. مسئولیت مشترک این روش ایجاد برنامه‌های WebGL، مش‌های چهارگانه و بافت‌های رویه‌ای است.
  • نادیده گرفتن روش BaseLayerViewGL2D.render() برای صدور فراخوانی و به روز رسانی منابع WebGL که به صورت پویا مدیریت می شوند. نمونه‌هایی از منابع پویا، بافت‌ها و مش‌های تصویری هستند که به سطح جزئیات (LOD) بستگی دارند. این روش هر فریم توسط MapView نامیده می شود .
  • روش BaseLayerViewGL2D.detach() را باطل کنید تا تمام منابع ایجاد شده توسط ۲ متد قبلی را از بین ببرید. این روش به عنوان یک تخریب کننده عمل می کند و زمانی که لایه سفارشی از نقشه حذف می شود توسط MapView فراخوانی می شود. این ۳ روش تنها روشهایی هستند که می توان کار WebGL را از آنجا صادر کرد. تماس با WebGL از هر مکان دیگری، از جمله تماس‌های غیرهمزمان و پس از انتظار ، احتمالاً رندر کل MapView را قطع می‌کند.
  • در هر زمان، کد سفارشی می‌تواند BaseLayerViewGL2D.requestRender() را برای برنامه‌ریزی یک فریم جدید فراخوانی کند، که منجر به ترسیم مجدد همه لایه‌ها از جمله لایه سفارشی توسط MapView می‌شود که به نوبه خود باعث اجرای ()BaseLayerViewGL2D.render می‌شود. BaseLayerViewGL2D.requestRender() را می توان برای پیاده سازی انیمیشن ها و برنامه ریزی به روز رسانی منابع WebGL پویا استفاده کرد.
  • یک لایه سفارشی را از esri/Layer یا یک کلاس لایه مناسب دیگر به ارث ببرید.
  • برای برگرداندن نمونه جدیدی از نمای لایه WebGL که قبلا تعریف شده بود، روش Layer.createLayerView را لغو کنید.

نمودار توالی زیر تعاملات زمان اجرا بین برنامه و سایر اشیاء درگیر در رندر دو بعدی را نشان می دهد.

این تجربه افزونه‌ای است که ما برای بیش از ۱۰ نسخه API از آن پشتیبانی کرده‌ایم. به خوبی می تواند این باشد که این تنها چیزی است که شما نیاز دارید. اگر اینطور باشد، عالی است! ما نمونه‌های SDK زیادی داریم که گردش کار استاندارد افزونه را با جزئیات پوشش می‌دهند، هم برای BaseLayerViewGL2D و هم برای BaseLayerView2D ، همتای Canvas2D آن.

اما، اگر شما یک توسعه دهنده WebGL هستید و به دنبال راه هایی برای افزایش بهره وری خود هستید، لطفا به خواندن ادامه دهید!

مروری بر animated-flow-tsمخزن

بیایید نگاهی به کد موجود در مخزن animated-flow-ts بیندازیم و ببینیم که چگونه می تواند به پروژه شما کمک کند.

با شبیه سازی مخزن، cdدر آن، npm installو npm startآن شروع کنید.

این دستورات کامپایلر TypeScript را در --watchحالت شروع می کنند، به طوری که هر بار که یک .tsفایل اصلاح می شود، به طور خودکار دوباره کامپایل می شود. به موازات آن، یک وب سرور آزمایشی شروع به گوش دادن در http://localhost:3000 می کند. یک پنجره مرورگر باید به طور خودکار با لیستی از برنامه های آزمایشی باز شود تا بتوانید آنها را امتحان کنید. برنامه ای که امروز از آن استفاده خواهیم کرد نام jumpstartدارد. اگر مرورگر به دلایلی باز نشد، مرورگر مورد نظر خود را راه اندازی کنید و آن را به http://localhost:3000/demos/jumpstart.html هدایت کنید.

این مخزن از ماژول های TypeScript و AMD استفاده می کند.

  • ساخت AMD از JS API از Esri CDN بارگیری می شود. JS API همچنین خود بارگذار AMD و تابع ()require را نیز مانند هر نمونه SDK ما ارائه می دهد.
  • ساخت AMD gl-matrixاز CDN نیز بارگیری می شود.
  • فایل های TypeScript محلی در ماژول های AMD کامپایل شده و بارگذاری می شوند.

دو دایرکتوری سطح بالا عبارتند از demosو src.

  • دمو حاوی فایل های HTML است. هر فایل یک برنامه است و در نگاه اول، دقیقاً مانند نمونه‌های SDK بسیار ما است که JS API را از CDN بارگیری می‌کند. با این حال، این برنامه ها همچنین دارای dojoConfigبخشی هستند که بارگیری ماژول های محلی جاوا اسکریپت AMD را از demos/jsزیر شاخه امکان پذیر می کند. این dojoConfigبخش همچنین بارگیری را برای انتشار عمومی gl-matrixکتابخانه، که ما برای جبر ماتریس WebGL به آن نیاز داریم، فعال می کند.
  • src حاوی فایل های TypeScript است. این tscدستور آنها را در ماژول های AMD جاوا اسکریپت کامپایل می کند، به گونه ای که هر .tsفایل به یک فایل مربوطه .jsدر زیر demos/js; اینها فایل های بارگذاری شده توسط برنامه ها هستند.

فایل های TypeScript در ۴ بسته سازماندهی شده اند.

  • برنامه ها حاوی فایل هایی هستند که نام آنها با برنامه های HTML موجود در دمو مطابقت دارد. هر برنامه نمایشی برای بارگیری ماژول جاوا اسکریپت مربوطه خود پیکربندی شده است، که به عنوان نقطه ورود عمل می کند و همه ماژول های مورد نیاز دیگر را بارگیری می کند.
  • core برخی از منطق های عمومی را پیاده سازی می کند که انتظار می رود هر لایه WebGL سفارشی دوبعدی به یک شکل به آن نیاز داشته باشد.
  • flow شامل اجرای تجسم جریان است. این بستگی به coreبسته عمومی دارد و الگوریتم ها و تکنیک های خاصی را اضافه می کند که تجسم جریان را پیاده سازی می کند.
  • کارگران حاوی کدی است که برای اجرا بر روی یک وب کار طراحی شده است . استفاده از کارگران اختیاری است اما می تواند پاسخگویی برنامه شما را تا حد زیادی بهبود بخشد.

coreبسته _

بسته coreشامل چند ماژول است. ۳ مورد از آنها برای اجرای تجسم های جدید مرتبط هستند.

  • هسته/رندر کلاسی به نام صادر می VisualizationStyleکند. این یک کلاس انتزاعی است که به عنوان پایه ای برای سبک های تجسم بتن استفاده می شود . یک سبک تجسم می داند که چگونه داده های مورد نیاز را بارگذاری کند و چگونه آن را ارائه کند. به طور سنتی، قبلاً یک پیاده‌سازی ملموس از این کلاس وجود داشت. FlowVisualizationStylein flow/rendering.tsتمام تکنیک‌های رندر و برنامه‌نویسی را پیاده‌سازی می‌کند که منحصربه‌فرد برای تجسم جریان است که در ابتدا در اوت گذشته منتشر کردیم. در این مقاله، ما بیشتر وقت خود را صرف توصیف تجسم‌های جایگزین می‌کنیم که هر کدام توسط VisualizationStyleزیر کلاس خود پیاده‌سازی می‌شوند.
  • core/types یک فایل اعلان است که شامل تعاریف نوع و واسط است.
  • زیر کلاس های اصلی/نمایش BaseLayerViewGL2D و صادرات VisualizationLayerView2D. این کلاس به عنوان یک نقطه شروع ساده تر برای ایجاد لایه های WebGL سفارشی عمل می کند. در این مقاله، VisualizationLayerView2Dبرای هر یک از تجسم‌های جایگزینی که روی آن کار خواهیم کرد، یک زیرکلاس ایجاد خواهیم کرد.

کلاس VisualizationLayerView2Dپایه انتزاعی

کلاس انتزاعی VisualizationLayerView2Dزیرکلاس BaseLayerViewGL2D را تشکیل می‌دهد و گردش کار توسعه‌ای آسان‌تر، هرچند محدودتر، ارائه می‌کند. برای استفاده از آن، زیر کلاس VisualizationLayerView2Dو متد createVisualizationStyle()را برای برگرداندن شی استایل خود پیاده سازی کنید.

همچنین باید با اجرای animateپرچم نمای لایه سفارشی را به عنوان متحرک یا غیر متحرک پرچم گذاری کنید. نمای لایه متحرک به طور مداوم بدون نیاز به فراخوانی صریح requestRender() دوباره ترسیم می شود .

Resourcesرابط _

Resourcesرابط به صورت هسته/انواع تعریف شده است و شیئی را توصیف می کند که از آن پشتیبانی می کند attach(gl)و detach(gl)متدها را پشتیبانی می کند. چنین اشیایی توسط سبک تجسم در یک حالت غیر متصل نمونه سازی می شوند . VisualizationLayerView2Dمسئول اتصال آنها در اولین رندر و جدا کردن آنها در صورت عدم نیاز است. روش ها و به عنوان یک جفت سازنده/ویرانگر عمل می کنند و زمینه رندر WebGL فعلی را به عنوان یک پارامتر دریافت می کنند.attach(gl)detach(gl)

این اشیا به عنوان محفظه هایی از منابع مورد نیاز الگوریتم رندر، از جمله مراجع غیرقابل جمع آوری مانند اشیاء WebGL و WebSockets هستند.

در هر زمان معین، تجسم بر مجموعه ای از منابع جهانی و مجموعه ای از منابع محلی متکی است. به این ترتیب، باید Resourcesدو بار رابط را پیاده سازی کنید.

  • منابع جهانی فقط یک بار بارگذاری و پیوست می شوند، زمانی که لایه به نقشه اضافه می شود، و زمانی که لایه حذف می شود، جدا می شوند. آنها مستقل از حالت دید هستند و نیازی به بارگذاری مجدد در هنگام جابجایی نقشه ندارند.
  • منابع محلی به حالت دید وابسته هستند و هر بار که پس از جابجایی نقشه، نما ثابت می شود، مکررا ایجاد و از بین می روند.

کلاس VisualizationStyleپایه انتزاعی

در مرحله بعد، شما نیاز به زیر کلاس دارید VisualizationStyle. یک سبک تجسم ، منطقی را که منابع را بارگیری و ارائه می کند، پیاده سازی می کند.

شما باید ۳ روش را نادیده بگیرید. این روش ها در صورت نیاز به طور خودکار توسط نمای لایه فراخوانی می شوند.

  • loadGlobalResources()باید یک قول را به یک Resourcesشیء ملموس برگرداند. این روش فقط یک بار، زمانی که لایه به نقشه اضافه می شود، فراخوانی می شود.
  • loadLocalResources()مشابه است اما هر بار که حالت view ثابت می شود فراخوانی می شود. اطلاعات مربوط به حالت نمایش و اندازه هدف را بر حسب پیکسل دریافت می کند تا بتواند تعیین کند چه چیزی باید بارگذاری شود و LOD مناسب.
  • renderVisualization()هر فریم فراخوانی می شود و مسئول صدور دستورات رندر WebGL است. به عنوان ورودی، زمینه رندر WebGL، منابع جهانی، جدیدترین منابع محلی و مجموعه ای از VisualizationRenderParams.

VisualizationRenderParamsرابط _

یک نمونه از این نوع در هر فریم به VisualizationStyle.renderVisualization()روش تحویل داده می شود. به سبک تجسم می گوید که در کجا تصویرسازی را رندر کند. در اینجا لیستی از مفیدترین خواص آن آورده شده است.

  • size: [number, number]. اندازه MapView ، بر حسب پیکسل.
  • translation: [number, number]. جایی که گوشه سمت چپ بالای تصویرسازی رندر شده باید به صورت پیکسل ظاهر شود.
  • rotation: number. چرخش نما، بر حسب رادیان.
  • scale: number. ضریب مقیاس برای تجسم مقدار ۱ به این معنی است که تجسم در همان مقیاسی که داده های آن بارگذاری شده است، ارائه می شود.

ایجاد کلاس لایه سفارشی

بسته coreهیچ راه خاصی برای پیاده سازی لایه سفارشی تجویز نمی کند. به این ترتیب، رایج‌ترین راه برای انجام این کار، زیرکلاس esri/Layer یا هر نوع لایه مناسب دیگری است و createLayerView()برای بازگرداندن نمونه‌ای از نمای لایه سفارشی، نادیده گرفته می‌شود.

مکانیزم گسترش جایگزین

اجازه دهید به طور خلاصه مراحل مورد نیاز برای پیاده سازی یک لایه WebGL سفارشی را با بسط دادن VisualizationLayerView2Dو سایر کلاس ها در بسته اصلی مخزن animated-flow-ts مرور کنیم. لطفاً مراحل انجام شده هنگام گسترش BaseLayerViewGL2D را مقایسه و مقایسه کنید .

  • تصمیم بگیرید که در زمان رندر به چه نوع منابعی نیاز دارید. اینها می توانند برنامه ها، بافت ها، مش های ایستا یا پویا باشند.
  • Resourcesدو بار رابط را پیاده سازی کنید: اول، به عنوان یک شی منابع جهانی ، منابع مورد نیاز را همیشه نگه می دارد و فقط یک بار بارگذاری می شود. دوم، به عنوان یک شی منابع محلی ، نگه داشتن منابعی که هر بار که نقشه جابجا می شود، دوباره بارگذاری می شوند.
  • تمدید VisualizationStyleکنید. شما باید ۳ روش را پیاده سازی کنید. loadGlobalResources()، loadLocalResources()، و renderVisualization().
  • تمدید VisualizationLayerView2Dکنید. شما نیاز به پیاده سازی createVisualizationStyle()و animateپرچم دارید.
  • esri /Layer را گسترش دهید و ()createLayerView را طبق معمول پیاده سازی کنید.

همانطور که می بینید، استفاده از coreبسته ساختار زیادی را به کد توسعه دهنده تحمیل می کند. توسعه دهندگان باید چیزهای خاصی را به روش خاصی پیاده سازی کنند. از سوی دیگر، تجربه توسعه استاندارد BaseLayerViewGL2D ، آزادی بسیار بیشتری را ارائه می دهد.

با این حال، انتخاب برای گسترش بسته اصلی دو مزیت دارد. این دو جنبه از توسعه لایه سفارشی را پوشش می دهد که در غیر این صورت درست کردن آنها بسیار دشوار است.

مزیت شماره ۱: مدیریت چرخه عمر منابع به صورت خودکار

VisualizationLayerView2Dنمای لایه سفارشی شما از یک سیستم مدیریت منابع کامل به ارث می رسد. شما نیازی به بارگیری، صف، پیوست کردن، جدا کردن، گوش دادن، تماشا کردن، بازگرداندن و یا هر چیزی نخواهید داشت. شما فقط باید منابع رندر را بین global و local تقسیم کنید، پیاده سازی کنید attach(gl)و detach(gl)و کلاس های پایه در هسته بقیه کار را انجام خواهند داد.

این رفتار خودکار با نمودار توالی زیر نشان داده شده است.

مزیت شماره ۲: مدیریت حالت مشاهده ساده

هنگامی که نما ثابت می شود و VisualizationStyle.loadLocalResources()فراخوانی می شود، به عنوان پارامتر میزان بارگذاری داده ها و اندازه هدف را بر حسب پیکسل دریافت می کند. شما می توانید از این اطلاعات برای جستجوی داده ها در LOD مناسب استفاده کنید و مجموعه ایده آل منابع محلی را برای آن برگردانید. وقتی این اتفاق می‌افتد، translationو scaleارسال به VisualizationStyle.renderVisualization()بازنشانی می‌شود.

نمودار زیر رفتار بزرگنمایی و بارگذاری مجدد داده های بعدی را در LOD بالاتر نشان می دهد.

آنچه که ما توضیح دادیم یک رفتار موروثی بسیار مهم است. به روز رسانی داده ها و موقعیت یابی دقیق صفحه را اجرا می کند. این یک جزء اساسی از هر تصویرسازی داده در مقیاس بزرگ در دنیای واقعی است. مهمتر از همه، کد WebGL شما را قادر می سازد تا از چندین LOD پشتیبانی کند و در عین حال ویژگی ها و لباس های شما را تا حد امکان کوچک نگه می دارد. به یاد داشته باشید که سایه زن های WebGL از نقطه شناور تک دقیق (یا بدتر از آن) برای همه محاسبات استفاده می کنند، و زمانی که ویژگی ها یا یکنواخت ها بیش از حد بزرگ می شوند، موقعیت یابی بسیار نادقیق می شود.

لطفا برای تماشای ویدیوی زیر کمی وقت بگذارید؛ این مکانیسم را در عمل نشان می دهد. ببینید که چگونه مقادیر بیکار برای هر بار که تکمیل translationمی شود بازنشانی می شود.scaleloadLocalResources()

مقادیر بیکار برای translationمنفی هستند زیرا مبدأ تجسم شمال غربی گوشه سمت چپ بالای وسعت فعلی است. این به این دلیل اتفاق می‌افتد که VisualizationLayerView2Dبه سبک تجسم می‌گوید تا وسعتی را بارگیری کند که ۱۵٪ بزرگتر از آنچه برای پوشاندن صفحه لازم است باشد. ما این کار را انجام می دهیم تا کمی فضای سر داشته باشیم و مصنوعات مرزی را از منطقه مورد نظر دور نگه داریم.

نمای کلی ما از مخزن کامل است. اکنون زمان آن است که به ۳ تجسم سفارشی جدید و پیاده سازی آنها نگاه کنیم! می‌توانید لایه‌های سفارشی جدید را به همراه نماهای لایه و سبک‌های تجسم آن‌ها در پوشه src/jumpstart پیدا کنید.

یک برنامه ( .ts ، .html ) وجود دارد که ۳ لایه سفارشی را به MapView اضافه می‌کند و توصیه می‌کنیم هنگام آزمایش کد، آن را در مرورگر خود باز نگه دارید. اگر اجرا می کنید npm start، نسخه زنده برنامه باید به طور خودکار در http://localhost:3000/demos/jumpstart.html باز شود. نسخه زنده نیز به صورت آنلاین در دسترس است.

برای هر تجسم، layer.tsفایل را که حاوی لایه سفارشی است و view.tsفایلی که حاوی نمای لایه سفارشی است، بررسی کنید. ببینید که چگونه لایه لغو createLayerView()می شود و چگونه نمای لایه از ارث می برد VisualizationLayerView2Dو نادیده می گیرد createVisualizationStyle().

سپس rendering.tsفایلی را که منابع جهانی، منابع محلی و سبک تجسم را تعریف می کند، بررسی کنید. تمام کدهای رندر WebGL در اینجا قرار دارند. لطفاً توجه داشته باشید که سبک‌های تجسم نیازی به نمای لایه ندارند و می‌توانند به طور مستقل از MapView نمونه‌سازی و استفاده شوند . این می تواند برای آزمایش و برای تولید تصاویر کوچک و گالری ها مفید باشد.

یکی از ویژگی‌های مشترک همه سبک‌های تجسم در مخزن، نحوه مدیریت ماتریس‌های تبدیل است. برای شروع، همه آنها از دو ماتریس به نام u_ScreenFromLocalو استفاده u_ClipFromScreenمی کنند، مکان های یکنواخت آنها همیشه در شی منابع سراسری و mat4نمونه های واقعی همیشه در شی منابع محلی نگهداری می شوند. علاوه بر این، محاسبه آنها همیشه به همین ترتیب انجام می شود.

در اینجا نحوه u_ScreenFromLocalمحاسبه است.

و در اینجا نحوه u_ClipFromScreenمحاسبه است.

نمونه کد شماره ۱: حالت نمایش “الگوی تست”

این تجسم وسعت عبور را به loadLocalResources()صورت یک مستطیل نیمه شفاف با حاشیه چین نشان می دهد. همچنین محدوده وسعت را در واحدهای نقشه نمایش می دهد.

چند نکته در مورد اجرا

نمونه کد شماره ۲: شطرنجی متحرک فانتزی

این تجسم داده‌های ارتفاع را از یک سرویس کاشی‌شده تصویر بارگیری می‌کند و کدورت هر پیکسل را با استفاده از فرمولی که زمان فعلی، ارتفاع پیکسل و تابع سینوسی را ترکیب می‌کند، متحرک می‌کند.

چند نکته در مورد اجرا

نمونه کد شماره ۳: نیروگاه های درخشان

این تجسم نقاط را از یک لایه ویژگی بارگیری می کند و آنها را به صورت نقاط درخشان درخشان تبدیل می کند. رنگ نقطه مشخصه محور است و افت کدورت با استفاده از تابع سینوسی متحرک می شود.

چند نکته در مورد اجرا

نتیجه گیری

امیدواریم که از این غواصی عمیق در دنیای لایه های WebGL سفارشی لذت برده باشید و مخزن انیمیشن-flow-ts برای پروژه خود مفید باشد.

بدون دیدگاه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

خانهدربارهتماسارتباط با ما