איך מגדירים סמנים שניתן ללחוץ עליהם ונגישים

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

  • כשסמן ניתן ללחיצה (או לגרירה), הוא יכול להגיב לקלט מהמקלדת ומהעכבר.
  • קוראי מסך יכולים לקרוא את הטקסט שצוין באפשרות title, והוא יוצג כשמשתמש יחזיק את מצביע העכבר מעל הסמן.
  • הגדלת הגודל של הסמנים מפחיתה את רמת הדיוק הנדרשת כדי ליצור אינטראקציה עם הסמן בכל המכשירים – במיוחד במכשירים עם מסך מגע – ומשפרת את הנגישות. גודל ברירת המחדל של הסמנים עומד בתקן WCAG AA לגודל מינימלי, אבל מפתחים שרוצים לעמוד בתקן WCAG AAA לגודל יעד צריכים להגדיל את גודל הסמנים.

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

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

כדי לנווט בין הסמנים באמצעות המקלדת:

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

איך יוצרים סמן שאפשר ללחוץ עליו

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

  • מגדירים את המאפיין gmpClickable לערך true.

TypeScript

const marker = new AdvancedMarkerElement({
    position,
    map,
    title: `${i + 1}. ${title}`,
    content: pin.element,
    gmpClickable: true,
});

JavaScript

const marker = new AdvancedMarkerElement({
    position,
    map,
    title: `${i + 1}. ${title}`,
    content: pin.element,
    gmpClickable: true,
});

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

TypeScript

// Add a click listener for each marker, and set up the info window.
marker.addListener('click', ({ domEvent, latLng }) => {
    const { target } = domEvent;
    infoWindow.close();
    infoWindow.setContent(marker.title);
    infoWindow.open(marker.map, marker);
});

JavaScript

// Add a click listener for each marker, and set up the info window.
marker.addListener('click', ({ domEvent, latLng }) => {
    const { target } = domEvent;
    infoWindow.close();
    infoWindow.setContent(marker.title);
    infoWindow.open(marker.map, marker);
});

  • כדי להפוך סמן ללא ניתן ללחיצה שוב, קוראים ל-removeListener כדי להסיר את מאזין אירועי הלחיצה:

    // Remove the listener.
    google.maps.event.removeListener(clickListener);
    

כדי לשפר עוד יותר את הנגישות:

  • מגדירים טקסט תיאורי לסמן באמצעות האפשרות AdvancedMarkerElement.title.
  • כדי להגדיל את גודל הסמן, משתמשים במאפיין scale של PinElement.

קוד לדוגמה מלא

הצגת קוד המקור המלא לדוגמה

TypeScript

async function initMap() {
    // Request needed libraries.
    const { Map, InfoWindow } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
    const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

    const map = new Map(document.getElementById("map") as HTMLElement, {
        zoom: 12,
        center: { lat: 34.84555, lng: -111.8035 },
        mapId: '4504f8b37365c3d0',
    });

    // Set LatLng and title text for the markers. The first marker (Boynton Pass)
    // receives the initial focus when tab is pressed. Use arrow keys to move
    // between markers; press tab again to cycle through the map controls.
    const tourStops = [
        {
            position: { lat: 34.8791806, lng: -111.8265049 }, 
            title: "Boynton Pass"
        },
        {
            position: { lat: 34.8559195, lng: -111.7988186 }, 
            title: "Airport Mesa"
        },
        {
            position: { lat: 34.832149, lng: -111.7695277 }, 
            title: "Chapel of the Holy Cross"
        },
        {
            position: { lat: 34.823736, lng: -111.8001857 }, 
            title: "Red Rock Crossing"
        },
        {
            position: { lat: 34.800326, lng: -111.7665047 }, 
            title: "Bell Rock"
        },
    ];

    // Create an info window to share between markers.
    const infoWindow = new InfoWindow();

    // Create the markers.
    tourStops.forEach(({position, title}, i) => {
        const pin = new PinElement({
            glyph: `${i + 1}`,
            scale: 1.5,
        });
        const marker = new AdvancedMarkerElement({
            position,
            map,
            title: `${i + 1}. ${title}`,
            content: pin.element,
            gmpClickable: true,
        });
        // Add a click listener for each marker, and set up the info window.
        marker.addListener('click', ({ domEvent, latLng }) => {
            const { target } = domEvent;
            infoWindow.close();
            infoWindow.setContent(marker.title);
            infoWindow.open(marker.map, marker);
        });
    });
}

initMap();

JavaScript

async function initMap() {
    // Request needed libraries.
    const { Map, InfoWindow } = await google.maps.importLibrary("maps");
    const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker");
    const map = new Map(document.getElementById("map"), {
        zoom: 12,
        center: { lat: 34.84555, lng: -111.8035 },
        mapId: '4504f8b37365c3d0',
    });
    // Set LatLng and title text for the markers. The first marker (Boynton Pass)
    // receives the initial focus when tab is pressed. Use arrow keys to move
    // between markers; press tab again to cycle through the map controls.
    const tourStops = [
        {
            position: { lat: 34.8791806, lng: -111.8265049 },
            title: "Boynton Pass"
        },
        {
            position: { lat: 34.8559195, lng: -111.7988186 },
            title: "Airport Mesa"
        },
        {
            position: { lat: 34.832149, lng: -111.7695277 },
            title: "Chapel of the Holy Cross"
        },
        {
            position: { lat: 34.823736, lng: -111.8001857 },
            title: "Red Rock Crossing"
        },
        {
            position: { lat: 34.800326, lng: -111.7665047 },
            title: "Bell Rock"
        },
    ];
    // Create an info window to share between markers.
    const infoWindow = new InfoWindow();
    // Create the markers.
    tourStops.forEach(({ position, title }, i) => {
        const pin = new PinElement({
            glyph: `${i + 1}`,
            scale: 1.5,
        });
        const marker = new AdvancedMarkerElement({
            position,
            map,
            title: `${i + 1}. ${title}`,
            content: pin.element,
            gmpClickable: true,
        });
        // Add a click listener for each marker, and set up the info window.
        marker.addListener('click', ({ domEvent, latLng }) => {
            const { target } = domEvent;
            infoWindow.close();
            infoWindow.setContent(marker.title);
            infoWindow.open(marker.map, marker);
        });
    });
}
initMap();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

HTML

<html>
  <head>
    <title>Advanced Marker Accessibility</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "beta"});</script>
  </body>
</html>

לניסיון