הוספת מקרא בהתאמה אישית

סקירה כללית

במדריך הזה מוסבר איך ליצור מקרא במפה ב-Google Maps. מקרא בדרך כלל מתאר את הסמלים והסמנים במפה. אפשר ליצור אותם באמצעות תכונת המיקום של פקדים בהתאמה אישית.

במפה שלמטה יש מקרא עם מידע על שלושה סמנים בהתאמה אישית שונים במפה.

בקטעים הבאים מוסברים השלבים העיקריים ליצירת מקרא.

בקטע דוגמה לקוד מלא מופיע הקוד המלא.

יצירת מאגר התגים של המקרא

יוצרים את מאגר התגים של המקרא על ידי הוספת div לרכיב gmp-map. אפשר להשתמש במיקום הפקדים כדי להגדיר את המיקום של המקרא. מידע נוסף על האפשרויות למיקום הפקדים

<gmp-map center="-33.91722,151.23064" zoom="16.5" map-id="DEMO_MAP_ID">
    <div id="legend" slot="control-inline-start-block-start"></div>
</gmp-map>

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

#legend {
    background-color: #fff;
    width: 15em;
    margin: 1em;
    border-radius: 8px;
    font-family: Roboto, Arial, sans-serif;
    overflow: hidden;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}

.legend-item {
    margin: 0.5em 1em;
    display: flex;
    flex-direction: row;
    align-items: center;
    padding-bottom: 0.5em;
}

.legend-icon {
    margin-right: 1em;
    font-size: 24px;
}

.legend-text {
    font-size: 1.5em;
}

מוסיפים את תוכן המקרא

הפונקציה makeLegend() יוצרת באופן פרוגרמטי מקרא למפה חזותית ומוסיפה אותו ל-DOM של הדף. כך זה עובד:

  1. מייבא את הספרייה: מייבא באופן דינמי את המחלקה PinElement מ-Maps SDK‏ (await google.maps.importLibrary('marker')).
const { PinElement } = await google.maps.importLibrary('marker');
  1. מכין את הקונטיינר: הוא לוקח את ה-<div id="legend"> הריק הקיים מה-HTML ומוסיף לו רכיב כותרת "מקרא".
const legend = document.getElementById('legend')!;

const title = document.createElement('div');
title.innerText = 'Legend';
title.classList.add('title');
legend.appendChild(title);
  1. עובר על ההגדרות: הוא עובר בלולאה על אובייקט ההגדרה icons כדי ליצור שורה לכל פריט (חנייה, ספרייה, מידע). פונקציית העזר נראית כך:

async function makeLegend() {
    const { PinElement } = await google.maps.importLibrary('marker');

    const legend = document.getElementById('legend');

    const title = document.createElement('div');
    title.innerText = 'Legend';
    title.classList.add('title');
    legend.appendChild(title);

    for (const type of Object.values(icons)) {
        const wrapper = document.createElement('div');
        wrapper.classList.add('legend-item');

        const pin = new PinElement({
            background: type.color,
            borderColor: type.color,
            glyphSrc: new URL(
                `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(type.icon)}`
            ),
            scale: 1.0,
        });

        // PinElement extends HTMLElement directly, so we can append it directly!
        const pinContainer = document.createElement('div');
        pinContainer.classList.add('legend-icon');
        pinContainer.appendChild(pin);

        const txt = document.createElement('div');
        txt.classList.add('legend-text');
        txt.innerText = type.name;

        wrapper.appendChild(pinContainer);
        wrapper.appendChild(txt);
        legend.appendChild(wrapper);
    }
}

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

קוד מלא לדוגמה

בקטע הבא מוצג הקוד המלא שצריך כדי ליצור את המפה ואת המקרא במדריך הזה.

TypeScript

const parkingSvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M13 3H6v18h4v-6h3c3.31 0 6-2.69 6-6s-2.69-6-6-6zm.2 8H10V7h3.2c1.1 0 2 .9 2 2s-.9 2-2 2z"/></svg>`;
const librarySvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 11.55C9.64 9.35 6.48 8 3 8v11c3.48 0 6.64 1.35 9 3.55 2.36-2.19 5.52-3.55 9-3.55V8c-3.48 0-6.64 1.35-9 3.55zM12 8c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3z"/></svg>`;
const infoSvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`;

const icons: Record<string, { name: string; icon: string; color: string }> = {
    parking: {
        name: 'Parking',
        icon: parkingSvg,
        color: '#1E88E5', // Blue
    },
    library: {
        name: 'Library',
        icon: librarySvg,
        color: '#43A047', // Green
    },
    info: {
        name: 'Info',
        icon: infoSvg,
        color: '#E53935', // Red
    },
};

async function init(): Promise<void> {
    const [{ AdvancedMarkerElement, PinElement }, { event }] =
        await Promise.all([
            google.maps.importLibrary('marker'),
            google.maps.importLibrary('core'),
            google.maps.importLibrary('maps'),
        ]);

    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    // Wait for the map to load before building the legend.
    event.addListenerOnce(innerMap, 'idle', () => {
        void makeLegend();
    });

    const features = [
        {
            position: { lat: -33.91721, lng: 151.2263 },
            type: 'info',
        },
        {
            position: { lat: -33.91539, lng: 151.2282 },
            type: 'info',
        },
        {
            position: { lat: -33.91747, lng: 151.22912 },
            type: 'info',
        },
        {
            position: { lat: -33.9191, lng: 151.22907 },
            type: 'info',
        },
        {
            position: { lat: -33.91725, lng: 151.23011 },
            type: 'info',
        },
        {
            position: { lat: -33.91872, lng: 151.23089 },
            type: 'info',
        },
        {
            position: { lat: -33.91784, lng: 151.23094 },
            type: 'info',
        },
        {
            position: { lat: -33.91682, lng: 151.23149 },
            type: 'info',
        },
        {
            position: { lat: -33.9179, lng: 151.23463 },
            type: 'info',
        },
        {
            position: { lat: -33.91666, lng: 151.23468 },
            type: 'info',
        },
        {
            position: { lat: -33.916988, lng: 151.23364 },
            type: 'info',
        },
        {
            position: { lat: -33.91662347903106, lng: 151.22879464019775 },
            type: 'parking',
        },
        {
            position: { lat: -33.916365282092855, lng: 151.22937399734496 },
            type: 'parking',
        },
        {
            position: { lat: -33.91665018901448, lng: 151.2282474695587 },
            type: 'parking',
        },
        {
            position: { lat: -33.919543720969806, lng: 151.23112279762267 },
            type: 'parking',
        },
        {
            position: { lat: -33.91608037421864, lng: 151.23288232673644 },
            type: 'parking',
        },
        {
            position: { lat: -33.91851096391805, lng: 151.2344058214569 },
            type: 'parking',
        },
        {
            position: { lat: -33.91818154739766, lng: 151.2346203981781 },
            type: 'parking',
        },
        {
            position: { lat: -33.91727341958453, lng: 151.23348314155578 },
            type: 'library',
        },
    ];

    for (const feature of features) {
        const iconData = icons[feature.type];

        const pin = new PinElement({
            background: iconData.color,
            borderColor: iconData.color,
            glyphSrc: new URL(
                `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(iconData.icon)}`
            ),
            scale: 1.5,
        });

        const marker = new AdvancedMarkerElement({
            position: feature.position,
            title: iconData.name,
        });

        marker.append(pin);
        mapElement.append(marker);
    }
}

async function makeLegend() {
    const { PinElement } = await google.maps.importLibrary('marker');

    const legend = document.getElementById('legend')!;

    const title = document.createElement('div');
    title.innerText = 'Legend';
    title.classList.add('title');
    legend.appendChild(title);

    for (const type of Object.values(icons)) {
        const wrapper = document.createElement('div');
        wrapper.classList.add('legend-item');

        const pin = new PinElement({
            background: type.color,
            borderColor: type.color,
            glyphSrc: new URL(
                `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(type.icon)}`
            ),
            scale: 1.0,
        });

        // PinElement extends HTMLElement directly, so we can append it directly!
        const pinContainer = document.createElement('div');
        pinContainer.classList.add('legend-icon');
        pinContainer.appendChild(pin);

        const txt = document.createElement('div');
        txt.classList.add('legend-text');
        txt.innerText = type.name;

        wrapper.appendChild(pinContainer);
        wrapper.appendChild(txt);
        legend.appendChild(wrapper);
    }
}

void init();

JavaScript

const parkingSvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M13 3H6v18h4v-6h3c3.31 0 6-2.69 6-6s-2.69-6-6-6zm.2 8H10V7h3.2c1.1 0 2 .9 2 2s-.9 2-2 2z"/></svg>`;
const librarySvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 11.55C9.64 9.35 6.48 8 3 8v11c3.48 0 6.64 1.35 9 3.55 2.36-2.19 5.52-3.55 9-3.55V8c-3.48 0-6.64 1.35-9 3.55zM12 8c1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3 1.34 3 3 3z"/></svg>`;
const infoSvg = `<svg fill="white" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`;

const icons = {
    parking: {
        name: 'Parking',
        icon: parkingSvg,
        color: '#1E88E5', // Blue
    },
    library: {
        name: 'Library',
        icon: librarySvg,
        color: '#43A047', // Green
    },
    info: {
        name: 'Info',
        icon: infoSvg,
        color: '#E53935', // Red
    },
};

async function init() {
    const [{ AdvancedMarkerElement, PinElement }, { event }] =
        await Promise.all([
            google.maps.importLibrary('marker'),
            google.maps.importLibrary('core'),
            google.maps.importLibrary('maps'),
        ]);

    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    // Wait for the map to load before building the legend.
    event.addListenerOnce(innerMap, 'idle', () => {
        void makeLegend();
    });

    const features = [
        {
            position: { lat: -33.91721, lng: 151.2263 },
            type: 'info',
        },
        {
            position: { lat: -33.91539, lng: 151.2282 },
            type: 'info',
        },
        {
            position: { lat: -33.91747, lng: 151.22912 },
            type: 'info',
        },
        {
            position: { lat: -33.9191, lng: 151.22907 },
            type: 'info',
        },
        {
            position: { lat: -33.91725, lng: 151.23011 },
            type: 'info',
        },
        {
            position: { lat: -33.91872, lng: 151.23089 },
            type: 'info',
        },
        {
            position: { lat: -33.91784, lng: 151.23094 },
            type: 'info',
        },
        {
            position: { lat: -33.91682, lng: 151.23149 },
            type: 'info',
        },
        {
            position: { lat: -33.9179, lng: 151.23463 },
            type: 'info',
        },
        {
            position: { lat: -33.91666, lng: 151.23468 },
            type: 'info',
        },
        {
            position: { lat: -33.916988, lng: 151.23364 },
            type: 'info',
        },
        {
            position: { lat: -33.91662347903106, lng: 151.22879464019775 },
            type: 'parking',
        },
        {
            position: { lat: -33.916365282092855, lng: 151.22937399734496 },
            type: 'parking',
        },
        {
            position: { lat: -33.91665018901448, lng: 151.2282474695587 },
            type: 'parking',
        },
        {
            position: { lat: -33.919543720969806, lng: 151.23112279762267 },
            type: 'parking',
        },
        {
            position: { lat: -33.91608037421864, lng: 151.23288232673644 },
            type: 'parking',
        },
        {
            position: { lat: -33.91851096391805, lng: 151.2344058214569 },
            type: 'parking',
        },
        {
            position: { lat: -33.91818154739766, lng: 151.2346203981781 },
            type: 'parking',
        },
        {
            position: { lat: -33.91727341958453, lng: 151.23348314155578 },
            type: 'library',
        },
    ];

    for (const feature of features) {
        const iconData = icons[feature.type];

        const pin = new PinElement({
            background: iconData.color,
            borderColor: iconData.color,
            glyphSrc: new URL(
                `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(iconData.icon)}`
            ),
            scale: 1.5,
        });

        const marker = new AdvancedMarkerElement({
            position: feature.position,
            title: iconData.name,
        });

        marker.append(pin);
        mapElement.append(marker);
    }
}

async function makeLegend() {
    const { PinElement } = await google.maps.importLibrary('marker');

    const legend = document.getElementById('legend');

    const title = document.createElement('div');
    title.innerText = 'Legend';
    title.classList.add('title');
    legend.appendChild(title);

    for (const type of Object.values(icons)) {
        const wrapper = document.createElement('div');
        wrapper.classList.add('legend-item');

        const pin = new PinElement({
            background: type.color,
            borderColor: type.color,
            glyphSrc: new URL(
                `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(type.icon)}`
            ),
            scale: 1.0,
        });

        // PinElement extends HTMLElement directly, so we can append it directly!
        const pinContainer = document.createElement('div');
        pinContainer.classList.add('legend-icon');
        pinContainer.appendChild(pin);

        const txt = document.createElement('div');
        txt.classList.add('legend-text');
        txt.innerText = type.name;

        wrapper.appendChild(pinContainer);
        wrapper.appendChild(txt);
        legend.appendChild(wrapper);
    }
}

void init();

CSS

html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#legend {
    background-color: #fff;
    width: 15em;
    margin: 1em;
    border-radius: 8px;
    font-family: Roboto, Arial, sans-serif;
    overflow: hidden;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}

.title {
    padding: 0.5em 1em;
    font-weight: bold;
    font-size: 1.5em;
    margin-bottom: 0.5em;
    background-color: rgb(66, 133, 244);
    color: white;
    box-sizing: border-box;
}

.legend-item {
    margin: 0.5em 1em;
    display: flex;
    flex-direction: row;
    align-items: center;
    padding-bottom: 0.5em;
}

.legend-icon {
    margin-right: 1em;
    font-size: 24px;
}

.legend-text {
    font-size: 1.5em;
}

HTML

<html>
    <head>
        <title>Custom Legend</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="-33.91722,151.23064" zoom="16.5" map-id="DEMO_MAP_ID">
            <div id="legend" slot="control-inline-start-block-start"></div>
        </gmp-map>
    </body>
</html>