كيفية إنشاء خريطة لأماكن السفر المرغوبة باستخدام Gatsby و React Leaflet و Hygraph
السفر متعة لا تضاهيها متعة، ولدينا جميعًا قائمة طويلة من الأماكن التي نحلم بزيارتها، ولكن نادرًا ما نجد الوقت الكافي لتحقيق كل ذلك دفعة واحدة. هنا يأتي دور “قائمة الأماكن المرغوبة للسفر” (Travel Bucket List)! ولكن كيف يمكننا إنشاء تطبيق خرائط مخصص يعرض جميع وجهاتنا المفضلة في مكان واحد؟
ملاحظة: اعتبارًا من يوليو 2022، أصبح اسم GraphCMS هو Hygraph. سيتم استخدام كلا الاسمين للإشارة إلى نفس الخدمة في هذا المقال.
ماذا سنبني؟
سنقوم ببناء تطبيق خرائط متكامل باستخدام Gatsby، يتم إدارة بياناته بواسطة نظام إدارة محتوى (CMS) مثل Hygraph. سيعرض هذا التطبيق علامات (markers) على الخريطة لوجهاتنا، بالإضافة إلى قائمة نصية بسيطة لتلك المواقع التي نرغب في زيارتها.

عرض توضيحي لتطبيق خريطة قائمة السفر المرغوبة
سنقوم بتشغيل التطبيق باستخدام قالب Gatsby Starter for Leaflet، ثم سنستخدم Hygraph لإنشاء وإدارة قائمة المواقع الخاصة بخريطتنا!
هل تطبيق الخرائط يبدو معقدًا؟ لا تقلق! إذا لم تكن قد تعاملت مع الخرائط من قبل، فلا تيأس. الأمر ليس بالصعوبة التي تتخيلها. إذا كنت تفضل البدء بأساسيات الخرائط، يمكنك قراءة المزيد حول كيفية عمل الخرائط أولاً.
الخطوة 1: إنشاء تطبيق جديد باستخدام Gatsby Starter Leaflet
سنبدأ باستخدام Gatsby Starter Leaflet. سيوفر لنا هذا القالب تطبيق React أساسيًا مع أدوات الخرائط مدمجة مسبقًا.
إنشاء تطبيق Gatsby جديد باستخدام Gatsby Starter Leaflet
للبدء، انتقل إلى المجلد الذي تريد إنشاء تطبيقك الجديد فيه وقم بتشغيل الأمر التالي:
gatsby new my-travel-bucket-list https://github.com/colbyfayock/gatsby-starter-leaflet
ملاحظة: يمكنك استبدال my-travel-bucket-list بأي اسم تريده. سيتم استخدام هذا الاسم لإنشاء المجلد الجديد للتطبيق.
بمجرد تشغيل الأمر، سيقوم Gatsby بتنزيل القالب وتثبيت التبعيات. بعد اكتمال العملية، انتقل إلى هذا الدليل وقم بتشغيل أمر التطوير:
cd my-travel-bucket-list
yarn develop # أو npm run develop
بمجرد الانتهاء، يجب أن يكون تطبيقك جاهزًا للعمل!
تنظيف بعض الأكواد التجريبية
نظرًا لأننا نستخدم قالبًا جاهزًا (Starter)، فإنه يحتوي على بعض الأكواد التجريبية. دعنا نقوم بتنظيفها لتجنب أي ارتباك.
افتح ملف src/pages/index.js.
أولاً، قم بإزالة كل شيء داخل دالة mapEffect باستثناء السطر الأول، وقم بإعداد اسم مستعار لـ leafletElement ليكون map:
async function mapEffect ( { leafletElement: map } = {} ) {
if ( !map ) return ;
}
بعد ذلك، يمكننا إزالة تعريف markerRef في الجزء العلوي من مكون IndexPage، وإزالة الخاصية ref={markerRef} من مكون <Marker> الخاص بنا، واستيراد useRef بجوار React.
الآن، يمكننا إزالة جميع المتغيرات التي تبدأ بـ popup و time، بما في ذلك:
timeToZoomtimeToOpenPopupAfterZoomtimeToUpdatePopupAfterZoompopupContentHellopopupContentGatsby
أخيرًا، يمكنك إزالة جميع الأسطر التالية:
import L from 'leaflet' ;
...
import { promiseToFlyTo, getCurrentLocation } from 'lib/map' ;
...
import gatsby_astronaut from 'assets/images/gatsby-astronaut.jpg' ;
...
const ZOOM = 10 ;
بمجرد الانتهاء، يجب أن نكون جاهزين للعمل مع تطبيق أساسي يحتوي على خريطة!

تطبيق جديد جاهز مع Gatsby Starter Leaflet
الخطوة 2: إنشاء وإدارة قائمة مواقع السفر باستخدام GraphCMS (Hygraph)
إنشاء حساب GraphCMS (Hygraph)
للبدء مع GraphCMS (الآن Hygraph)، ستحتاج إلى حساب. لن نتناول هذه الخطوة بالتفصيل، ولكن الخبر السار هو أنهم يقدمون خطة مجانية سخية تسهل علينا التسجيل لاستخدامها في عرضنا التوضيحي!
بدلاً من ذلك، إذا كان لديك حساب بالفعل، يمكنك التأكد من تسجيل دخولك.
إنشاء مشروع GraphCMS (Hygraph) جديد
بمجرد تسجيل الدخول، سنرغب في إنشاء مشروع جديد. سنقوم بإنشاء مشروع يدويًا، لذا بمجرد الوصول إلى لوحة تحكم GraphCMS Dashboard، اختر Create new project:

إنشاء مشروع جديد في GraphCMS
هنا، يمكنك إدخال ما تريده لـ Name و Description مثل:
Name: My Travel Bucket ListDescription: The locations that I want to travel to some day!
أسفل ذلك سترى خريطة حيث ستختار Region. هذا هو المكان الذي ستعيش فيه بيانات قاعدة بياناتك، وعلى الرغم من أنه قد لا يهم كثيرًا لأغراضنا، يمكنك اختيار الأقرب إليك.

تكوين مشروع جديد في GraphCMS
بعد تحديد خياراتك، انقر فوق Create Project.

اختيار الخطة الشخصية في GraphCMS
بعد ذلك، ستظهر لك خيارات الفوترة. نظرًا لأننا نقوم بإنشاء عرض توضيحي فقط، ضمن Personal، حدد Continue، وعند هذه النقطة سننتقل إلى لوحة تحكم مشروع GraphCMS الجديد الخاص بنا.
إنشاء مخطط نموذج محتوى (Content Model Schema) جديد باستخدام GraphCMS (Hygraph)
في GraphCMS (Hygraph)، يشير Content Model إلى نوع معين من البيانات له خصائص محددة مرتبطة به. في حالتنا، سيكون نموذجنا هو Destination (الوجهة)، والذي سيتم تعريفه بواسطة Name (الاسم) و Location (الموقع).
أولاً، انتقل إلى قسم Schema في GraphCMS (Hygraph) في الشريط الجانبي الأيسر وحدد Create Model.

إنشاء نموذج مخطط جديد في GraphCMS
بمجرد التحديد، سترى نافذة منبثقة تطلب بعض المعلومات الإضافية. هنا، يمكنك كتابة “Destination” كـ Display Name، والذي سيملأ أيضًا معظم الحقول الأخرى. سنتركها كما هي.

تكوين نموذج محتوى جديد في GraphCMS
لا تتردد في إضافة وصف إذا أردت، ولكنه غير مطلوب. ثم حدد Create model.
الآن بعد أن أصبح لدينا نموذجنا (Model)، نحتاج إلى خصائصنا. أولاً، حدد Single line text في القائمة اليمنى للحقول وأضف Display Name باسم “Name”. سيؤدي هذا أيضًا إلى ملء App Id الذي يمكنك تركه كما هو. ثم انقر فوق Create.

إضافة وتكوين حقل نصي جديد في GraphCMS
بعد ذلك، قم بالتمرير لأسفل في خيارات الحقول على اليمين وتحت Location حدد Map. أضف “Location” كـ Display Name، والذي سيحدد App Id كـ “location” والذي يمكنك تركه كما هو. ثم بنفس الطريقة السابقة، انقر فوق Create.

إضافة وتكوين حقل خريطة جديد في GraphCMS
الآن لدينا نموذج محتوى (Content Model) سنستخدمه لإنشاء مواقعنا!

نموذج محتوى الوجهة في GraphCMS
إنشاء مواقعنا
أخيرًا، دعنا ننشئ مواقعنا. انتقل إلى Content في لوحة تحكم GraphCMS (Hygraph)، وتأكد من تحديد Destination ضمن System (يجب أن يكون هو الوحيد)، ثم حدد Create New.

إنشاء محتوى وجهة جديد في GraphCMS
الآن يمكننا البدء في إضافة جميع مواقعنا! أولاً، أضف اسم موقعك في حقل Name، ثم يمكنك استخدام مربع البحث تحت Location للعثور على هذا الموقع على الخريطة.

إضافة عنصر محتوى وجهة جديد في GraphCMS
بمجرد الانتهاء، اضغط على Save and publish. سيؤدي هذا إلى إنشاء موقعك الأول! اتبع نفس الخطوات وقم بإنشاء العديد من المواقع كما تريد.

قائمة عناصر محتوى الوجهة في GraphCMS
سنستخدم هذه المواقع لخريطتنا وقائمة الأماكن المرغوبة.
الخطوة 3: استعلام بيانات مواقع GraphCMS (Hygraph) باستخدام Gatsby و GraphQL
الآن بعد أن أصبح لدينا مواقعنا، دعنا نستخدمها!
إضافة إضافة (Plugin) إلى Gatsby للاستعلام عن بيانات GraphQL
أولاً، نحتاج إلى إضافة إضافة جديدة إلى مشروع Gatsby الخاص بنا للاستعلام عن بيانات GraphQL. في طرفيتك (terminal)، تأكد من أن خادم التطوير لا يعمل وقم بتشغيل:
yarn add gatsby-source-graphql # أو npm install gatsby-source-graphql
بعد ذلك، افتح ملف gatsby-config.js في جذر مشروعك وأضف ما يلي إلى الإضافات (plugins) الخاصة بك:
{
resolve: 'gatsby-source-graphql',
options: {
typeName: 'GCMS',
fieldName: 'gcms',
url: '[API ENDPOINT]',
}
}
هذا هو ما سيقوم بجلب بياناتنا من GraphCMS (Hygraph)، ولكننا نحتاج إلى نقطة نهاية (endpoint).
العثور على نقطة نهاية API الخاصة بنا لـ GraphCMS (Hygraph)
افتح متصفحك مرة أخرى وتوجه إلى مشروع GraphCMS (Hygraph) الخاص بك. بعد تحديد Settings في قائمة التنقل اليسرى، حدد API Access.

الوصول إلى API في GraphCMS
قبل أن ننسخ نقطة نهاية API Endpoint الخاصة بنا، نحتاج أولاً إلى تحديث أذوناتنا حتى نتمكن من الاستعلام عن API الخاص بنا. ضمن Public API Permissions، ضع علامة في المربع بجوار Content from stage Published وانقر على Save.

تكوين أذونات API في GraphCMS
بعد ذلك، انسخ عنوان URL تحت Endpoints:

نسخ نقطة نهاية API في GraphCMS
والصقها في ملف gatsby-config.js الذي قمنا بتعديله أعلاه:
{
resolve: 'gatsby-source-graphql',
options: {
typeName: 'GCMS',
fieldName: 'gcms',
url: 'https: //[region-id].graphcms.com/v2/[project-id]/master',
},
},
ملاحظة: سيحتوي عنوان URL الخاص بك على قيم فعلية داخل [region-id] و [project-id].
احفظ ملف gatsby-config.js الخاص بك وابدأ تشغيل خادم التطوير مرة أخرى (yarn develop) ونحن جاهزون للانطلاق!
الاستعلام عن مواقعنا عبر GraphQL
أخيرًا، دعنا نستعلم عن بياناتنا بالفعل حتى نتمكن من استخدامها في تطبيقنا. سنقوم بإنشاء React Hook جديد سنتمكن من استخدامه لجلب مواقعنا في أي مكان داخل تطبيقنا.
ضمن src/hooks/index.js، أضف السطر التالي إلى القائمة الموجودة:
export { default as useDestinations } from './useDestinations' ;
سيسمح لنا هذا باستيراد خطافنا (hook) بشكل أكثر ملاءمة والذي سننشئه لاحقًا.
ضمن src/hooks، أنشئ ملفًا جديدًا باسم useDestinations.js والصق هذا الكود:
import { graphql, useStaticQuery } from 'gatsby' ;
export default function useDestinations ( ) {
const { gcms = {} } = useStaticQuery( graphql `
query {
gcms {
destinations {
id
name
location {
latitude
longitude
}
}
}
}
` );
let { destinations } = gcms;
return {
destinations,
};
}
هنا، نقوم بالآتي:
- استيراد أدوات
graphqlوuseStaticQueryمنGatsby. - نقوم بإنشاء دالة جديدة (أو خطاف
hook) يتم تصديرها افتراضيًا. - في هذه الدالة، نستخدم
useStaticQueryلإنشاء استعلامGraphQLجديد يطلب منGraphCMS(Hygraph) إرجاع بنية البيانات التي حددناها. - يعيد هذا الاستعلام قيمة نقوم بتفكيكها على الفور لجلب كائن
gmcs. - نقوم بتفكيك
destinationsمنgmcsوإعادتها كجزء من كائن جديد من خطافنا.
باستخدام هذا، يمكننا الآن استخدام خطافنا في أي مكان في تطبيقنا!
توجه إلى ملف src/pages/index.js الخاص بك، أولاً قم باستيراد خطافنا الجديد:
import { useDestinations } from 'hooks' ;
وفي الجزء العلوي من مكون IndexPage، استعلم عن بياناتنا:
const { destinations } = useDestinations();
يضع هذا جميع مواقعنا في متغير destinations. يمكننا اختبار ما إذا كان هذا يعمل عن طريق تسجيله في وحدة التحكم:
console .log( 'destinations' , destinations);
وبمجرد فتح متصفحنا والنظر في وحدة تحكم أدوات مطور الويب، يمكننا رؤية بيانات موقعنا!

تسجيل بيانات الوجهات في وحدة تحكم الويب
الخطوة 4: إنشاء قائمة بالأماكن المرغوبة وإضافتها إلى الخريطة
سنبدأ بإنشاء قائمة نصية بسيطة لوجهاتنا. سيتيح لنا هذا رؤية جميع وجهاتنا بتنسيق سهل القراءة.
إنشاء قائمة نصية لوجهاتنا
داخل IndexPage وفوق “Still Getting Started?”، دعنا نضيف الكود التالي:
<h2>My Destinations</h2>
<ul>
{ destinations.map(destination => {
const { id, name } = destination;
return <li key = {id} > { name } </li>
})}
</ul>
يقوم هذا الكود بالآتي:
- يضيف عنوانًا جديدًا لقائمتنا.
- ينشئ قائمة غير مرتبة جديدة (
unordered list). - يتكرر عبر
destinationsوينشئ عنصر قائمة جديدًا لكل وجهة يتضمن اسم الموقع.
بمجرد الحفظ وإعادة التحميل، يجب أن نرى قائمتنا أسفل خريطتنا!

قائمة أساسية جديدة للوجهات في التطبيق
تبدو القائمة غريبة بعض الشيء، أليس كذلك؟ ربما نريد تنسيقها بشكل أفضل لتناسب الصفحة.
افتح ملف src/assets/stylesheets/pages/_home.scss وداخل الفئة .home-start، أضف:
.home-start {
...
ul {
list-style : none;
padding : 0 ;
margin : 1.2em 0 ;
}
}
دعنا أيضًا نعدل h2 لتباعد الأشياء بشكل أفضل قليلاً:
.home-start {
...
h2 {
margin-top : 2em ;
& :first-child {
margin-top : 0 ;
}
}
}
بمجرد الحفظ وإعادة التحميل، يجب أن تبدو أفضل قليلاً.

الوجهات في التطبيق مع أنماط منسقة
لا تتردد في إجراء تغييرات إضافية، لكننا سنتركها عند هذا الحد في الوقت الحالي.
إضافة وجهاتنا إلى الخريطة
الآن يمكننا أخيرًا إضافة وجهاتنا إلى الخريطة!
داخل مكون <Map> الخاص بنا، لدينا بالفعل <Marker>. يسمح لنا هذا بإضافة علامة بسهولة إلى الخريطة بالنظر إلى موضع. سنأخذ هذا المفهوم ونجمعه مع قائمتنا النصية لإضافة مواقعنا إلى الخريطة.
دعنا نحدث كود <Map> الخاص بنا ليتطابق مع ما يلي:
< Map {...mapSettings}>
{ destinations.map( destination => {
const { id, name, location } = destination;
const position = [location.latitude, location.longitude];
return < Marker key = {id} position = {position} />
})}
</ Map >
هنا نقوم بالآتي:
- نتكرر عبر
destinationsلإنشاء قائمة جديدة ديناميكيًا من المكونات داخل<Map>الخاص بنا. - داخل كل تكرار، نقوم بتفكيك بياناتنا من
destination. - نقوم بإنشاء مصفوفة
positionجديدة مع خطوط الطول والعرض. - نقوم بإنشاء
Markerجديد حيث نستخدم موضعنا لإضافته إلى الخريطة.
هذا يعطينا علاماتنا على الخريطة!

علامات لكل وجهة في تطبيق الخرائط
لكننا نريد معرفة ما هي كل هذه المواقع، لذا دعنا نضيف أيضًا نافذة منبثقة (popup) لكل علامة ستظهر الاسم.
أولاً، نحتاج إلى استيراد Popup من react-leaflet:
import { Marker, Popup } from 'react-leaflet' ;
ثم، دعنا نحدث مكون <Marker> الخاص بنا لإرجاع:
return (
< Marker key = {id} position = {position} >
< Popup >
{ name }
</ Popup >
</ Marker >
);
وبمجرد الحفظ وإعادة فتح خريطتنا، يمكنك الآن النقر على كل علامة ورؤية اسم وجهاتنا!

نافذة منبثقة لكل علامة وجهة في تطبيق الخرائط
قبل الانتهاء، قم بتوسيط الخريطة
سابقًا، كانت خريطتنا التجريبية متمركزة حول واشنطن العاصمة. دعنا نحدث ذلك إلى مركز العالم نظرًا لأن خريطتنا لا تركز على الولايات المتحدة.
حدث متغير LOCATION إلى:
const LOCATION = {
lat : 0 ,
lng : 0 ,
};
وبهذا، أصبح لدينا خريطتنا جاهزة!

تطبيق الخرائط النهائي مع العلامات والنوافذ المنبثقة لكل وجهة
ميزات إضافية يمكننا إضافتها إلى تطبيقنا
إليك بعض الأفكار لتحسين تطبيقك وتوسيع وظائفه:
-
إضافة طريقة لتحديد كل موقع تم زيارته:
فيGraphCMS(Hygraph)، يمكنك إضافة حقل جديد إلى نموذج محتوىDestinationالخاص بك يسمح لك بتحديد ما إذا كنت قد زرت كل موقع أم لا. باستخدام هذه القيمة، يمكننا إضافتها إلى استعلامنا وتحديث خريطتنا بنوع من المؤشرات، مثل علامة صح، لإظهار أننا قد أتممنا زيارة هذا الموقع من قائمة الأماكن المرغوبة لدينا! -
تخصيص أنماط خلفية الخريطة:
نحن نستخدم إصدارًا عامًا منOpenStreetMapوهو مفتوح المصدر، ولكنMapboxيقدم بعض الخرائط الرائعة التي يمكننا استخدامها لجعلها تبدو أكثر إثارة للإعجاب. إذا كنت ترغب في البدء في تغيير أنماط خريطتك، يمكنك مراجعة هذا الدليل الآخر لمعرفة كيفية استخدامMapbox. -
تنسيق علامات الخريطة بصورة مخصصة:
يمكنك مراجعة دليل الفيديو الخاص بي حول كيفية تغيير العلامات إلى صورة مخصصة. يمكنك المضي قدمًا في ذلك واستخدام الميزة المذكورة أعلاه لإظهار صورة علامة مختلفة ديناميكيًا عند تحديد موقع كـ “تمت زيارته”.
هل ترغب في تعلم المزيد عن الخرائط؟
اطلع على بعض دروسي ومقاطع الفيديو الأخرى:
- الخرائط باستخدام React Leaflet (egghead.io)
- تطبيقات الخرائط باستخدام React و Gatsby و Leaflet (youtube.com)
- كيفية إنشاء لوحة تحكم وخريطة لتطبيق فيروس كورونا (COVID-19) باستخدام Gatsby و Leaflet (colbyfayock.com)
- كيفية إنشاء تطبيق خريطة لرحلة صيفية باستخدام Gatsby و Leaflet (colbyfayock.com)
- كيفية بناء تطبيق خرائط في React بالطريقة السهلة باستخدام Leaflet (colbyfayock.com)
- يمكن لأي شخص رسم الخرائط! إلهام ومقدمة لعالم رسم الخرائط (colbyfayock.com)
ما هي الأماكن التي تتمنى زيارتها في قائمة سفرك؟ شاركنا أفكارك على تويتر!
الخلاصة التقنية
لقد استعرضنا في هذا المقال عملية شاملة لبناء تطبيق خرائط تفاعلي باستخدام أحدث التقنيات في تطوير الويب. من خلال دمج Gatsby كإطار عمل ثابت سريع، و React Leaflet لتقديم الخرائط الديناميكية، و Hygraph (المعروف سابقًا بـ GraphCMS) كحل headless CMS لإدارة المحتوى، تمكنا من إنشاء تجربة مستخدم غنية ومرنة. تبرز أهمية هذه الأدوات في قدرتها على تبسيط عملية تطوير تطبيقات الخرائط المعقدة، مع توفير أداء عالٍ وقابلية للتوسع. إن استخدام GraphQL للاستعلام عن البيانات من Hygraph يضمن كفاءة عالية في جلب البيانات المطلوبة فقط، مما يعزز من سرعة التطبيق واستجابته. هذا النهج يفتح آفاقًا واسعة للمطورين لإنشاء تطبيقات خرائط مخصصة تلبي احتياجات متنوعة، سواء كانت لقوائم السفر الشخصية أو لمشاريع تجارية أكبر.