بناء لوحة تحكم وتطبيق خريطة لكوفيد-19 باستخدام React و Gatsby و Leaflet

دقائق القراءة: 10

مقدمة: بناء خرائط تفاعلية لبيانات كوفيد-19

لقد غيَّرت جائحة فيروس كورونا (كوفيد-19) بشكل جذري طريقة تفاعلنا اليومي. فكيف يمكننا الاستفادة من واجهات برمجة التطبيقات (APIs) المتاحة لبناء تطبيق خرائط يوضح تأثير هذه الجائحة على العالم؟ يهدف هذا المقال إلى تقديم دليل عملي خطوة بخطوة لإنشاء لوحة تحكم وتطبيق خريطة تفاعلية لعرض بيانات كوفيد-19 باستخدام تقنيات الويب الحديثة.

ملاحظة هامة من المؤلف: هذا المشروع هو بمثابة عرض توضيحي وإثبات لمفهوم بناء تطبيق خرائط مؤثر باستخدام بيانات واقعية. للحصول على تحليل كامل ودقيق، يرجى التأكد من استخدام أدوات موثوقة مثل لوحة تحكم جامعة جونز هوبكنز. ابقوا في منازلكم وكونوا بأمان! ❤️

تحديث واجهة برمجة التطبيقات (API)

تم إهمال نقطة النهاية الأصلية NovelCOVID API v1. يرجى التحديث واستخدام نقطة النهاية التالية بدلاً منها: https://corona.lmao.ninja/v2/countries

ماذا سنبني في هذا المشروع؟

سنقوم بتطوير تطبيق خرائط يستخدم واجهة برمجة تطبيقات (API) تحتوي على إحصائيات حديثة لفيروس كورونا، ويرسم خرائط للمواقع والتأثير الذي تواجهه كل دولة.

لوحة تحكم وخريطة تفاعلية لتطبيق كوفيد-19 مبني باستخدام React و Gatsby و Leaflet

على الخريطة، سنعرض علامة (marker) لكل دولة مع عدد الحالات المؤكدة. علاوة على ذلك، سنقوم بتضمين تلميح منبثق (popup tooltip) يظهر معلومات أكثر تفصيلاً.

ستبدو الخريطة التي سنبنيها مشابهة للصورة أعلاه إلى حد كبير، ولكنها ستكون أبسط قليلاً. سنستخدم خادم البلاط العام (public tileserver) الخاص بـ OpenStreetMap بدلاً من استخدام Mapbox مخصص.

للبدء، سنستخدم Leaflet Gatsby Starter الذي أعددته لجعل الإعداد الأولي أكثر سلاسة. بعد تهيئة تطبيقنا، سنقوم بجلب بياناتنا وإضافة علامات إلى الخريطة بها.

تطبيق خرائط؟ لا تقلق!

إذا لم تكن قد تعاملت مع الخرائط من قبل، فلا تيأس! الأمر ليس بالصعوبة التي تتخيلها. إذا كنت تفضل البدء بأساسيات الخرائط، يمكنك قراءة المزيد حول كيفية عمل الخرائط أولاً.

ماذا نحتاج قبل البدء؟

إذا كنت قد تابعت دروسي السابقة لبناء متتبع سانتا أو إنشاء خريطة لرحلة صيفية، يمكنك اتباع نفس الخطوات للبدء. إذا لم يكن الأمر كذلك، فسنحتاج إلى التأكد من إعداد ما يلي:

  • node أو yarn – سأستخدم yarn، ولكن يمكنك استبداله بـ npm عند الاقتضاء.
  • واجهة سطر الأوامر (CLI) الخاصة بـ Gatsby
    yarn global add gatsby-cli

إذا لم تكن متأكدًا من أي مما سبق، يمكنك مراجعة بداية البرنامج التعليمي السابق.

سنحتاج أيضًا إلى إعداد أساس لخريطتنا. يمكننا القيام بذلك باستخدام Leaflet Gatsby Starter الذي أعددته، والذي يوفر لنا إعدادًا أساسيًا مع Leaflet و React Leaflet.

gatsby new my-coronavirus-map https://github.com/colbyfayock/gatsby-starter-leaflet

إنشاء تطبيق خريطة كورونا جديد باستخدام Gatsby CLI و Leaflet Starter في سطر الأوامر

بعد انتهاء التشغيل، يمكنك الانتقال إلى دليل المشروع الذي تم إنشاؤه حديثًا وبدء خادم التطوير المحلي:

cd my-coronavirus-map
yarn develop

بدء تشغيل خادم تطوير Gatsby المحلي في سطر الأوامر

إذا سار كل شيء كما هو مخطط له، يجب أن يبدأ الخادم الخاص بك، ويجب أن تكون قادرًا الآن على رؤية تطبيق الخرائط الأساسي الخاص بك في متصفحك!

تطبيق خريطة Gatsby-Leaflet الأساسي يعمل في المتصفح

الخطوة 1: تنظيف الكود غير الضروري

يأتي Gatsby Starter الذي نستخدمه لتشغيل هذا التطبيق مع بعض الأكواد التجريبية التي لا نحتاجها هنا. سنقوم بإجراء جميع التغييرات أدناه في الملف src/pages/index.js، وهو الصفحة الرئيسية لتطبيقنا.

أولاً، دعنا نزيل كل شيء من دالة mapEffect. تُستخدم هذه الدالة لتشغيل الكود الذي يتم تنفيذه عند عرض الخريطة.

// في src/pages/index.js
async function mapEffect ( { leafletElement } = {} ) {
  // تخلص من كل شيء هنا
}

سنقوم أيضًا بتغيير اسم المتغير leafletElement ببساطة لتسهيل فهم الكود أثناء كتابته.

async function mapEffect ( { leafletElement: map } = {} ) {

}

بعد ذلك، لا نريد علامة (marker) هذه المرة، لذا دعنا نزيل مكون <Marker> من مكون <Map> الخاص بنا:

<Map {...mapSettings} />

الآن بعد أن قمنا بمسح هذه الأجزاء، يمكننا إزالة جميع الاستيرادات والمتغيرات التالية من أعلى ملفنا:

  • useRef
  • Marker
  • promiseToFlyTo
  • getCurrentLocation
  • gatsby_astronaut
  • timeToZoom
  • timeToOpenPopupAfterZoom
  • timeToUpdatePopupAfterZoom
  • ZOOM
  • popupContentHello
  • popupContentGatsby
  • markerRef

بعد ذلك، يجب أن تستمر خريطتنا في العمل، ولكنها لن تفعل أي شيء.

تطبيق الخرائط الجديد بعد إزالة الأكواد التجريبية

الخطوة 2: جلب بيانات فيروس كورونا

لتطبيقنا، سنستخدم NovelCOVID API. على وجه الخصوص، سنستخدم نقطة النهاية الخاصة بالدول (countries endpoint) لجلب قائمة الدول والإحصائيات المرتبطة بها.

لإجراء الطلبات، أنا شخصياً أفضل استخدام axios لأنه يحتوي على واجهة برمجة تطبيقات سهلة الاستخدام. إذا كنت ترغب في استخدام fetch أو مكتبة الطلبات المفضلة لديك، فاستبدلها في هذه الخطوة. سنبدأ بتثبيت axios:

yarn add axios

بمجرد التثبيت، تذكر إعادة تشغيل الخادم الخاص بك. قم باستيراد حزمة axios في أعلى ملف pages/index.js الخاص بنا:

import axios from 'axios';

بعد ذلك، سنقوم بالفعل بتقديم طلبنا. داخل دالة mapEffect الخاصة بنا، دعنا نحاول تقديم طلب إلى نقطة نهاية API:

async function mapEffect ( { leafletElement: map } = {} ) {
  let response;

  try {
    response = await axios.get(
      'https://corona.lmao.ninja/v2/countries'
    );
  } catch (e) {
    console
      .log(`Failed to fetch countries: ${e.message}`, e);
    return;
  }

  const { data = [] } = response;
}

في هذا المقتطف، نقوم بما يلي:

  • إعداد متغير response الذي سيسمح لنا بتخزين الاستجابة.
  • إضافة كتلة try/catch التي ستلتقط أي أخطاء في API إذا فشل الطلب.
  • إذا كان الطلب ناجحًا، نقوم بتخزين الاستجابة في متغير response.
  • إذا فشل الطلب، نقوم بتسجيل الخطأ في وحدة التحكم والعودة من الدالة حتى لا نستمر في تشغيل الكود بطلب فاشل.

بمجرد حصولنا على استجابتنا، يمكننا تفكيك (destructure) data من الاستجابة وتعيين القيمة الافتراضية إلى مصفوفة فارغة، حيث سيكون هذا هو نوع البيانات التي نحتاجها.

بعد إعداد ذلك، يمكننا تسجيل كائن data في وحدة التحكم وسنرى بياناتنا تم جلبها بنجاح!

بيانات مواقع كورونا المعروضة في وحدة تحكم المتصفح

الخطوة 3: تحويل بيانات فيروس كورونا إلى تنسيق بيانات جغرافية

الآن بعد أن أصبح لدينا بياناتنا، يمكننا تحويلها إلى تنسيق بيانات جغرافية، وتحديداً GeoJSON، مما سيتيح لنا التفاعل مع Leaflet. دعنا نبدأ بإضافة كتلة الكود هذه:

const { data = [] } = response;

const hasData = Array.isArray(data) && data.length > 0;

if ( !hasData ) return;

const geoJson = {
  type: 'FeatureCollection',
  features: data.map((country = {}) => {
    const { countryInfo = {} } = country;
    const { lat, long: lng } = countryInfo;
    return {
      type: 'Feature',
      properties: {
        ...country,
      },
      geometry: {
        type: 'Point',
        coordinates: [ lng, lat ]
      }
    }
  })
}

إذن، ماذا نفعل هنا؟

  • نقوم بإنشاء ثابت جديد يسمى hasData يتحقق مما إذا كان متغير data الخاص بنا مصفوفة ويحتوي على بيانات.
  • إذا لم يكن لدينا بيانات، فإننا نعود من الدالة، حيث لا نريد محاولة إضافة بيانات لا نملكها.
  • نقوم بإنشاء كائن geoJson سيكون مستند GeoJSON الخاص بنا.
  • مستندنا من النوع FeatureCollection، وكـ features نقوم بالتكرار عبر مجموعة البيانات الخاصة بنا.
  • لكل دولة في بياناتنا، نحصل على lat و lng لإنشاء نقطة لخريطتنا.
  • بالإضافة إلى ذلك، نضيف بيانات دولتنا كـ properties حتى نتمكن من الوصول إليها داخل واجهات برمجة تطبيقات الخرائط الخاصة بنا.

إذا قمت بتسجيل (console.log) هذا الكائن في متصفحك ونسخت المحتويات، يمكنك لصقها في geojson.io ورؤية بيانات الموقع تظهر بشكل صحيح.

معاينة بيانات مواقع كورونا بصيغة GeoJSON على موقع geojson.io

باستخدام مستند GeoJSON هذا، سنتمكن الآن من إضافته إلى خريطتنا.

الخطوة 4: إضافة بيانات فيروس كورونا إلى الخريطة

لدينا مستند GeoJSON الخاص بنا مع بيانات الموقع، لذا دعنا نضيفه إلى الخريطة. دعنا نبدأ بكتلة الكود هذه. إنها طويلة، لكننا سنقوم بتقسيمها قطعة قطعة:

const geoJsonLayers = new L.GeoJSON(geoJson, {
  pointToLayer: (feature = {}, latlng) => {
    const { properties = {} } = feature;
    let updatedFormatted;
    let casesString;

    const {
      country,
      updated,
      cases,
      deaths,
      recovered
    } = properties

    casesString = `${cases}`;

    if ( cases > 1000 ) {
      casesString = `${casesString.slice(0, -3)}k+`
    }

    if ( updated ) {
      updatedFormatted = new Date(updated).toLocaleString();
    }

    const html = `
      <span class="icon-marker">
        <span class="icon-marker-tooltip">
          <h2>${country}</h2>
          <ul>
            <li><strong>Confirmed:</strong> ${cases}</li>
            <li><strong>Deaths:</strong> ${deaths}</li>
            <li><strong>Recovered:</strong> ${recovered}</li>
            <li><strong>Last Update:</strong> ${updatedFormatted}</li>
          </ul>
        </span>
        ${ casesString }
      </span>
    `;

    return L.marker( latlng, {
      icon: L.divIcon({
        className: 'icon',
        html
      }),
      riseOnHover: true
    });
  }
});

إذن، ماذا نفعل هنا؟

  • نقوم بإنشاء مثيل جديد من L.GeoJSON الذي سيحول مستند GeoJSON الخاص بنا إلى شيء سيفهمه Leaflet.
  • داخل هذا المثيل، نقوم بتعريف دالة pointToLayer مخصصة. يسمح لنا هذا بتخصيص طبقة الخريطة التي ينشئها Leaflet لخريطتنا.
  • في دالتنا، نقوم بتعيين وإنشاء نقاط البيانات التي نريدها. معظمها هو تفكيك (destructuring)، لكننا نقوم بتنسيق عدد الحالات لعرض 1k+ بدلاً من 1000 وتاريخ منسق بدلاً من الطابع الزمني.
  • نقوم بإنشاء كتلة سلسلة HTML تُستخدم لتعريف علامة الخريطة (map marker) التي ستتم إضافتها إلى الخريطة. يتضمن هذا أيضًا HTML للتلميح المنبثق (tooltip) الذي سيظهر عند التمرير فوق علامة.
  • نقوم بإرجاع L.marker مع تكويننا المخصص الذي يتضمن فئة icon للحاوية و HTML المخصص الخاص بنا. بالإضافة إلى ذلك، نضيف خاصية riseOnHover بحيث عند التمرير فوق علامة، تظهر فوق العلامات الأخرى على الخريطة.

نريد أيضًا إضافة بعض CSS هنا حتى نتمكن من التأكد من ظهور علاماتنا في الخريطة وأنها قابلة للاستخدام. دعنا نضيف هذا المقتطف إلى ملف assets/stylesheets/components/_map.scss الخاص بنا:

.icon-marker {
  display: flex;
  position: relative;
  justify-content: center;
  align-items: center;
  color: white;
  width: 3.6em;
  height: 3.6em;
  font-size: .7em;
  font-weight: bold;
  background-color: $red-800;
  border-radius: 100%;
  box-shadow: 0 2px 5px rgba(black, .9);

  &:hover {
    .icon-marker-tooltip {
      display: block;
    }
  }
}

.icon-marker-tooltip {
  display: none;
  position: absolute;
  bottom: 100%;
  width: 16em;
  font-size: 1.4em;
  padding: 1em;
  background-color: $blue-grey-900;
  border-radius: .4em;
  margin-bottom: 1em;
  box-shadow: 0 3px 5px rgba(black, .9);

  &:before {
    display: block;
    position: absolute;
    bottom: -.6em;
    left: 50%;
    content: '';
    width: 1.4em;
    height: 1.4em;
    background-color: $blue-grey-900;
    transform: rotate(45deg);
    margin-left: -.7em;
  }

  h2 {
    font-size: 1.5em;
    line-height: 1.2;
    margin-bottom: .1em;
    margin-top: 0;
  }

  h3 {
    font-size: 1.2em;
    margin: .1em 0;
    font-weight: normal;
    color: $blue-grey-100;
  }

  ul, p {
    font-weight: normal;
  }

  ul {
    list-style: none;
    padding: 0;
    margin: .6em 0 0;
  }
}

ما نقوم به هنا:

  • نقوم بإنشاء علاماتنا الدائرية باستخدام فئة .icon-marker ونقوم بإعداد فئة .icon-marker-tooltip لتظهر عند التمرير فوقها.
  • تكون فئة .icon-marker-tooltip مخفية افتراضيًا، لأنها تلميحنا، لكننا نضعها بشكل مطلق لتظهر فوق علامتنا ويتم تنسيقها بالطريقة التي نريدها.

وأخيرًا، بمجرد إنشاء geoJsonLayers مع إضافة تصميمنا، يمكننا إضافتها إلى الخريطة!

geoJsonLayers.addTo(map)

الخريطة تعرض بيانات مواقع كورونا مع المؤشرات

الآن قد تتساءل لماذا لا يبدو أنها تتمركز بشكل صحيح. امض قدمًا وقم بتغيير متغير LOCATION في أعلى ملف index.js إلى:

const LOCATION = {
  lat: 0,
  lng: 0
};

بمجرد تعيين ذلك، عند إعادة تحميل الصفحة، يجب أن تتمركز الخريطة في منتصف العالم!

خريطة بيانات كورونا متمركزة عالمياً مع تلميحات المؤشرات

تهانينا، لقد أنجزنا ذلك! 🎉 إذا تابعت الخطوات، فقد أنشأت الآن لوحة تحكم خريطة فيروس كورونا الخاصة بك والتي توفر بعض الإحصائيات السريعة حول الحالات حول العالم. استفد مما تعلمته وطبقه. يمكنك تطبيق هذا على أي نوع آخر من البيانات التي يمكنك تخيلها.

ماذا يمكننا أن نفعل أيضًا؟

إضافة المزيد من الأنماط وخريطة أساس مخصصة

في عرضي التوضيحي الأصلي، قمت بإعداد خريطة أساس مخصصة باستخدام Mapbox تسمح لي بالحصول على خلفية داكنة مما يجعل العلامات أسهل في الرؤية.

إنشاء خريطة أساس مخصصة في Mapbox Studio

Mapbox رائع ولديه طبقة مجانية جيدة إذا كنت مهتمًا بالبدء. بمجرد أن يكون لديك حساب Mapbox، يمكنك حتى نسخ النمط الذي استخدمته وجعله خاصًا بك: Basic Dark Mapbox Theme.

لمعرفة كيفية دمجه، يمكنك محاولة التحقق من الكود المصدري لعرضي التوضيحي الأصلي: https://github.com/colbyfayock/coronavirus-map-dashboard

إضافة إحصائيات لوحة التحكم الشاملة

تسمح لوحات التحكم مع الخرائط مثل تطبيق جامعة جونز هوبكنز لنا برؤية أكثر من مجرد نظرة على الخريطة، بل لمحة عن الإحصائيات السريعة حول الحالات حول العالم.

لوحة تحكم خريطة جامعة جونز هوبكنز لكوفيد-19

تحتوي NovelCOVID API على نقاط نهاية إضافية مثل /all التي توفر بعض الإحصائيات العالمية.

ابقَ آمناً ومطلعاً

أود أن أكرر أنه يجب عليك التأكد من البقاء على اطلاع باستخدام المصادر الرسمية للمعلومات، مثل لوحة تحكم جامعة جونز هوبكنز. على الرغم من أن البيانات يجب أن تكون موثوقة، إلا أنها يجب أن تُعتبر أيضًا إثباتًا للمفهوم لبناء خريطة ومرجعًا، ولكن لا ينبغي اعتبارها لأي نوع من التحليل الإحصائي. يرجى الاعتناء بأنفسكم خلال هذه الأوقات. نحن جميعًا معًا في هذا! ❤️

هل تريد معرفة المزيد عن الخرائط؟

يمكنك الاطلاع على بعض مصادري الأخرى للبدء:

صورة تذييل اجتماعي للمؤلف كولبي فايوك

الخلاصة التقنية

يُظهر هذا المشروع كيف يمكن دمج قوة مكتبات الواجهة الأمامية الحديثة مثل React و Gatsby مع مكتبات الخرائط المتخصصة مثل Leaflet لإنشاء تطبيقات ويب تفاعلية وغنية بالبيانات. من خلال الاستفادة من واجهات برمجة التطبيقات العامة وتحويل البيانات إلى تنسيقات جغرافية قياسية مثل GeoJSON، يمكن للمطورين بناء لوحات تحكم مرئية توفر رؤى قيمة. إن القدرة على تخصيص عرض البيانات، مثل المؤشرات والتلميحات المنبثقة، تزيد من سهولة استخدام التطبيق وتفاعله مع المستخدم. هذا النهج ليس مقتصرًا على بيانات الجائحة فحسب، بل يمكن تطبيقه على مجموعة واسعة من مجموعات البيانات الجغرافية، مما يفتح آفاقًا جديدة لتصور البيانات المكانية.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *