אירועים

בחירת פלטפורמה: Android iOS JavaScript

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

אירועים בממשק המשתמש

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

  • אירועי משתמש (כמו אירועי "לחיצה" בעכבר) מופצים מה-DOM ל-API JavaScript של מפות Google. האירועים האלה נפרדים מאירועי DOM רגילים.
  • התראות על שינויים במצב MVC משקפות שינויים באובייקטים של Maps JavaScript API, והשמות שלהן מבוססים על המוסכמה property_changed.

כל אובייקט JavaScript API של מפות Google מייצא מספר אירועים בעלי שם. תוכניות שמתעניינות באירועים מסוימים ירשמו פונקציות event listener של JavaScript לאירועים האלה ויפעילו קוד כשהאירועים האלה יתקבלו באמצעות קריאה ל-addListener() כדי לרשום גורמים מטפלים באירועים באובייקט.

הדוגמה הבאה מראה אילו אירועים מופעלים על ידי google.maps.Map בזמן האינטראקציה שלך עם המפה.

רשימה מלאה של האירועים זמינה בחומר העזר בנושא API של JavaScript ב-Maps. האירועים מפורטים בקטע נפרד עבור כל אובייקט שמכיל אירועים.

אירועים בממשק המשתמש

אובייקטים מסוימים ב-Maps JavaScript API נועדו להגיב לאירועי משתמש כמו אירועים של עכבר או מקלדת. לדוגמה, לפניכם חלק מאירועי המשתמש שאובייקט google.maps.marker.AdvancedMarkerElement יכול להאזין להם:

  • 'click'
  • 'drag'
  • 'dragend'
  • 'dragstart'
  • 'gmp-click'

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

שינויים במצב של MVC

אובייקטים מסוג MVC מכילים בדרך כלל מצב. בכל פעם שמאפיין של אובייקט משתנה, Maps JavaScript API יפעיל אירוע שהנכס השתנה. לדוגמה, ה-API יפעיל אירוע zoom_changed על מפה כשרמת המרחק מהתצוגה של המפה משתנה. אפשר ליירט את שינויי המצב האלה על ידי קריאה ל-addListener() כדי לרשום גורמים מטפלים באירועים גם באובייקט.

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

טיפול באירועים

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

דוגמה: אירועים במפה וסמן

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

TypeScript

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

  const myLatlng = { lat: -25.363, lng: 131.044 };

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: myLatlng,
      mapId: "DEMO_MAP_ID",
    }
  );

  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position as google.maps.LatLng);
    }, 3000);
  });

  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position as google.maps.LatLng);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const myLatlng = { lat: -25.363, lng: 131.044 };
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: myLatlng,
    mapId: "DEMO_MAP_ID",
  });
  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position);
    }, 3000);
  });
  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position);
  });
}

initMap();
להצגת דוגמה

רוצה לנסות את הדוגמה

טיפ: אם מנסים לזהות שינוי באזור התצוגה, יש להשתמש באירוע הספציפי של bounds_changed ולא באירועים הקודמים zoom_changed ו-center_changed. מכיוון ש-Maps JavaScript API מפעיל את האירועים האלה באופן עצמאי, יכול להיות שמערכת getBounds() לא תדווח על תוצאות מועילות עד שאזור התצוגה ישתנה באופן מהימן. אם ברצונך getBounds() אחרי אירוע כזה, צריך להאזין לאירוע של bounds_changed במקום זאת.

דוגמה: אירועים של עריכה וגרירה של צורה

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

לצפייה בדוגמה (rectangle-event.html)

גישה לארגומנטים באירועים בממשק המשתמש

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

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

TypeScript

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

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng: google.maps.LatLng, map: google.maps.Map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary(
    "marker",
  );
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng, map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();
להצגת דוגמה

רוצה לנסות את הדוגמה

שימוש בחסימות ב-Event Listener

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

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

TypeScript

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

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  const bounds: google.maps.LatLngBoundsLiteral = {
    north: -25.363882,
    south: -31.203405,
    east: 131.044922,
    west: 125.244141,
  };

  // Display the area between the location southWest and northEast.
  map.fitBounds(bounds);

  // Add 5 markers to map at random locations.
  // For each of these markers, give them a title with their index, and when
  // they are clicked they should open an infowindow with text from a secret
  // message.
  const secretMessages = ["This", "is", "the", "secret", "message"];
  const lngSpan = bounds.east - bounds.west;
  const latSpan = bounds.north - bounds.south;

  for (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
function attachSecretMessage(
  marker: google.maps.marker.AdvancedMarkerElement,
  secretMessage: string
) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });
  const bounds = {
    north: -25.363882,
    south: -31.203405,
    east: 131.044922,
    west: 125.244141,
  };

  // Display the area between the location southWest and northEast.
  map.fitBounds(bounds);

  // Add 5 markers to map at random locations.
  // For each of these markers, give them a title with their index, and when
  // they are clicked they should open an infowindow with text from a secret
  // message.
  const secretMessages = ["This", "is", "the", "secret", "message"];
  const lngSpan = bounds.east - bounds.west;
  const latSpan = bounds.north - bounds.south;

  for (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
function attachSecretMessage(marker, secretMessage) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();
להצגת דוגמה

רוצה לנסות את הדוגמה

קבלה והגדרה של מאפיינים ב'מטפלי אירועים'

אף אחד מאירועי השינוי במצב ה-MVC במערכת האירועים של Maps JavaScript API לא מעביר ארגומנטים כשהאירוע מופעל. (אירועי משתמש מעבירים ארגומנטים שאפשר לבדוק). אם צריך לבדוק מאפיין בשינוי של מצב MVC, צריך לבצע קריאה מפורשת ל-method getProperty() המתאימה באובייקט הזה. הבדיקה הזו תמיד תאחזר את המצב הנוכחי של אובייקט ה-MVC, שעשוי להיות לא המצב כשהאירוע הופעל לראשונה.

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

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

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: originalMapCenter,
    }
  );

  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);

  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom()!);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: originalMapCenter,
  });
  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);
  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom());
  });
}

initMap();
להצגת דוגמה

רוצה לנסות את הדוגמה

האזנה לאירועי DOM

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

לשיטת נוחות זו יש חתימה כפי שמוצג בהמשך:

addDomListener(instance:Object, eventName:string, handler:Function)

instance יכול להיות כל רכיב DOM שנתמך על ידי הדפדפן, כולל:

  • חברים היררכיים ב-DOM, כמו window או document.body.myform
  • רכיבים בעלי שם כמו document.getElementById("foo")

חשוב לשים לב ש-addDomListener() מעביר את האירוע שצוין לדפדפן, שמטפל בו בהתאם למודל אירועי ה-DOM של הדפדפן. עם זאת, כמעט כל הדפדפנים המודרניים תומכים לפחות ברמת DOM 2. (למידע נוסף על אירועים ברמת DOM, ראו Mozilla DOM Levels).

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const mapDiv = document.getElementById("map") as HTMLElement;
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const mapDiv = document.getElementById("map");
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

HTML

<html>
  <head>
    <title>Listening to DOM Events</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>
להצגת דוגמה

רוצה לנסות את הדוגמה

הקוד שלמעלה הוא קוד של Maps JavaScript API, אבל השיטה addDomListener() מקשרת לאובייקט window של הדפדפן ומאפשרת ל-API לתקשר עם אובייקטים מחוץ לדומיין הרגיל של ה-API.

הסרה של פונקציות event listener

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

var listener1 = marker.addListener('click', aFunction);

google.maps.event.removeListener(listener1);

כדי להסיר את כל המאזינים ממכונה מסוימת, צריך לקרוא לפונקציה clearInstanceListeners() ולהעביר את שם המכונה.

var listener1 = marker.addListener('click', aFunction);
var listener2 = marker.addListener('mouseover', bFunction);

// Remove listener1 and listener2 from marker instance.
google.maps.event.clearInstanceListeners(marker);

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

marker.addListener('click', aFunction);
marker.addListener('click', bFunction);
marker.addListener('click', cFunction);

// Remove all click listeners from marker instance.
google.maps.event.clearListeners(marker, 'click');

מידע נוסף זמין במסמכי התיעוד של מרחב השמות של google.maps.event.

האזנה לשגיאות אימות

אם רוצים לזהות באופן פרוגרמטי כשל באימות (למשל, לשלוח איתות Bluetooth באופן אוטומטי), אפשר להכין פונקציית קריאה חוזרת. אם הפונקציה הגלובלית הבאה מוגדרת, היא תיקרא כשהאימות ייכשל. function gm_authFailure() { /* Code */ };