אירועים

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

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

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

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

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

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

בדוגמה הבאה אפשר לראות אילו אירועים מופעלים על ידי ה-google.maps.Map כשאתם מבצעים פעולות במפה.

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

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

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

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

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

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

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

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

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

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

להצגת דוגמה (rectangle-event.html)

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

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

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

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

ניסיון של דוגמה

שימוש ב-Closures ב-Event Listeners

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

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

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

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

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 (Document Object Model) בדפדפן יוצר אירועים משלו ושולח אותם, בהתאם למודל האירועים הספציפי של הדפדפן שבו נעשה שימוש. אם רוצים לתעד את האירועים האלה ולהגיב להם, אפשר להשתמש ב-method הסטטי addDomListener() ב-Maps JavaScript API כדי להאזין לאירועי DOM ולקשור אליהם.

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

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

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

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

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

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

ניסיון של דוגמה

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

הסרת פונקציות מסוג Event Listener

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

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.

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

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