معظم منتجات الاكتشاف المحلي تحيا أو تموت على شاشة واحدة: الخريطة. يفتح المستخدم تطبيقك ليجيب عن سؤال بسيط، ما الذي يجري بالقرب مني الآن، والخريطة هي وسيلته للإجابة. إتقان هذه الخريطة، بعلاماتها الصحيحة وتصفيتها السريعة وقوائمها التي تستطيع محركات البحث قراءتها فعلاً، هو العمل الهندسي الجوهري خلف أي دليل فعاليات.
يقودك هذا الدليل عبر بناء خريطة فعاليات لمدينة من الصفر: نمذجة بيانات الفعالية، وتحويل عناوين الأماكن إلى إحداثيات، ورسم العلامات وتجميعها، والتصفية حسب الفئة والحي، وجعل القوائم قابلة للاكتشاف. يفترض الدليل أنك تعرف بالفعل كيف تعرض خريطة أساسية. إن لم تكن تعرف، فابدأ بدرسنا حول كيف تضيف خرائط تفاعلية إلى موقعك ثم عُد إلى هنا للأجزاء الخاصة بالفعاليات.
نمذجة الفعالية حول مكانها
الفعالية شيء محدود بالزمن يحدث في مكان. المكان هو ما يظهر على الخريطة، لذا فالمكان هو محور نموذج بياناتك. أبسط سجل لفعالية يبدو هكذا:
const event = {
id: 'evt_8471',
title: 'Late Night Jazz at The Vortex',
category: 'live-music',
venue: 'The Vortex Jazz Club, 11 Gillett Square, London N16 8AZ',
coords: null, // يُملأ عبر geocoding، مرة واحدة
neighbourhood: null, // يُملأ عبر reverse geocoding، مرة واحدة
startsAt: '2026-07-09T20:30:00Z',
url: 'https://example.com/tickets/8471',
};
الحقلان null مهمان. لا تريد تحويل عنوان المكان في كل مرة تُحمّل فيها الخريطة. حوّله مرة واحدة، عند إنشاء الفعالية أو استيرادها، ثم خزّن الإحداثيات وتعامل معها كأنها دائمة.
الخطوة 1: حوّل كل مكان إلى إحداثيات
عملية geocoding تحوّل العنوان البشري إلى خط عرض وخط طول تستطيع رسمهما. أرسل نص المكان إلى Geocoding API واقرأ الإحداثيات من النتيجة الأولى:
async function geocodeVenue(address) {
const url = new URL('https://api.mapatlas.eu/geocoding/v1/search');
url.searchParams.set('text', address);
url.searchParams.set('size', '1');
const res = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
const data = await res.json();
const top = data.features?.[0];
if (!top) return null;
const [lon, lat] = top.geometry.coordinates;
return { lat, lon, label: top.properties.label };
}
نفّذ هذا وقت الكتابة، عندما تدخل الفعالية نظامك، واحفظ الإحداثيات المُرجعة على السجل. لشرح كامل لأهمية دقة موقع العلامة، وكيف تختلف إحداثيات سطح المبنى عن الباب الذي يمشي إليه الناس فعلاً، انظر تحديد إحداثيات مدخل المبنى.
الخطوة 2: ارسم الفعاليات كعلامات
مع وجود إحداثيات على كل فعالية، يصبح الرسم مجرد حلقة تكرار. امنح كل فئة لونها الخاص لتكون الخريطة مقروءة بلمحة:
const CATEGORY_COLORS = {
'live-music': '#E75480',
'theatre': '#006BA6',
'comedy': '#EE7C0E',
'food': '#16A34A',
'nightlife': '#7C3AED',
};
function plotEvents(map, events) {
events.forEach((evt) => {
if (!evt.coords) return;
const popup = new mapmetricsgl.Popup().setHTML(
`<strong>${evt.title}</strong><br>${new Date(evt.startsAt).toLocaleString()}` +
`<br><a href="${evt.url}">التذاكر</a>`,
);
new mapmetricsgl.Marker({ color: CATEGORY_COLORS[evt.category] || '#0c3456' })
.setLngLat([evt.coords.lon, evt.coords.lat])
.setPopup(popup)
.addTo(map);
});
}
هذا هو النمط الذي تقوم عليه المنتجات الحقيقية. مثال حي هو OnlyHere، وهو دليل يومي للأنشطة في لندن يحوّل كل مكان إلى إحداثيات ويرسم فعاليات اليوم على خريطة MapAtlas تفاعلية، فيتمكن المستخدم من تصفح ما يجري حسب المكان والحي بدل تمرير قائمة مسطحة.
الخطوة 3: جمّع العلامات حين تمتلئ المدينة
العلامات الفردية جيدة لعدد قليل من الفعاليات. لكن تدفق فعاليات على مستوى المدينة ليس عدداً قليلاً. بمجرد أن تتجاوز نحو 100 إلى 200 علامة، انقل الفعاليات إلى مصدر GeoJSON ودع الخريطة تجمّعها:
map.addSource('events', {
type: 'geojson',
cluster: true,
clusterRadius: 50,
data: {
type: 'FeatureCollection',
features: events.filter((e) => e.coords).map((e) => ({
type: 'Feature',
geometry: { type: 'Point', coordinates: [e.coords.lon, e.coords.lat] },
properties: { title: e.title, category: e.category },
})),
},
});
الآن تعرض ليلة مزدحمة في وسط المدينة فقاعة واحدة مع عدّاد بدل مئة علامة متراكبة، وتنقسم المجموعة إلى أجزاء كلما كبّر المستخدم.
الخطوة 4: صفِّ حسب الفئة والحي
التصفية هي حيث تتحول خريطة الفعاليات إلى منتج فعاليات. احتفظ بالقائمة الكاملة في الذاكرة وصفِّ المصفوفة، ثم سلّم المجموعة المصفّاة إلى مصدر الخريطة بدل إعادة بناء العلامات يدوياً:
function applyFilters(map, allEvents, { category, neighbourhood }) {
const filtered = allEvents.filter((e) =>
(!category || e.category === category) &&
(!neighbourhood || e.neighbourhood === neighbourhood),
);
map.getSource('events').setData({
type: 'FeatureCollection',
features: filtered.filter((e) => e.coords).map((e) => ({
type: 'Feature',
geometry: { type: 'Point', coordinates: [e.coords.lon, e.coords.lat] },
properties: { title: e.title },
})),
});
return filtered;
}
لملء حقل neighbourhood، طبّق reverse geocoding على إحداثيات كل مكان مرة واحدة واحفظ اسم المنطقة الإدارية. تلك القيمة الواحدة تشغّل قائمة منسدلة للأحياء، وعرض "ما الفعاليات في هذه المنطقة"، وصفحة قوائم أنظف، كل ذلك دون أي استعلام إضافي وقت التشغيل.
الخطوة 5: اجعل القوائم قابلة للاكتشاف
الخريطة تجيب عن السؤال للشخص الموجود بالفعل داخل تطبيقك. لكنها لا تفعل شيئاً للجمهور الأكبر بكثير الذي يسأل محرك بحث أو مساعد ذكاء اصطناعي "ما الفعاليات في هذا الحي الليلة". تلك الأنظمة تقرأ البيانات المنظمة، لا البكسلات.
وسّم كل فعالية بحقول schema.org Event، وأعد استخدام الإحداثيات التي لديك بالفعل:
{
"@context": "https://schema.org",
"@type": "Event",
"name": "Late Night Jazz at The Vortex",
"startDate": "2026-07-09T20:30:00Z",
"location": {
"@type": "Place",
"name": "The Vortex Jazz Club",
"geo": { "@type": "GeoCoordinates", "latitude": 51.5462, "longitude": -0.0753 }
}
}
الإحداثيات التي ترسم العلامة تغذّي أيضاً البيانات المنظمة، فيأتي العرض والاكتشاف من مصدر واحد للحقيقة. هذا هو الفرق بين خريطة تبدو جميلة ومنتج يُعثر عليه. لمزيد حول سبب دفع بيانات الموقع القابلة للقراءة آلياً لظهورك في بحث الذكاء الاصطناعي، انظر دليلنا حول الأسئلة الشائعة المرتبطة بالموقع لبحث الذكاء الاصطناعي.
نجمع كل شيء معاً
خريطة فعاليات المدينة خمسة أجزاء متحركة: نموذج بيانات محوره المكان، وgeocoding وقت الكتابة، وعلامات ملوّنة، وتجميع عند الحجم الكبير، وتصفية قائمة على المصفوفات، وكلها تجلس فوق بيانات منظمة تبقي القوائم قابلة للاكتشاف. ابنِ هذه الأجزاء على منصة جغرافية واحدة، وستتدفق الإحداثيات بنظافة من المحوّل إلى الخريطة إلى الـ schema، دون استعلامات مكررة ودون بيانات متضاربة.
يمنحك MapAtlas خدمات geocoding وreverse geocoding والبحث عن الأماكن وعرض الخرائط لبناء كل ذلك على بنية تحتية مستضافة في الاتحاد الأوروبي ومتوافقة مع GDPR. استكشف Geocoding API وSearch API لتبدأ برسم مدينتك.
الأسئلة الشائعة
ما البيانات التي أحتاجها لبناء خريطة فعاليات لمدينة؟
كحد أدنى، تحتاج كل فعالية إلى عنوان المكان، وفئة، ووقت بدء. العنوان هو ما يحوّل الفعالية إلى علامة على الخريطة: تحوّله مرة واحدة إلى خط عرض وخط طول (geocoding)، ثم تخزّن هذه الإحداثيات وتعيد استخدامها في كل مرة تُعرض فيها الفعالية. أما كل شيء آخر مثل روابط التذاكر والصور والأوصاف، فهو بيانات وصفية تُرفقها بنافذة العلامة المنبثقة.
كيف أحوّل عنوان المكان إلى إحداثيات على الخريطة؟
استدعِ واجهة geocoding API مع نص عنوان المكان، ثم اقرأ خط العرض وخط الطول من الاستجابة. مع MapAtlas Geocoding API ترسل العنوان كاستعلام نصي إلى https://api.mapatlas.eu/geocoding/v1/search وتستخدم إحداثيات النتيجة الأولى. حوّل كل مكان مرة واحدة عند إنشاء الفعالية، وليس عند كل تحميل للصفحة، حتى تبقى الخريطة سريعة ويبقى استهلاكك للواجهة منخفضاً.
كم عدد علامات الفعاليات التي يمكن أن تعرضها الخريطة قبل أن تصبح بطيئة؟
يبقى عرض العلامات الفردية سلساً حتى نحو 100 إلى 200 علامة في عرض متباعد. بعد ذلك، انتقل إلى تجميع مصدر GeoJSON، الذي يجمع الفعاليات المتقاربة في فقاعة عدّ واحدة عند مستوى التكبير المنخفض، ثم يفرّقها عند التكبير. أي تدفق فعاليات على مستوى المدينة يضم مئات القوائم يجب أن يستخدم التجميع من البداية.
كيف أتيح للمستخدمين تصفية الفعاليات حسب الفئة أو الحي؟
احتفظ بقائمة الفعاليات الكاملة في الذاكرة كمصفوفة، وأرفق فئة وحياً بكل عنصر، ثم صفِّ هذه المصفوفة استجابة لاختيار المستخدم. بعد ذلك حدّث مصدر الخريطة بالمجموعة المصفّاة بدل حذف العلامات وإعادة بنائها. التصفح حسب الحي يعمل بالطريقة نفسها: صفِّ إلى الفعاليات التي تقع إحداثياتها داخل المنطقة المختارة، أو التي تشترك في اسمها الإداري من عملية reverse geocoding.
لماذا تحتاج خريطة الفعاليات إلى بيانات منظمة؟
الخريطة المرئية تساعد البشر، لكن محركات البحث ومساعدي الذكاء الاصطناعي يقرأون البيانات المنظمة. توسيم كل فعالية بحقول schema.org Event، بما فيها اسم المكان وإحداثياته ووقت البدء، هو ما يجعل القائمة تظهر في الإجابات عن أسئلة مثل "ما الفعاليات في هذا الحي الليلة". الإحداثيات نفسها التي ترسمها على الخريطة تغذّي البيانات المنظمة، فيأتي الاكتشاف والعرض من مصدر واحد للحقيقة.

