אירועים

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

הקוד הבא משלבת אירועי משתמש עם אירועי שינוי מצב. אנחנו מצרפים מטפל באירועים לסמן שמגדיל את התצוגה במפה כשלוחצים עליה. אנחנו גם מוסיפים למפה גורם 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. מכיוון ש-JavaScript API של מפות Google מפעיל את האירועים האחרונים באופן עצמאי, getBounds() לא ידווח על תוצאות מועילות עד שאזור התצוגה ישתנה באופן מהימן. אם רוצים getBounds() אחרי אירוע כזה, חשוב להאזין לאירוע bounds_changed במקום זאת.

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

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

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

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

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

אפשר לגשת לארגומנטים של האירוע מתוך event listener באותו אופן שבו ניגשים למאפיינים של אובייקט. הדוגמה הבאה מוסיפה רכיב 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();
להצגת דוגמה

כדאי לנסות דוגמה

שימוש בחסימות כבישים במאזינים לאירועים

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

הדוגמה הבאה משתמשת בסגירת פונקציה ב-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();
להצגת דוגמה

כדאי לנסות דוגמה

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

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

הערה: הגדרה מפורשת של מאפיין בתוך הגורם המטפל באירועים שמגיב לשינוי המצב של הנכס הספציפי, עלולה לגרום להתנהגות בלתי צפויה או לא רצויה. לדוגמה, הגדרה של מאפיין כזה תפעיל אירוע חדש, ואם תמיד מגדירים נכס ב-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

מודל האירועים של JavaScript ב-Maps 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 Level 2. (למידע נוסף על אירועים ברמת ה-DOM, אפשר לעיין במאמר רמות Mozilla DOM).

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>

    <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>
להצגת דוגמה

כדאי לנסות דוגמה

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

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

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

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 */ };