處理滑鼠事件

選取平台: Android iOS JavaScript

總覽

請將地圖項目圖層設計成能夠回應 mousemoveclick 事件,並使用這些地圖項目,傳回所點擊邊界的相關資訊。這項資訊包括 ID、顯示名稱和地圖項目類型。以下地圖範例顯示 2 級行政區的邊界,並提供事件處理程式碼,可根據使用者互動設定多邊形樣式 (mousemove 會變更邊框粗細,click 則會為背景顏色加上陰影,並顯示資訊視窗)。

啟用地圖項目圖層事件

請按照下列步驟啟用地圖項目圖層上的事件:

  1. 找出您要註冊的每個事件,對地圖項目圖層呼叫 addListener() 函式,註冊事件通知的地圖項目圖層。在本例中,地圖也會取得事件監聽器。

    TypeScript

    // Add the feature layer.
    featureLayer = innerMap.getFeatureLayer(
        google.maps.FeatureType.ADMINISTRATIVE_AREA_LEVEL_2
    );
    
    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);
    
    // Map event listener.
    innerMap.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.
    featureLayer = innerMap.getFeatureLayer(google.maps.FeatureType.ADMINISTRATIVE_AREA_LEVEL_2);
    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);
    // Map event listener.
    innerMap.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 時變更背景並顯示資訊視窗,一種則是預設樣式。

    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 innerMap;
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;

    // Get the gmp-map element.
    const mapElement = document.querySelector(
        'gmp-map'
    ) as google.maps.MapElement;

    // Get the inner map.
    innerMap = mapElement.innerMap;

    // Set map options.
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Add the feature layer.
    featureLayer = innerMap.getFeatureLayer(
        google.maps.FeatureType.ADMINISTRATIVE_AREA_LEVEL_2
    );

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

    // Map event listener.
    innerMap.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 info window.
    // Get the place instance from the selected feature.
    const place = await feature.fetchPlace();

    // Create a new div to hold the text content.
    let content = document.createElement('div');

    // Get the text values.
    let nameText = document.createElement('span');
    nameText.textContent = `Display name: ${place.displayName}`;
    let placeIdText = document.createElement('span');
    placeIdText.textContent = `Place ID: ${feature.placeId}`;
    let featureTypeText = document.createElement('span');
    featureTypeText.textContent = `Feature type: ${feature.featureType}`;

    // Append the text to the div.
    content.appendChild(nameText);
    content.appendChild(document.createElement('br'));
    content.appendChild(placeIdText);
    content.appendChild(document.createElement('br'));
    content.appendChild(featureTypeText);

    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: innerMap,
        shouldFocus: false,
    });
}

initMap();

JavaScript

let innerMap;
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'));
    // Get the gmp-map element.
    const mapElement = document.querySelector('gmp-map');
    // Get the inner map.
    innerMap = mapElement.innerMap;
    // Set map options.
    innerMap.setOptions({
        mapTypeControl: false,
    });
    // Add the feature layer.
    featureLayer = innerMap.getFeatureLayer(google.maps.FeatureType.ADMINISTRATIVE_AREA_LEVEL_2);
    // Add the event listeners for the feature layer.
    featureLayer.addListener('click', handleClick);
    featureLayer.addListener('mousemove', handleMouseMove);
    // Map event listener.
    innerMap.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 info window.
    // Get the place instance from the selected feature.
    const place = await feature.fetchPlace();
    // Create a new div to hold the text content.
    let content = document.createElement('div');
    // Get the text values.
    let nameText = document.createElement('span');
    nameText.textContent = `Display name: ${place.displayName}`;
    let placeIdText = document.createElement('span');
    placeIdText.textContent = `Place ID: ${feature.placeId}`;
    let featureTypeText = document.createElement('span');
    featureTypeText.textContent = `Feature type: ${feature.featureType}`;
    // Append the text to the div.
    content.appendChild(nameText);
    content.appendChild(document.createElement('br'));
    content.appendChild(placeIdText);
    content.appendChild(document.createElement('br'));
    content.appendChild(featureTypeText);
    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: innerMap,
        shouldFocus: false,
    });
}
initMap();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
gmp-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>
    <!-- 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: "weekly"});</script>
  </head>
  <body>
    <gmp-map center="39.23,-105.73" zoom="8" map-id="8b37d7206ccf0121a2634fd5">
  </body>
</html>

試用範例

進一步瞭解事件