استكشاف الأماكن باستخدام عنصر البحث عن الأماكن وMaps JavaScript API

الهدف

تعرَّف على كيفية دمج عنصر "البحث عن الأماكن" مع "خرائط Google" لمساعدة المستخدمين في العثور على أماكن باستخدام البحث عن الأماكن القريبة أو البحث النصي، ما يعزّز قدرتهم على استكشاف نقاط الاهتمام. استخدِم "العنصر المضغوط لتفاصيل المكان" لتقديم المزيد من التفاصيل حول الأماكن التي تظهر في تطبيقك.

ما هو "عنصر البحث عن الأماكن"؟

عنصر "البحث عن الأماكن" هو جزء من حزمة أدوات واجهة المستخدم الخاصة بخدمة "أماكن" في Maps JavaScript API. وهي عنصر HTML يعرض نتائج البحث عن مكان مباشرةً بتنسيق قائمة ضمن تطبيقك. يبسّط هذا العنصر عملية عرض الأماكن التي تم العثور عليها باستخدام "البحث القريب" أو "البحث النصي"، ما يوفّر تجربة سلسة للمستخدمين في ما يتعلّق باستكشاف الأماكن. عندما يختار المستخدم مكانًا من القائمة، يمكنك عرض تفاصيله على الخريطة، وغالبًا ما يتم ذلك باستخدام "نافذة المعلومات" و"عنصر تفاصيل المكان".

عرض مرئي لاكتشاف الأماكن

تعرض الصورة التالية مثالاً على "عنصر البحث عن الأماكن" أثناء العمل. على اليمين، تظهر قائمة بالمطاعم (عنصر "البحث عن مكان"). عند اختيار مطعم، تظهر تفاصيله في نافذة معلومات على الخريطة، ويتم توسيط الخريطة على موقعه الجغرافي.

الصورة

حالات استخدام ميزة "اقتراحات"

يمكن أن يؤدي دمج عنصر "البحث عن الأماكن" إلى تحسين تطبيقات مختلفة في مجالات متنوعة، مثل:

  • السفر والسياحة: تتيح للسياح البحث عن أماكن جذب أو فنادق أو أنواع معيّنة من المأكولات في منطقة معيّنة.
  • العقارات: يمكنك السماح للمشترين أو المستأجرين المحتملين بالعثور على المدارس أو محلات السوبرماركت أو خيارات النقل العام القريبة.
  • الخدمات اللوجستية: مساعدة السائقين في العثور على محطات شحن المركبات الكهربائية أو محطات الوقود أو مراكز الصيانة المحدّدة

سير عمل الحلّ: تنفيذ ميزة "اقتراحات"

يرشدك هذا القسم إلى خطوات دمج عنصر "البحث عن الأماكن" لاستكشاف الأماكن على الخريطة، بما في ذلك مقتطفات الرموز البرمجية للتفاعل مع Places UI Kit. سنتناول عملية تهيئة الخريطة وتنفيذ وظيفتَي "البحث القريب" و"البحث النصي". أخيرًا، سنستخدم عنصر Place Details لعرض المزيد من التفاصيل حول مكان معيّن عند النقر على الدبوس الخاص به على الخريطة.

المتطلبات الأساسية

ننصحك بالاطّلاع على المستندات التالية:

فعِّل Maps JavaScript API وPlaces UI Kit في مشروعك.

قبل البدء، تأكَّد من تحميل Maps JavaScript API واستيراد المكتبات المطلوبة. يفترض هذا المستند أيضًا توفّر معرفة عملية بتطوير الويب، بما في ذلك HTML وCSS وJavaScript.

إضافة خريطة إلى الصفحة

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

هناك طريقتان لإضافة خريطة إلى صفحة:

  1. استخدام gmp-map مكوّن ويب HTML
  2. استخدام JavaScript

تم إنشاء مقتطفات الرموز البرمجية في هذه الصفحة باستخدام خريطة JavaScript.

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

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

الصورة

تتوسّط الخريطة مدينة سان فرانسيسكو، ويظهر دبوس أزرق للإشارة إلى المكان الذي نبحث عنه في المنطقة المجاورة. تم تخصيص لون الدبوس باستخدام PinElement. تم إخفاء عنصر التحكّم في نوع الخريطة من واجهة المستخدِم.

إعداد "عنصر البحث عن الأماكن"

يمكننا الآن إعداد HTML وCSS لعرض "عنصر البحث عن الأماكن". في هذا المثال، سنضع العنصر فوق الجانب الأيسر من الخريطة، ولكن يُنصح بتجربة تنسيقات مختلفة لتناسب تطبيقك.

يستخدم عنصر "بحث الأماكن" أسلوبًا تصريحيًا. بدلاً من ضبطها بالكامل في JavaScript، يمكنك تحديد نوع البحث مباشرةً في HTML من خلال تضمين عنصر طلب، مثل <gmp-place-nearby-search-request>، داخل المكوّن الرئيسي <gmp-place-search>.

ضِمن رمز HTML، ابدأ العنصر <gmp-place-search>. استخدِم السمة selectable لتفعيل أحداث النقر على النتائج. داخلها، أضِف <gmp-place-nearby-search-request> لتحديد أنّ هذا العنصر سيُستخدَم في البحث عن الأجهزة المجاورة.

<gmp-place-search selectable>
  <gmp-place-nearby-search-request>
  </gmp-place-nearby-search-request>
</gmp-place-search>

لإجراء بحث أولي وعرض النتائج، سنستخدم JavaScript للحصول على مرجع لعنصر الطلب المتداخل وضبط خصائصه. ابدأ دائرة لاستخدامها كـ locationRestriction، باستخدام موضع العلامة من الخطوة السابقة كنقطة مركزية. بعد ذلك، اضبط السمتَين locationRestriction وincludedPrimaryTypes في عنصر الطلب لتشغيل البحث.

في ما يلي مقتطف الرمز البرمجي الخاص بذلك:

// Get references to the Place Search and its nested request element
const placeSearchElement = document.querySelector("gmp-place-search");
const placeSearchRequestElement = document.querySelector("gmp-place-nearby-search-request");

// Define the location restriction for the search
const circleRestriction = new Circle({
    center: marker.position,
    radius: 500
});

// Set the properties on the request element to perform an initial search for restaurants.
placeSearchRequestElement.locationRestriction = circleRestriction;
placeSearchRequestElement.includedPrimaryTypes = ['restaurant'];

في ما يلي مثال على الشكل الذي يمكن أن يبدو عليه التطبيق في هذه المرحلة:

الصورة

يتيح "عنصر البحث عن الأماكن" خيارَي بحث:

هذه هي العناصر المتداخلة داخل <gmp-place-search>. بعد ذلك، يمكنك بدء عمليات البحث من خلال ضبط سمات عنصر الطلب المتداخل باستخدام JavaScript.

يوضّح هذا القسم كيفية تنفيذ الطريقتَين.

الصورة

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

ننصحك باختيار مجموعة فرعية من الأنواع ذات الصلة بحالة الاستخدام. على سبيل المثال، إذا كنت بصدد تطوير تطبيق لعرض الأماكن القريبة من فندق للسياح، يمكنك اختيار: bakery وcoffee_shop وmuseum وrestaurant وtourist_attraction.

يجب أن يتضمّن رمز HTML العنصر <gmp-place-search> مع العنصر <gmp-place-nearby-search-request> المضمّن فيه.

<gmp-place-search selectable>
  <gmp-place-nearby-search-request>
  </gmp-place-nearby-search-request>
</gmp-place-search>

بعد ذلك، أنشئ أداة معالجة JavaScript للحدث change في أداة اختيار نوع المكان. سيستدعي هذا المعالج دالة تعدّل خصائص العنصر <gmp-place-nearby-search-request>، ما يؤدي تلقائيًا إلى بدء عملية بحث جديدة وتعديل القائمة.

// Get a reference to the nested request element
const placeSearchRequestElement = document.querySelector('gmp-place-nearby-search-request');

// Function to update the place search based on the selected type
function updatePlaceList() {
    const selectedType = placeTypeSelect.value;
    if (!selectedType) {
        // If no type is selected, don't perform a search.
        // You could optionally hide the list or clear previous results here.
        placeSearchElement.style.display = 'none';
        return;
    }
    placeSearchElement.style.display = 'block';

    // Set properties on the request element to trigger a new search
    placeSearchRequestElement.locationRestriction = searchCircle;
    placeSearchRequestElement.maxResultCount = 8;
    placeSearchRequestElement.includedPrimaryTypes = [selectedType];
}

يتم استخدام searchCircle نفسه من خطوة الإعداد في locationRestriction. تم ضبط السمة includedPrimaryTypes على القيمة المحدّدة من قِبل المستخدم. يتم أيضًا ضبط maxResultCount اختياريًا للحدّ من عدد النتائج.

الصورة

لتفعيل البحث النصي، يجب تغيير إعدادات HTML. بدلاً من طلب البحث عن الأجهزة القريبة، يمكنك تضمين عنصر <gmp-place-text-search-request>.

<gmp-place-search selectable>
  <gmp-place-text-search-request>
  </gmp-place-text-search-request>
</gmp-place-search>

أضِف إدخالاً نصيًا وزر بحث إلى واجهة المستخدم. أنشئ أداة معالجة JavaScript لحدث click الخاص بالزر. سيتلقّى معالج الأحداث إدخال المستخدم ويعدّل خصائص العنصر <gmp-place-text-search-request> لتنفيذ البحث.

// Get a reference to the text search request element
const placeTextSearchRequestElement = document.querySelector('gmp-place-text-search-request');
const textSearchInput = document.getElementById('textSearchInput');
const textSearchButton = document.getElementById('textSearchButton');

textSearchButton.addEventListener('click', performTextSearch);

function performTextSearch() {
    const query = textSearchInput.value.trim();
    if (!query) {
        console.log("Search query is empty.");
        return;
    }
    // Set properties on the request element to trigger a new search
    placeTextSearchRequestElement.textQuery = query;
    placeTextSearchRequestElement.locationBias = map.getBounds();
    placeTextSearchRequestElement.maxResultCount = 8;
}

في هذا المثال، نضبط السمة textQuery باستخدام الإدخال الذي يقدّمه المستخدم. نوفّر أيضًا locationBias باستخدام حدود الخريطة الحالية، ما يطلب من واجهة برمجة التطبيقات تفضيل النتائج ضمن تلك المنطقة بدون حصرها بشكل صارم. يحدّ maxResultCount اختياري من عدد النتائج المعروضة.

عرض دبابيس الأماكن وتفاصيلها

يمكن للتطبيق الآن إجراء بحث عن مكان وتعبئة العنصر. في الخطوة التالية، سنحسّن وظائفها من خلال:

  • عرض دبابيس على الخريطة لكل مكان تم ملؤه في عنصر &quot;بحث الأماكن&quot;
  • السماح للمستخدم بالنقر على دبوس أو على المكان ضمن عنصر "بحث الأماكن" لعرض المزيد من التفاصيل حول هذا المكان

ويظل مبدأ هذه الخطوة كما هو سواء كان التطبيق يستخدم البحث القريب أو البحث النصي.

أولاً، أضِف متغيّرًا عامًا إلى رمز JavaScript لتخزين عناصر نائب عن موضع الإعلان. سيسمح لك ذلك بإزالتها عند تغيير البحث والتعامل مع أحداث النقر.

let markers = {};

أنشئ دالة لإضافة علامات إلى الخريطة. سيتم استدعاء هذه الدالة عند تحميل نتائج بحث جديدة. سيؤدي ذلك إلى:

  • أزِل أي علامات أماكن حالية من الخريطة.
  • كرِّر النتائج من &quot;عنصر البحث عن الأماكن&quot; وأضِف علامة لكل نتيجة.
  • اضبط حدود الخريطة لتظهر جميع العلامات الجديدة.

للاستماع إلى وقت توفّر نتائج البحث، أضِف أداة معالجة الأحداث gmp-load إلى العنصر <gmp-place-search>. يتم تنشيط هذا الحدث بعد اكتمال البحث وعرض النتائج.

سنضيف أداة معالجة الأحداث داخل دالة البحث (مثلاً، updatePlaceList)، واستخدِم الخيار { once: true } للتأكّد من أنّه يتم تفعيله فقط لنتائج البحث الحالي.

// In your search function, after setting the request properties:
placeSearchElement.addEventListener('gmp-load', addMarkers, { once: true });

تبدو الدالة addMarkers على النحو التالي:

async function addMarkers() {
    const { LatLngBounds } = await google.maps.importLibrary("core");
    const bounds = new LatLngBounds();

    if (placeSearchElement.places.length > 0) {
        // Remove existing markers
        for (const m in markers) {
            markers[m].map = null;
        }
        markers = {};

        // Loop through each place from the search results
        // and add a marker for each one.
        for (const place of placeSearchElement.places) {
            const marker = new google.maps.marker.AdvancedMarkerElement({
                map: map,
                position: place.location,
            });

            markers[place.id] = marker;
            bounds.extend(place.location);
            marker.collisionBehavior = google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL;

            // Add a click listener for each marker.
            marker.addListener('gmp-click', (event) => {
                // The main logic for showing details will go here.
            });
        }
        // Position the map to display all markers.
        map.setCenter(bounds.getCenter());
        map.fitBounds(bounds);
    }
}

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

الصورة

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

أضِف رمز HTML الخاص بالعنصر المضغوط لتفاصيل المكان إلى الرمز، على سبيل المثال:

<gmp-place-details-compact orientation="vertical" style="display: none;">
    <gmp-place-all-content></gmp-place-all-content>
    <gmp-place-attribution light-scheme-color="gray" dark-scheme-color="white"></gmp-place-attribution>
</gmp-place-details-compact>

تم ضبط style على display: none، ولن يظهر إلا عند الحاجة إليه. يتم تمرير gmp-place-all-content لعرض كل محتوى العنصر. لاختيار المحتوى الذي سيتم عرضه، راجِع مستندات عنصر "تفاصيل المكان" المضغوط.

أنشئ متغيّرًا عامًا في JavaScript للاحتفاظ بمرجع إلى العنصر المضغوط الخاص بـ "تفاصيل المكان"، واملأ هذا المتغيّر في رمز التهيئة، على سبيل المثال:

let placeDetailsElement;
...
placeDetailsElement = document.querySelector('gmp-place-details-compact');

ضمن الدالة addMarkers، أضِف أداة معالجة الأحداث gmp-click إلى كل علامة، واضبط "العنصر المضغوط لتفاصيل المكان" لعرض تفاصيل المكان من خلال تمرير رقم تعريف المكان الخاص بالعلامة الحالية.

بعد الانتهاء من ذلك، يتم فتح نافذة معلومات لعرض "العنصر الصغير لتفاصيل المكان"، والذي يتم تثبيته على العلامة.

أخيرًا، يتم ضبط موضع الخريطة على إطار العرض الخاص بالمكان المحدّد، ما يجعله مرئيًا.

async function addMarkers() {
          ...
            marker.addListener('gmp-click', (event) => {
                //Set up Place Details Compact Widget
                placeDetailsElement.style.display = "block";
                // Remove any existing place request element
                const existingPlaceRequest = placeDetailsElement.querySelector('gmp-place-details-place-request');
                if (existingPlaceRequest) {
                    existingPlaceRequest.remove();
                }
                // Create and configure the new place request element
                const placeRequestElement = new google.maps.places.PlaceDetailsPlaceRequestElement({ place: place.id });
                // Prepend the new place request element to the main widget
                placeDetailsElement.prepend(placeRequestElement);
                if (infoWindow.isOpen) {
                    infoWindow.close();
                }
                infoWindow.setOptions({
                    content: placeDetailsElement
                });
                infoWindow.open({
                    anchor: marker,
                    map: map
                });
                // Position the map to show the selected place
                placeDetailsElement.addEventListener('gmp-load', () => {
                    map.fitBounds(place.viewport, { top: 500, left: 400 });
                });
            });
          ...
        });
    }
}

للسماح للمستخدم بالنقر على مكان في "عنصر قائمة الأماكن" لعرض "عنصر تفاصيل المكان المختصر"، أضِف ما يلي إلى رمز JavaScript بعد طلب configureFromSearchNearbyRequest.

placeSearchElement.addEventListener("gmp-select", ({ place }) => {
    if (markers[place.id]) {
        markers[place.id].click();
    }
});

بعد إكمال هذه الخطوة، سيتمكّن التطبيق من استخدام إما Nearby Search أو Text Search لملء عنصر قائمة الأماكن. ستعرض نتائج هذا الطلب دبابيس على الخريطة، وعند النقر على دبوس أو مكان في عنصر &quot;قائمة الأماكن&quot;، سيتم عرض &quot;نافذة معلومات&quot; تتضمّن تفاصيل المكان، والتي يوفّرها عنصر &quot;تفاصيل المكان&quot; المضغوط.

سيبدو التطبيق على النحو التالي:

الصورة

الخاتمة

يوفّر عنصر "البحث عن الأماكن" مع عنصر "تفاصيل المكان" المضغوط طريقة مبسطة لإضافة ميزات غنية لاكتشاف الأماكن إلى تطبيقاتك على Google Maps Platform.

جرِّب Places UI Kit اليوم لمساعدة المستخدمين في العثور على الأماكن واستكشافها باستخدام عمليات البحث النصية وعمليات البحث عن الأماكن القريبة، وعرض تفاصيل غنية عن الأماكن، ما يعزّز تفاعلهم مع حالات استخدام استكشاف الأماكن.

المساهمون

هنريك فالف | مهندس DevX