マウスイベントを処理する

プラットフォームを選択: Android iOS JavaScript

概要

mousemoveclick イベントに反応する地図のレイヤを作成し、それを使用してクリックされた領域に関する情報を返します。プレイス ID、表示名、対象物タイプなどがこの情報に該当します。次のサンプルの地図には、行政区域レベル 2 の境界線が表示されています。また、ユーザー操作に応じてポリゴンのスタイルを設定するイベント処理コードも含まれています(mousemove によって境界線の太さが変わり、click によって背景色が暗くなって情報ウィンドウが表示されます)。

地図のレイヤのイベントを有効にする

地図のレイヤ上のイベントを有効にする手順は次のとおりです。

  1. 登録するイベントごとに地図のレイヤで addListener() 関数を呼び出して、イベント通知用の地図のレイヤを登録します。この例では、地図にはリスナーも設定されています。

    TypeScript

    // Add the feature layer.
    //@ts-ignore
    featureLayer = map.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');
    
    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);
    
    // Map event listener.
    map.addListener('mousemove', () => {
      // If the map gets a mousemove, that means there are no feature layers
      // with listeners registered under the mouse, so we clear the last
      // interacted feature ids.
      if (lastInteractedFeatureIds?.length) {
        lastInteractedFeatureIds = [];
        featureLayer.style = applyStyle;
      }
    });

    JavaScript

    // Add the feature layer.
    //@ts-ignore
    featureLayer = map.getFeatureLayer("ADMINISTRATIVE_AREA_LEVEL_2");
    // Add the event listeners for the feature layer.
    featureLayer.addListener("click", handleClick);
    featureLayer.addListener("mousemove", handleMouseMove);
    // Map event listener.
    map.addListener("mousemove", () => {
      // If the map gets a mousemove, that means there are no feature layers
      // with listeners registered under the mouse, so we clear the last
      // interacted feature ids.
      if (lastInteractedFeatureIds?.length) {
        lastInteractedFeatureIds = [];
        featureLayer.style = applyStyle;
      }
    });

  2. イベント ハンドラのコードを追加して、インタラクションの種類に基づいて選択した対象物のスタイルを設定します。

    TypeScript

    function handleClick(/* MouseEvent */ e) {
      lastClickedFeatureIds = e.features.map(f => f.placeId);
      lastInteractedFeatureIds = [];
      featureLayer.style = applyStyle;
      createInfoWindow(e);
    }
    
    function handleMouseMove(/* MouseEvent */ e) {
      lastInteractedFeatureIds = e.features.map(f => f.placeId);
      featureLayer.style = applyStyle;
    }

    JavaScript

    function handleClick(/* MouseEvent */ e) {
      lastClickedFeatureIds = e.features.map((f) => f.placeId);
      lastInteractedFeatureIds = [];
      featureLayer.style = applyStyle;
      createInfoWindow(e);
    }
    
    function handleMouseMove(/* MouseEvent */ e) {
      lastInteractedFeatureIds = e.features.map((f) => f.placeId);
      featureLayer.style = applyStyle;
    }
    

  3. スタイルを適用するには、対象物スタイル関数を使用します。ここで示す対象物スタイル関数は、インタラクションの種類に基づいて条件付きでスタイルを適用します。ここでは、mousemove 時に境界線を太字にするスタイル、click 時に背景を変更して情報ウィンドウを表示するスタイル、既定のスタイルの 3 つのスタイルが定義されています。

    TypeScript

    // Define styles.
    // Stroke and fill with minimum opacity value.
    const styleDefault = {
      strokeColor: '#810FCB',
      strokeOpacity: 1.0,
      strokeWeight: 2.0,
      fillColor: 'white',
      fillOpacity: 0.1,  // Polygons must be visible to receive events.
    };
    // Style for the clicked polygon.
    const styleClicked = {
      ...styleDefault,
      fillColor: '#810FCB',
      fillOpacity: 0.5,
    };
    // Style for polygon on mouse move.
    const styleMouseMove = {
      ...styleDefault,
      strokeWeight: 4.0,
    };
    
    // Apply styles using a feature style function.
    function applyStyle(/* FeatureStyleFunctionOptions */ params) {
      const placeId = params.feature.placeId;
      //@ts-ignore
      if (lastClickedFeatureIds.includes(placeId)) {
        return styleClicked;
      }
      //@ts-ignore
      if (lastInteractedFeatureIds.includes(placeId)) {
        return styleMouseMove;
      }
      return styleDefault;
    }

    JavaScript

    // Define styles.
    // Stroke and fill with minimum opacity value.
    const styleDefault = {
      strokeColor: "#810FCB",
      strokeOpacity: 1.0,
      strokeWeight: 2.0,
      fillColor: "white",
      fillOpacity: 0.1, // Polygons must be visible to receive events.
    };
    // Style for the clicked polygon.
    const styleClicked = {
      ...styleDefault,
      fillColor: "#810FCB",
      fillOpacity: 0.5,
    };
    // Style for polygon on mouse move.
    const styleMouseMove = {
      ...styleDefault,
      strokeWeight: 4.0,
    };
    
    // Apply styles using a feature style function.
    function applyStyle(/* FeatureStyleFunctionOptions */ params) {
      const placeId = params.feature.placeId;
    
      //@ts-ignore
      if (lastClickedFeatureIds.includes(placeId)) {
        return styleClicked;
      }
    
      //@ts-ignore
      if (lastInteractedFeatureIds.includes(placeId)) {
        return styleMouseMove;
      }
      return styleDefault;
    }
    

コードサンプルの全文

TypeScript

let map: google.maps.Map;
let featureLayer;
let infoWindow;
let lastInteractedFeatureIds = [];
let lastClickedFeatureIds = [];

function handleClick(/* MouseEvent */ e) {
  lastClickedFeatureIds = e.features.map(f => f.placeId);
  lastInteractedFeatureIds = [];
  featureLayer.style = applyStyle;
  createInfoWindow(e);
}

function handleMouseMove(/* MouseEvent */ e) {
  lastInteractedFeatureIds = e.features.map(f => f.placeId);
  featureLayer.style = applyStyle;
}

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

  map = new Map(document.getElementById('map') as HTMLElement, {
    center: {lat: 39.23, lng: -105.73},
    zoom: 8,
    // In the cloud console, configure your Map ID with a style that enables the
    // 'Administrative Area Level 2' Data Driven Styling type.
    mapId: 'a3efe1c035bad51b', // Substitute your own map ID.
    mapTypeControl: false,
  });

  // Add the feature layer.
  //@ts-ignore
  featureLayer = map.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');

  // Add the event listeners for the feature layer.
  featureLayer.addListener('click', handleClick);
  featureLayer.addListener('mousemove', handleMouseMove);

  // Map event listener.
  map.addListener('mousemove', () => {
    // If the map gets a mousemove, that means there are no feature layers
    // with listeners registered under the mouse, so we clear the last
    // interacted feature ids.
    if (lastInteractedFeatureIds?.length) {
      lastInteractedFeatureIds = [];
      featureLayer.style = applyStyle;
    }
  });

  // Create the infowindow.
  infoWindow = new InfoWindow({});
  // Apply style on load, to enable clicking.
  featureLayer.style = applyStyle;
}

// Helper function for the infowindow.
async function createInfoWindow(event) {
  let feature = event.features[0];
  if (!feature.placeId) return;

  // Update the infowindow.
  const place = await feature.fetchPlace();
  let content =
      '<span style="font-size:small">Display name: ' + place.displayName +
      '<br/> Place ID: ' + feature.placeId +
      '<br/> Feature type: ' + feature.featureType + '</span>';

  updateInfoWindow(content, event.latLng);
}

// Define styles.
// Stroke and fill with minimum opacity value.
const styleDefault = {
  strokeColor: '#810FCB',
  strokeOpacity: 1.0,
  strokeWeight: 2.0,
  fillColor: 'white',
  fillOpacity: 0.1,  // Polygons must be visible to receive events.
};
// Style for the clicked polygon.
const styleClicked = {
  ...styleDefault,
  fillColor: '#810FCB',
  fillOpacity: 0.5,
};
// Style for polygon on mouse move.
const styleMouseMove = {
  ...styleDefault,
  strokeWeight: 4.0,
};

// Apply styles using a feature style function.
function applyStyle(/* FeatureStyleFunctionOptions */ params) {
  const placeId = params.feature.placeId;
  //@ts-ignore
  if (lastClickedFeatureIds.includes(placeId)) {
    return styleClicked;
  }
  //@ts-ignore
  if (lastInteractedFeatureIds.includes(placeId)) {
    return styleMouseMove;
  }
  return styleDefault;
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
  infoWindow.setContent(content);
  infoWindow.setPosition(center);
  infoWindow.open({
    map,
    shouldFocus: false,
  });
}

initMap();

JavaScript

let map;
let featureLayer;
let infoWindow;
let lastInteractedFeatureIds = [];
let lastClickedFeatureIds = [];

function handleClick(/* MouseEvent */ e) {
  lastClickedFeatureIds = e.features.map((f) => f.placeId);
  lastInteractedFeatureIds = [];
  featureLayer.style = applyStyle;
  createInfoWindow(e);
}

function handleMouseMove(/* MouseEvent */ e) {
  lastInteractedFeatureIds = e.features.map((f) => f.placeId);
  featureLayer.style = applyStyle;
}

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

  map = new Map(document.getElementById("map"), {
    center: { lat: 39.23, lng: -105.73 },
    zoom: 8,
    // In the cloud console, configure your Map ID with a style that enables the
    // 'Administrative Area Level 2' Data Driven Styling type.
    mapId: "a3efe1c035bad51b", // Substitute your own map ID.
    mapTypeControl: false,
  });
  // Add the feature layer.
  //@ts-ignore
  featureLayer = map.getFeatureLayer("ADMINISTRATIVE_AREA_LEVEL_2");
  // Add the event listeners for the feature layer.
  featureLayer.addListener("click", handleClick);
  featureLayer.addListener("mousemove", handleMouseMove);
  // Map event listener.
  map.addListener("mousemove", () => {
    // If the map gets a mousemove, that means there are no feature layers
    // with listeners registered under the mouse, so we clear the last
    // interacted feature ids.
    if (lastInteractedFeatureIds?.length) {
      lastInteractedFeatureIds = [];
      featureLayer.style = applyStyle;
    }
  });
  // Create the infowindow.
  infoWindow = new InfoWindow({});
  // Apply style on load, to enable clicking.
  featureLayer.style = applyStyle;
}

// Helper function for the infowindow.
async function createInfoWindow(event) {
  let feature = event.features[0];

  if (!feature.placeId) return;

  // Update the infowindow.
  const place = await feature.fetchPlace();
  let content =
    '<span style="font-size:small">Display name: ' +
    place.displayName +
    "<br/> Place ID: " +
    feature.placeId +
    "<br/> Feature type: " +
    feature.featureType +
    "</span>";

  updateInfoWindow(content, event.latLng);
}

// Define styles.
// Stroke and fill with minimum opacity value.
const styleDefault = {
  strokeColor: "#810FCB",
  strokeOpacity: 1.0,
  strokeWeight: 2.0,
  fillColor: "white",
  fillOpacity: 0.1, // Polygons must be visible to receive events.
};
// Style for the clicked polygon.
const styleClicked = {
  ...styleDefault,
  fillColor: "#810FCB",
  fillOpacity: 0.5,
};
// Style for polygon on mouse move.
const styleMouseMove = {
  ...styleDefault,
  strokeWeight: 4.0,
};

// Apply styles using a feature style function.
function applyStyle(/* FeatureStyleFunctionOptions */ params) {
  const placeId = params.feature.placeId;

  //@ts-ignore
  if (lastClickedFeatureIds.includes(placeId)) {
    return styleClicked;
  }

  //@ts-ignore
  if (lastInteractedFeatureIds.includes(placeId)) {
    return styleMouseMove;
  }
  return styleDefault;
}

// Helper function to create an info window.
function updateInfoWindow(content, center) {
  infoWindow.setContent(content);
  infoWindow.setPosition(center);
  infoWindow.open({
    map,
    shouldFocus: false,
  });
}

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>Handle Region Boundary Click Event</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>

サンプルを試す

詳細: イベントについて