使用標記

歐洲經濟區 (EEA) 開發人員

呼叫 createWaypointAdvancedMarkers(),為路線航點建立標記。預設情況下,createWaypointAdvancedMarkers() 會為每個路線控點建立標記為「A」、「B」、「C」等的路線標記。您可以傳遞選項,根據標記索引或對應 RouteLeg 的屬性,進一步自訂標記樣式。

查看完整範例原始碼

以下程式碼範例說明如何為路徑航點建立自訂標記。

TypeScript

let mapPolylines: google.maps.Polyline[] = [];
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

// Initialize and add the map.
async function init() {
    //  Request the needed libraries.
    const [{ event }] = await Promise.all([
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    // Call the function after the map is loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void getDirections();
    });
}

async function getDirections() {
    // Request the needed libraries.
    const [{ Route }, { PinElement }] = await Promise.all([
        google.maps.importLibrary('routes'),
        google.maps.importLibrary('marker'),
    ]);

    // Define routes request with an intermediate stop.
    const request: google.maps.routes.ComputeRoutesRequest = {
        origin: 'Parking lot, Christmas Tree Point Rd, San Francisco, CA 94131',
        destination: '100 Spinnaker Dr, Sausalito, CA 94965', // We're having a yummy lunch!
        intermediates: [{ location: '300 Finley Rd San Francisco, CA 94129' }], // But first, we golf!
        travelMode: 'DRIVING',
        fields: ['path', 'legs', 'viewport'],
    };

    // Call computeRoutes to get the directions.
    const result = await Route.computeRoutes(request);
    if (!result.routes || result.routes.length === 0) {
        console.warn('No routes found');
        return;
    }

    // Alter style based on marker index.
    function markerOptionsMaker(
        defaultOptions: google.maps.marker.AdvancedMarkerElementOptions,
        waypointMarkerDetails: google.maps.routes.WaypointMarkerDetails
    ) {
        const { index, totalMarkers } = waypointMarkerDetails;

        // Style the origin waypoint.
        if (index === 0) {
            return {
                ...defaultOptions,
                title: 'Origin',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'green',
                    borderColor: 'green',
                    scale: 1.5,
                }),
            };
        }

        // Style all intermediate waypoints.
        if (!(index === 0 || index === totalMarkers - 1)) {
            return {
                ...defaultOptions,
                title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
                map: innerMap,
                gmpClickable: true, // Make marker focusable and allow keyboard navigation
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'blue',
                    borderColor: 'blue',
                    scale: 1.5, // Increase size for better visibilty
                }),
            };
        }

        // Style the destination waypoint.
        if (index === totalMarkers - 1) {
            return {
                ...defaultOptions,
                title: 'Destination',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'red',
                    borderColor: 'red',
                    scale: 1.5,
                }),
            };
        }

        return { ...defaultOptions, map: innerMap };
    }

    await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

    // Fit the map to the route.
    innerMap.fitBounds(result.routes[0].viewport!);
    innerMap.setHeading(270);

    // Create polylines and add them to the map.
    mapPolylines = result.routes[0].createPolylines();
    mapPolylines.forEach((polyline) => {
        polyline.setMap(innerMap);
    });
}

void init();

JavaScript

let mapPolylines = [];
const mapElement = document.querySelector('gmp-map');
let innerMap;

// Initialize and add the map.
async function init() {
    //  Request the needed libraries.
    const [{ event }] = await Promise.all([
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    // Call the function after the map is loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void getDirections();
    });
}

async function getDirections() {
    // Request the needed libraries.
    const [{ Route }, { PinElement }] = await Promise.all([
        google.maps.importLibrary('routes'),
        google.maps.importLibrary('marker'),
    ]);

    // Define routes request with an intermediate stop.
    const request = {
        origin: 'Parking lot, Christmas Tree Point Rd, San Francisco, CA 94131',
        destination: '100 Spinnaker Dr, Sausalito, CA 94965', // We're having a yummy lunch!
        intermediates: [{ location: '300 Finley Rd San Francisco, CA 94129' }], // But first, we golf!
        travelMode: 'DRIVING',
        fields: ['path', 'legs', 'viewport'],
    };

    // Call computeRoutes to get the directions.
    const result = await Route.computeRoutes(request);
    if (!result.routes || result.routes.length === 0) {
        console.warn('No routes found');
        return;
    }

    // Alter style based on marker index.
    function markerOptionsMaker(defaultOptions, waypointMarkerDetails) {
        const { index, totalMarkers } = waypointMarkerDetails;

        // Style the origin waypoint.
        if (index === 0) {
            return {
                ...defaultOptions,
                title: 'Origin',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'green',
                    borderColor: 'green',
                    scale: 1.5,
                }),
            };
        }

        // Style all intermediate waypoints.
        if (!(index === 0 || index === totalMarkers - 1)) {
            return {
                ...defaultOptions,
                title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
                map: innerMap,
                gmpClickable: true, // Make marker focusable and allow keyboard navigation
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'blue',
                    borderColor: 'blue',
                    scale: 1.5, // Increase size for better visibilty
                }),
            };
        }

        // Style the destination waypoint.
        if (index === totalMarkers - 1) {
            return {
                ...defaultOptions,
                title: 'Destination',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'red',
                    borderColor: 'red',
                    scale: 1.5,
                }),
            };
        }

        return { ...defaultOptions, map: innerMap };
    }

    await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

    // Fit the map to the route.
    innerMap.fitBounds(result.routes[0].viewport);
    innerMap.setHeading(270);

    // Create polylines and add them to the map.
    mapPolylines = result.routes[0].createPolylines();
    mapPolylines.forEach((polyline) => {
        polyline.setMap(innerMap);
    });
}

void init();

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>Get directions</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (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: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <gmp-map center="37.447646, -122.113878" zoom="12"></gmp-map>
    </body>
</html>

新增預設標記

如要使用預設樣式新增標記,請呼叫 createWaypointAdvancedMarkers(),並傳遞標記選項來指定目前的地圖,如下列程式碼片段所示。

// Create markers using default style.
const markers = await result.routes[0].createWaypointAdvancedMarkers({ map: innerMap });
  

新增自訂樣式的標記

如要使用自訂樣式新增標記,請呼叫 createWaypointAdvancedMarkers(),並傳遞包含自訂樣式屬性的標記選項。套用這類樣式時,所有標記都會採用相同樣式。下列程式碼片段說明如何建立具有自訂樣式的標記。

// Create markers with a custom style.
const markerOptions = {
  map: innerMap,
  content: new PinElement({
    scale: 1.5,
    background: '#8C0DD1',
    borderColor: '#6D0AA5',
    glyphColor: '#6D0AA5',
  }).element
}

const markers = await result.routes[0].createWaypointAdvancedMarkers(markerOptions);
  

為個別標記套用自訂樣式

如要為個別標記套用自訂樣式,請將函式傳遞至 createWaypointAdvancedMarkers(),根據標記索引或 RouteLeg 屬性設定標記樣式選項。下列程式碼片段顯示函式,可根據標記索引建立標記並設定樣式:

TypeScript

// Alter style based on marker index.
function markerOptionsMaker(
    defaultOptions: google.maps.marker.AdvancedMarkerElementOptions,
    waypointMarkerDetails: google.maps.routes.WaypointMarkerDetails
) {
    const { index, totalMarkers } = waypointMarkerDetails;

    // Style the origin waypoint.
    if (index === 0) {
        return {
            ...defaultOptions,
            title: 'Origin',
            map: innerMap,
            gmpClickable: true,
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'green',
                borderColor: 'green',
                scale: 1.5,
            }),
        };
    }

    // Style all intermediate waypoints.
    if (!(index === 0 || index === totalMarkers - 1)) {
        return {
            ...defaultOptions,
            title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
            map: innerMap,
            gmpClickable: true, // Make marker focusable and allow keyboard navigation
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'blue',
                borderColor: 'blue',
                scale: 1.5, // Increase size for better visibilty
            }),
        };
    }

    // Style the destination waypoint.
    if (index === totalMarkers - 1) {
        return {
            ...defaultOptions,
            title: 'Destination',
            map: innerMap,
            gmpClickable: true,
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'red',
                borderColor: 'red',
                scale: 1.5,
            }),
        };
    }

    return { ...defaultOptions, map: innerMap };
}

await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

JavaScript

// Alter style based on marker index.
function markerOptionsMaker(defaultOptions, waypointMarkerDetails) {
    const { index, totalMarkers } = waypointMarkerDetails;

    // Style the origin waypoint.
    if (index === 0) {
        return {
            ...defaultOptions,
            title: 'Origin',
            map: innerMap,
            gmpClickable: true,
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'green',
                borderColor: 'green',
                scale: 1.5,
            }),
        };
    }

    // Style all intermediate waypoints.
    if (!(index === 0 || index === totalMarkers - 1)) {
        return {
            ...defaultOptions,
            title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
            map: innerMap,
            gmpClickable: true, // Make marker focusable and allow keyboard navigation
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'blue',
                borderColor: 'blue',
                scale: 1.5, // Increase size for better visibilty
            }),
        };
    }

    // Style the destination waypoint.
    if (index === totalMarkers - 1) {
        return {
            ...defaultOptions,
            title: 'Destination',
            map: innerMap,
            gmpClickable: true,
            content: new PinElement({
                glyphText: (index + 1).toString(),
                glyphColor: 'white',
                background: 'red',
                borderColor: 'red',
                scale: 1.5,
            }),
        };
    }

    return { ...defaultOptions, map: innerMap };
}

await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

將標記設計為符合無障礙功能

您可以透過下列方式提升標記無障礙程度:

  • 提供標題:在標記選項中設定 title 屬性,為標記提供標籤。螢幕閱讀器和輔助技術會使用這個標籤。
  • 區分中途停靠點:將樣式函式傳遞至 createWaypointAdvancedMarkers() 時,請使用 WaypointMarkerDetails 中的 index 和 totalMarkers 參數,為中途停靠點指派獨一無二的說明標題和標籤 (例如 Waypoint ${(index + 1).toString()}),讓螢幕閱讀器使用者可以區分中途停靠點與起點和目的地。
  • 啟用鍵盤導覽和點擊事件:在標記選項中設定 gmpClickable: true,讓互動式標記可透過鍵盤 (使用 Tab 鍵和方向鍵) 聚焦,並回應鍵盤和滑鼠輸入動作。
  • 放大標記:在 PinElement 上設定 scale 屬性 (例如 scale: 1.5),降低與標記互動所需的精確度,特別是在觸控螢幕裝置上。預設標記符合 WCAG AA 最小尺寸標準,放大比例有助於符合 WCAG AAA 目標尺寸標準。
  • 維持色彩對比:自訂 PinElement 顏色時,請選擇 glyphColor 和 background 值,確保有足夠的對比度,讓路線控點標籤保持清晰易讀。

下列程式碼片段說明如何設定標記的樣式,以符合無障礙功能需求。它具有 title,可為螢幕閱讀器提供標籤;標題會使用索引來區分中途航點。gmpClickable 屬性設為 true,可啟用鍵盤瀏覽和點擊事件,並增加 scale,方便與標記互動。

TypeScript

// Style all intermediate waypoints.
if (!(index === 0 || index === totalMarkers - 1)) {
    return {
        ...defaultOptions,
        title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
        map: innerMap,
        gmpClickable: true, // Make marker focusable and allow keyboard navigation
        content: new PinElement({
            glyphText: (index + 1).toString(),
            glyphColor: 'white',
            background: 'blue',
            borderColor: 'blue',
            scale: 1.5, // Increase size for better visibilty
        }),
    };
}

JavaScript

// Style all intermediate waypoints.
if (!(index === 0 || index === totalMarkers - 1)) {
    return {
        ...defaultOptions,
        title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
        map: innerMap,
        gmpClickable: true, // Make marker focusable and allow keyboard navigation
        content: new PinElement({
            glyphText: (index + 1).toString(),
            glyphColor: 'white',
            background: 'blue',
            borderColor: 'blue',
            scale: 1.5, // Increase size for better visibilty
        }),
    };
}

詳情請參閱「將標記設計為可點選且符合無障礙功能」。

查看完整範例

TypeScript

let mapPolylines: google.maps.Polyline[] = [];
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

// Initialize and add the map.
async function init() {
    //  Request the needed libraries.
    const [{ event }] = await Promise.all([
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    // Call the function after the map is loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void getDirections();
    });
}

async function getDirections() {
    // Request the needed libraries.
    const [{ Route }, { PinElement }] = await Promise.all([
        google.maps.importLibrary('routes'),
        google.maps.importLibrary('marker'),
    ]);

    // Define routes request with an intermediate stop.
    const request: google.maps.routes.ComputeRoutesRequest = {
        origin: 'Parking lot, Christmas Tree Point Rd, San Francisco, CA 94131',
        destination: '100 Spinnaker Dr, Sausalito, CA 94965', // We're having a yummy lunch!
        intermediates: [{ location: '300 Finley Rd San Francisco, CA 94129' }], // But first, we golf!
        travelMode: 'DRIVING',
        fields: ['path', 'legs', 'viewport'],
    };

    // Call computeRoutes to get the directions.
    const result = await Route.computeRoutes(request);
    if (!result.routes || result.routes.length === 0) {
        console.warn('No routes found');
        return;
    }

    // Alter style based on marker index.
    function markerOptionsMaker(
        defaultOptions: google.maps.marker.AdvancedMarkerElementOptions,
        waypointMarkerDetails: google.maps.routes.WaypointMarkerDetails
    ) {
        const { index, totalMarkers } = waypointMarkerDetails;

        // Style the origin waypoint.
        if (index === 0) {
            return {
                ...defaultOptions,
                title: 'Origin',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'green',
                    borderColor: 'green',
                    scale: 1.5,
                }),
            };
        }

        // Style all intermediate waypoints.
        if (!(index === 0 || index === totalMarkers - 1)) {
            return {
                ...defaultOptions,
                title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
                map: innerMap,
                gmpClickable: true, // Make marker focusable and allow keyboard navigation
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'blue',
                    borderColor: 'blue',
                    scale: 1.5, // Increase size for better visibilty
                }),
            };
        }

        // Style the destination waypoint.
        if (index === totalMarkers - 1) {
            return {
                ...defaultOptions,
                title: 'Destination',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'red',
                    borderColor: 'red',
                    scale: 1.5,
                }),
            };
        }

        return { ...defaultOptions, map: innerMap };
    }

    await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

    // Fit the map to the route.
    innerMap.fitBounds(result.routes[0].viewport!);
    innerMap.setHeading(270);

    // Create polylines and add them to the map.
    mapPolylines = result.routes[0].createPolylines();
    mapPolylines.forEach((polyline) => {
        polyline.setMap(innerMap);
    });
}

void init();

JavaScript

let mapPolylines = [];
const mapElement = document.querySelector('gmp-map');
let innerMap;

// Initialize and add the map.
async function init() {
    //  Request the needed libraries.
    const [{ event }] = await Promise.all([
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
        mapId: 'DEMO_MAP_ID',
    });

    // Call the function after the map is loaded.
    event.addListenerOnce(innerMap, 'idle', () => {
        void getDirections();
    });
}

async function getDirections() {
    // Request the needed libraries.
    const [{ Route }, { PinElement }] = await Promise.all([
        google.maps.importLibrary('routes'),
        google.maps.importLibrary('marker'),
    ]);

    // Define routes request with an intermediate stop.
    const request = {
        origin: 'Parking lot, Christmas Tree Point Rd, San Francisco, CA 94131',
        destination: '100 Spinnaker Dr, Sausalito, CA 94965', // We're having a yummy lunch!
        intermediates: [{ location: '300 Finley Rd San Francisco, CA 94129' }], // But first, we golf!
        travelMode: 'DRIVING',
        fields: ['path', 'legs', 'viewport'],
    };

    // Call computeRoutes to get the directions.
    const result = await Route.computeRoutes(request);
    if (!result.routes || result.routes.length === 0) {
        console.warn('No routes found');
        return;
    }

    // Alter style based on marker index.
    function markerOptionsMaker(defaultOptions, waypointMarkerDetails) {
        const { index, totalMarkers } = waypointMarkerDetails;

        // Style the origin waypoint.
        if (index === 0) {
            return {
                ...defaultOptions,
                title: 'Origin',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'green',
                    borderColor: 'green',
                    scale: 1.5,
                }),
            };
        }

        // Style all intermediate waypoints.
        if (!(index === 0 || index === totalMarkers - 1)) {
            return {
                ...defaultOptions,
                title: `Waypoint ${(index + 1).toString()}`, // Provide label for screenreaders
                map: innerMap,
                gmpClickable: true, // Make marker focusable and allow keyboard navigation
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'blue',
                    borderColor: 'blue',
                    scale: 1.5, // Increase size for better visibilty
                }),
            };
        }

        // Style the destination waypoint.
        if (index === totalMarkers - 1) {
            return {
                ...defaultOptions,
                title: 'Destination',
                map: innerMap,
                gmpClickable: true,
                content: new PinElement({
                    glyphText: (index + 1).toString(),
                    glyphColor: 'white',
                    background: 'red',
                    borderColor: 'red',
                    scale: 1.5,
                }),
            };
        }

        return { ...defaultOptions, map: innerMap };
    }

    await result.routes[0].createWaypointAdvancedMarkers(markerOptionsMaker);

    // Fit the map to the route.
    innerMap.fitBounds(result.routes[0].viewport);
    innerMap.setHeading(270);

    // Create polylines and add them to the map.
    mapPolylines = result.routes[0].createPolylines();
    mapPolylines.forEach((polyline) => {
        polyline.setMap(innerMap);
    });
}

void init();

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>Get directions</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (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: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <gmp-map center="37.447646, -122.113878" zoom="12"></gmp-map>
    </body>
</html>