چای ۹: تبدیل GeoJSON به SVG با استفاده از D3


مقدمه

جئوجیسون (GeoJSON) یک فرمت ذخیره‌سازی و نمایش اطلاعات جغرافیایی (به همراه خصوصیات غیر برداری) برپایه فرمت JSON است که در برنامه‌ها و سیستم‌های مرتبط با اطلاعات جغرافیایی استفاده زیادی دارد.

حتی دیتابیس‌هایی مثل mongoDB از این فرمت منحصرا پشتیبانی کرده و از از یک داده JSON عادی متمایز می‌کنند.

این فرمت از داده‌های جغرافیایی مختلفی مثل نقطه (Point)، خط (LineString)، پولیگان (Polygon) و مجموعه‌هایی از آن‌ها -مثلا MultiPoint- پشتیبانی می‌کنه که در GeoJSON RFC تبیین شدن.

یک نمونه ساده از یک نقطه به‌فرمت GeoJSON به‌صورت زیر است:

نمایش یک نمونه GeoJSON در سایت geojson.io
نمایش یک نمونه GeoJSON در سایت geojson.io


برای نمایش بصری داده‌های جغرافیایی‌ از روش‌های مختلفی استفاده می‌شود، این داده‌ها را می‌توان به‌صورت تایل (کاشی [Tile]) شده و یا به‌صورت واحد، به فرمت‌های مختلف تصویر رستری (پیکسلی [raster])‌ یا وکتوری (برداری [vector]) نمایش داد. در این پست می‌خواهیم داده‌های جغرافیایی به فرمت GeoJSON رو به‌فرمت SVG که یکی از روش‌های مرسوم نمایش داده‌های گرافیکی -عموما تصاویر- و یکی از انعطاف‌پذیر‌ترین، کم‌حجم‌ترین و دردسترس‌ترین فرمت‌های استفاده شده در وب است تبدیل کنیم.

آماده‌سازی

برای این تبدیل از کتاب‌خونه D3 استفاده می‌کنیم و نیاز به یک محیط اجرای جاوا اسکریپت (Javascript) داریم که بتونیم توسط اون به DOM هم دسترسی داشته باشیم. بنابراین اگر از NodeJS برای این تبدیل استفاده می‌کنید یکی از پکیج‌های پیاده‌ساز DOM مثل jsdom و یا پکیجی مانند d3-node را استفاده کنید.

داده‌های GeoJSON

برای ساخت یک داده جغرافیایی به فرمت GeoJSON ابزار‌های حرفه‌ای زیادی مانند نرم‌افزار QGIS وجود دارن، اما برای سادگی‌کار از ابزار آنلاین geojson.io ساخت شرکت mapbox استفاده می‌کنیم. این سایت رو باز کنید و با استفاده از نوار ابزار سمت راست یک یا چند شکل (نقطه یا پولیگان یا غیره) رسم کنید:

رسم یک پولی‌گان (Polygon) در geojson.io
رسم یک پولی‌گان (Polygon) در geojson.io



تبدیل GeoJSON به SVG

ابتدا با استفاده از D3 یک SVG به سایز مورد نظرمون می‌سازیم:

const width = 200;
const height = 100;

const svg = d3
  .create(&quotsvg&quot)
  .attr(&quotwidth&quot, width)
  .attr(&quotheight&quot, height);


قبل از تبدیل کد GeoJSON به یک تصویر SVG، نکته مهمی رو لازم است بدونیم:

مختصات نقاط در فرمت GeoJSON به‌صورت پادساعت‌گرد ذخیره می‌شوند، درحالی‌که، D3 به‌صورت پیش‌فرض، یک عارضه‌را به‌صورت ساعت‌گرد انتظار داشته و در‌نظر می‌گیرد.

برای اینکه مختصات پولیگان خودمون رو به‌صورت ساعت‌گرد تبدیل کنیم، از ابزار mapbox/geojson-rewind استفاده می‌کنیم:

const _geoJson = rewind(polygon, true);




حال برای نمایش عارضه GeoJSON و تبدیل اون به SVG از d3-geo استفاده می‌کنیم که به‌صورت پیش‌فرض داخل D3 موجوده ولی به‌صورت یک کتابخانه جدا نیز ارائه میشه. برای اینکار کافیه تا با استفاده از d3.geoPath یک تابع path ایجاد کنیم و از آن در ساخت المان path داخل SVG خودمون استفاده کنیم.

با اینکه با استفاده از این روش فایل GeoJSON ما به‌درستی به SVG تبدیل شده، سایز نمایش اون درست نیست و درواقع کل محدوده مختصات جغرافیایی (کل نقشه جهان) به محدوده SVG ما نگاشت شده و در نتیجه پولیگان رسم‌شده بسیار کوچک خواهد بود.

برای اینکه بتونیم پولیگان را به اندازه فعلی SVG تصویر کنیم و به‌اصطلاح project کنیم به‌صورت زیر عمل می‌کنیم:

پولیگان تبدیل شده درحالت‌های تصویر نشده و تصویر شده به سایز SVG
پولیگان تبدیل شده درحالت‌های تصویر نشده و تصویر شده به سایز SVG


در این روش، مختصات تبدیل شده توسط سیستم تصویر مرکاتور (سیستمی برای نمایش نقشه جهان به‌صورت تخت) را به‌سایز فعلی SVG متناسب می‌کنیم.


نتیجه نهایی رو می‌تونید در مثال زیر مشاهده کنید:


https://stackblitz.com/edit/geojson-svg-d3?embed=1&file=index.js&hideExplorer=1



این پست، قسمت نهم از چای، مجموعه‌ای در باب «چیزی که امروز یادگرفتم» است. باقی چای‌ها رو می‌تونید از اینجا مشاهده کنید و در مورد فلسفه‌ی این کار بخونید.