איך יוצרים מאתר אינטראקטיבי לחיפוש חנויות בעזרת Places UI Kit

מטרה

במסמך הזה מוסבר איך לפתח אפליקציה אינטראקטיבית לחיפוש חנויות באמצעות הפלטפורמה של מפות Google, ובמיוחד באמצעות ממשק ה-API של JavaScript במפות Google וערכת ה-UI של מפות Google: רכיב פרטי המקום. במדריך הזה תלמדו איך ליצור מפה שבה מוצגים מיקומי החנויות, איך לעדכן באופן דינמי רשימה של חנויות גלויות ואיך להציג מידע עשיר על כל מקום.

דרישות מוקדמות

מומלץ להכיר את הנושאים הבאים:

מפעילים בפרויקט את Maps JavaScript API ואת Places UI Kit.

לפני שמתחילים, חשוב לוודא שטענתם את Maps JavaScript API וייבאתם את הספריות הנדרשות לסמנים מתקדמים ול-Places UI Kit. הנחת המוצא במסמך הזה היא שיש לכם ידע בסיסי בפיתוח אינטרנט, כולל HTML,‏ CSS ו-JavaScript.

הגדרה ראשונית

השלב הראשון הוא להוסיף מפה לדף. המפה הזו תשמש להצגת סיכות שקשורות למיקומי החנויות שלכם.

יש שתי דרכים להוסיף מפה לדף:

  1. שימוש ברכיב אינטרנט מסוג HTML‏ gmp-map
  2. באמצעות JavaScript

בוחרים את השיטה שמתאימה ביותר לתרחיש לדוגמה שלכם. שתי הדרכים להטמעת המפה יפעלו עם המדריך הזה.

הדגמה (דמו)

הדגמה הזו מציגה דוגמה לאיתור החנות הפיזית בפעולה, עם מיקומי המשרדים של Google באזור מפרץ סן פרנסיסקו. רכיב פרטי המקום מוצג לכל מיקום, לצד כמה מאפיינים לדוגמה.

טעינת מיקומי חנויות והצגתם

בקטע הזה נטען את נתוני החנות שלכם ונדגים אותם במפה. ההנחה במדריך הזה היא שיש לכם מאגר מידע על החנויות הקיימות שלכם שאפשר למשוך ממנו. נתוני החנות יכולים להגיע ממקורות שונים, כמו מסד הנתונים שלכם. בדוגמה הזו, נניח שיש קובץ JSON מקומי (stores.json) עם מערך של אובייקטים של חנויות, שכל אחד מהם מייצג מיקום של חנות אחת. כל אובייקט צריך לכלול לפחות את המאפיינים name,‏ location (עם lat ו-lng) ו-place_id.

אם עדיין אין לכם את מזהי המקומות של מיקומי החנויות, יש כמה דרכים לאחזר אותם. מידע נוסף זמין במסמכי התיעוד של מזהי המקומות.

דוגמה לרשומה של פרטי חנות בקובץ stores.json עשויה להיראות כך. יש שדות לשם, למיקום (קו הרוחב/קו האורך) ולמזהה המקום. יש אובייקט שמכיל את שעות הפתיחה של החנות (קטועות). יש גם שני ערכים בוליאניים שיעזרו לתאר מאפיינים ספציפיים של מיקום החנות.

{
  "name": "Example Store Alpha",
  "location": { "lat": 51.51, "lng": -0.12 },
  "place_id": "YOUR_STORE_PLACE_ID",
  "opening_hours": { "Monday": "09:00 - 17:00", "...": "..." },
  "new_store_design": true,
  "indoor_seating": false
}

בקוד ה-JavaScript, מאחזרים את הנתונים של מיקומי החנויות ומציגים סיכה במפה לכל אחד מהם.

דוגמה לאופן שבו עושים זאת מופיעה בהמשך. הפונקציה הזו מקבלת אובייקט שמכיל את הפרטים של החנויות ויוצרת סמן על סמך המיקום של כל אחת מהן.

function displayInitialMarkers(storeLocations) {
    if (!AdvancedMarkerElement || !LatLng || !mapElement) return;
    storeLocations.forEach(store => {
        if (store.location) {
            const marker = new AdvancedMarkerElement({
                position: new LatLng(store.location.lat, store.location.lng),
                title: store.name
            });
            mapElement.appendChild(marker);
        }
    });
}

אחרי שתעלו את החנויות שלכם והסיכות שמייצגות את המיקומים שלהן יופיעו במפה, תוכלו ליצור סרגל צד באמצעות HTML ו-CSS כדי להציג פרטים על החנויות השונות.

דוגמה לאופן שבו מאתר החנות עשוי להיראות בשלב הזה:

תמונה

האזנה לשינויים באזור התצוגה של המפה

כדי לשפר את הביצועים ואת חוויית המשתמש, כדאי לעדכן את האפליקציה כך שתציג סמנים ופרטים בסרגל הצד רק כשהמיקומים המתאימים שלהם נמצאים באזור המפה הגלוי (אזור התצוגה). כדי לעשות זאת, צריך להאזין לשינויים בחלון התצוגה של המפה, לבטל את ה-debouncing של האירועים האלה ואז לצייר מחדש רק את הסמנים הנחוצים.

מחברים פונקציית event listener לאירוע הסטטוס 'לא פעיל' של המפה. האירוע הזה מופעל אחרי שכל פעולות ההחלקה או השינוי של מרחק התצוגה מסתיימות, ומספק שדה תצוגה יציב לחישוב.

map.addListener('idle', debounce(updateMarkersInView, 300));

קטע הקוד שלמעלה מקשיב לאירוע idle וקורא לפונקציה debounce. שימוש בפונקציית ביטול הקשה מיותרת (debounce) מבטיח שהלוגיקה של עדכון הסמנים תפעל רק אחרי שהמשתמש יפסיק את האינטראקציה עם המפה למשך פרק זמן קצר, וכך משפרת את הביצועים.

function debounce(func, delay) {
    let timeoutId;
    return function(...args) {
        const context = this;
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            func.apply(context, args);
        }, delay);
    };
}

הקוד שלמעלה הוא דוגמה לפונקציית ביטול הקשה כפולה. הוא מקבל פונקציה וארגומנט של עיכוב, שאפשר לראות שהועברו למאזין במצב חוסר פעילות. עיכוב של 300 אלפיות השנייה מספיק כדי להמתין עד שהמפה תפסיק לזוז, בלי להוסיף עיכוב ניכר בממשק המשתמש. לאחר שתוקף הזמן הקצוב לתפוגה יפוג, המערכת תקרא לפונקציה שהועברה, במקרה הזה updateMarkersInView.

הפונקציה updateMarkersInView צריכה לבצע את הפעולות הבאות:

מחיקה של כל הסימנים הקיימים מהמפה

בודקים אם המיקום של החנות נמצא בתוך גבולות המפה הנוכחיים, לדוגמה:

if (map.getBounds().contains(storeLatLng)) {
  // logic
}

בתוך תנאי ה-if שלמעלה, כותבים קוד כדי להציג את הסמנים ולשמור את הפרטים בסרגל הצד, אם מיקום החנות נמצא בחלון התצוגה של המפה.

הצגת פרטים עשירים על מקום באמצעות הרכיב 'פרטי המקום'

בשלב הזה, האפליקציה מציגה את כל מיקומי החנויות, והמשתמשים יכולים לסנן אותם על סמך חלון התצוגה של המפה. כדי לשפר את המצב, מוסיפים פרטים עשירים על כל חנות, כמו תמונות, ביקורות ופרטי נגישות, באמצעות הרכיב 'פרטי המקום'. בדוגמה הזו נעשה שימוש ספציפי ברכיב המרוכז של פרטי המקום.

לכל מיקום של חנות במקור הנתונים צריך להיות מזהה מקום תואם. המזהה הזה מזהה את המיקום באופן ייחודי במפות Google והוא חיוני לאחזור הפרטים שלו. בדרך כלל, צריך לקבל את מזהי המקומות האלה מראש ולשמור אותם לכל רשומת חנות.

שילוב רכיב קומפקטי של פרטי מקום באפליקציה

כשנקבעת חנות שנמצאת בחלון התצוגה הנוכחי של המפה ונעשה רינדור שלה בסרגל הצד, אפשר ליצור ולשלב רכיב דחוס של פרטי המקום באופן דינמי.

בחנות הנוכחית שמעובדת, מאחזרים את מזהה המקום מהנתונים. מזהה המקום משמש לקביעת המקום שבו הרכיב יוצג.

ב-JavaScript, יוצרים באופן דינמי מכונה של PlaceDetailsCompactElement. נוצר גם PlaceDetailsPlaceRequestElement חדש, מזהה המקום מועבר אליו והוא מצורף ל-PlaceDetailsCompactElement. לסיום, משתמשים ב-PlaceContentConfigElement כדי להגדיר את התוכן שיוצג ברכיב.

הפונקציה הבאה מבוססת על ההנחה שספריות Place UI Kit הנדרשות מיובאות וזמינות בהיקף שבו הפונקציה הזו נקראת, ושהערך storeData שמוענק לפונקציה מכיל את הערך place_id.

הפונקציה הזו תחזיר את הרכיב, וקוד הקריאה יהיה אחראי להוספת הרכיב ל-DOM.

function createPlaceDetailsCompactElement(storeData) {
    // Create the main details component
    const detailsCompact = new PlaceDetailsCompactElement();
    detailsCompact.setAttribute('orientation', 'vertical'); // Or 'horizontal'

    // Specify the Place ID
    const placeRequest = new PlaceDetailsPlaceRequestElement();
    placeRequest.place = storeData.place_id;
    detailsCompact.appendChild(placeRequest);

    // Configure which content elements to display
    const contentConfig = new PlaceContentConfigElement();
    // For this example, we'll render media, rating, accessibility, and attribution:
    contentConfig.appendChild(new PlaceMediaElement({ lightboxPreferred: true }));
    contentConfig.appendChild(new PlaceRatingElement());
    contentConfig.appendChild(new PlaceAccessibleEntranceIconElement());
    // Configure attribution
    const placeAttribution = new PlaceAttributionElement();
    placeAttribution.setAttribute('light-scheme-color', 'gray');
    placeAttribution.setAttribute('dark-scheme-color', 'gray');
    contentConfig.appendChild(placeAttribution);
    detailsCompact.appendChild(contentConfig);
    // Return the element
    return detailsCompact;
}

בקוד לדוגמה שלמעלה, הרכיב מוגדר להציג את התמונות של המקום, את דירוג הביקורות ואת פרטי הנגישות. אפשר להתאים אישית את הרכיבים האלה על ידי הוספה או הסרה של רכיבי תוכן אחרים. במסמכי העזרה של PlaceContentConfigElement מפורטות כל האפשרויות הזמינות.

הרכיב המרוכז של פרטי המקום תומך בעיצוב באמצעות מאפייני CSS בהתאמה אישית. כך תוכלו להתאים את המראה שלו (צבעים, גופנים וכו') לעיצוב של האפליקציה. מחילים את המאפיינים המותאמים אישית האלה בקובץ ה-CSS. מאפייני ה-CSS הנתמכים מפורטים במסמכי העזרה של PlaceDetailsCompactElement.

דוגמה לאופן שבו הבקשה עשויה להיראות בשלב הזה:

תמונה

שיפור הכלי לאיתור חנויות

יצרתם בסיס יציב לאפליקציה למציאת חנויות. עכשיו נציג כמה דרכים להרחיב את הפונקציונליות של האתר וליצור חוויית משתמש עשירה יותר שממוקדת במשתמש.

הוספת השלמה אוטומטית

כדי לשפר את האופן שבו משתמשים מוצאים אזורים לחיפוש חנויות, אפשר לשלב קלט חיפוש עם השלמה אוטומטית של מקומות. כשמשתמשים מקלידים כתובת, שכונה או נקודת עניין ובוחרים הצעה, אפשר לתכנת את המפה כך שהיא תתמקד באופן אוטומטי במיקום הזה, ותגרום לעדכון של החנויות בסביבה. כדי לעשות זאת, מוסיפים שדה קלט ומצרפים אליו את הפונקציונליות של השלמה אוטומטית של מקומות. כשבוחרים הצעה, אפשר למרכז את המפה באותה נקודה. חשוב להגדיר אותו כך שיטה את התוצאות לאזור הפעילות שלכם או יגביל אותן לאזור הזה.

זיהוי המיקום

כדי להציע תוכן רלוונטי באופן מיידי, במיוחד למשתמשים בנייד, כדאי להטמיע פונקציונליות לזיהוי המיקום הגיאוגרפי הנוכחי שלהם. אחרי קבלת הרשאה מהדפדפן לזהות את המיקום שלהם, המפה תתמקם באופן אוטומטי במיקום שלהם ויוצגו החנויות הקרובות ביותר. משתמשים מעריכים מאוד את התכונה בסביבה כשהם מחפשים אפשרויות מיידיות. מוסיפים לחצן או הנחיה ראשונית לבקשת גישה למיקום.

הצגת המרחק והמסלול

אחרי שמשתמש מזהה חנות שמעניינת אותו, כדאי לשפר משמעותית את חוויית השימוש שלו על ידי שילוב של Routes API. לכל חנות שציינתם, תוכלו לחשב ולהציג את המרחק מהמיקום הנוכחי של המשתמש או מהמיקום שחיפש. בנוסף, צריך לספק לחצן או קישור שמשתמשים ב-Routes API כדי ליצור מסלול מהמיקום של המשתמש לחנות שנבחרה. לאחר מכן תוכלו להציג את המסלול הזה במפה או לקשר למפות Google לצורך ניווט, וכך ליצור מעבר חלק מחיפוש החנות ועד להגיע אליה בפועל.

הטמעת התוספים האלה מאפשרת לכם להשתמש ביכולות נוספות של פלטפורמת מפות Google כדי ליצור מאתר מקיף ונוח יותר לאיתור חנויות, שמתאים ישירות לצרכים הנפוצים של המשתמשים.

סיכום

במדריך הזה הראינו את השלבים המרכזיים ליצירת מאתר חנויות אינטראקטיבי. למדתם איך להציג את מיקומי החנויות שלכם במפה באמצעות Maps JavaScript API, איך לעדכן באופן דינמי את החנויות הגלומות על סמך שינויים בחלון התצוגה, ואיך להציג את נתוני החנות שלכם בהתאם ל-Places UI Kit. באמצעות פרטי החנות הקיימים, כולל מזהי המקומות, תוכלו להשתמש ברכיב 'פרטי המקום' כדי להציג פרטים עשירים וסטנדרטיים לכל אחד מהמיקומים שלכם, וכך ליצור בסיס חזק למאתר חנויות ידידותי למשתמש.

כדאי לנסות את Maps JavaScript API ואת Places UI Kit כדי להציע כלים חזקים שמבוססים על רכיבים לפיתוח מהיר של אפליקציות מתוחכמות מבוססות-מיקום. שילוב התכונות האלה יכול לעזור לכם ליצור חוויות מעניינות ומועילות למשתמשים.

תורמים

Henrik Valve | מהנדס DevX