জায়গার ফটো

ইউরোপীয় অর্থনৈতিক অঞ্চল (EEA)-এর ডেভেলপার

'জায়গার ফটো' আপনাকে ওয়েব পেজে খুব ভালো কোয়ালিটির ফটোগ্রাফিক কন্টেন্ট যোগ করতে দেয়। Places ডেটাবেসে সেভ করা লক্ষ লক্ষ ফটো অ্যাক্সেস করুন এবং Find Place, Nearby Search, Text Search, Autocomplete এবং Place Details ব্যবহার করে ছোট বড় করা যায় এমন ছবি পান।

সম্পূর্ণ উদাহরণ সোর্স কোড দেখুন

এই ডেমো পাঁচটি শহরের মধ্যে একটি থেকে একটি র‍্যান্ডম ফটো দেখায় এবং ফটোটির নিচের ডানদিকের কোণায় প্রয়োজনীয় লেখক অ্যাট্রিবিউশন দেখায়।

TypeScript

const CITIES = [
    { name: 'New York', id: 'ChIJOwg_06VPwokRYv534QaPC8g' },
    { name: 'London', id: 'ChIJdd4hrwug2EcRmSrV3Vo6llI' },
    { name: 'Paris', id: 'ChIJD7fiBh9u5kcRYJSMaMOCCwQ' },
    { name: 'Tokyo', id: 'ChIJ51cu8IcbXWARiRtXIothAS4' },
    { name: 'Rome', id: 'ChIJu46S-ZZhLxMROG5lkwZ3D7k' },
];

async function init() {
    const { Place } = await google.maps.importLibrary('places');

    const heading = document.getElementById('heading')!;
    const summary = document.getElementById('summary')!;
    const expandedImageDiv = document.getElementById('expanded-image')!;
    const randomizeBtn = document.getElementById(
        'randomize-btn'
    ) as HTMLButtonElement;

    async function showRandomCityPhoto() {
        randomizeBtn.disabled = true;

        // Pick a random city
        const city = CITIES[Math.floor(Math.random() * CITIES.length)];

        try {
            const place = new Place({ id: city.id });
            await place.fetchFields({
                fields: ['displayName', 'photos', 'editorialSummary'],
            });

            heading.textContent = place.displayName ?? city.name;
            summary.textContent = place.editorialSummary ?? '';
            expandedImageDiv.innerHTML = '';

            if (place.photos && place.photos.length > 0) {
                // Pick one of the first 10 photos
                const maxPhotos = Math.min(10, place.photos.length);
                const randomIndex = Math.floor(Math.random() * maxPhotos);
                const photo = place.photos[randomIndex];

                const img = document.createElement('img');
                img.alt = `Photo of ${place.displayName ?? city.name}`;
                img.src = photo.getURI({ maxHeight: 800 });
                expandedImageDiv.appendChild(img);

                if (photo.authorAttributions.length) {
                    expandedImageDiv.appendChild(
                        createAttribution(photo.authorAttributions[0])
                    );
                }
            } else {
                expandedImageDiv.textContent =
                    'No photos available for this location.';
            }
        } catch (error) {
            console.error('Failed to fetch place details:', error);
            summary.textContent = 'Failed to load data.';
        }

        // Re-enable button after 2 seconds
        setTimeout(() => {
            randomizeBtn.disabled = false;
        }, 2000);
    }

    // Helper function to create attribution DIV.
    function createAttribution(
        attribution: google.maps.places.AuthorAttribution
    ) {
        const attributionLabel = document.createElement('a');
        attributionLabel.classList.add('attribution-label');
        attributionLabel.textContent = attribution.displayName;
        attributionLabel.href = attribution.uri!;
        attributionLabel.target = '_blank';
        attributionLabel.rel = 'noopener noreferrer';
        return attributionLabel;
    }

    randomizeBtn.addEventListener('click', () => void showRandomCityPhoto());

    // Initial load
    void showRandomCityPhoto();
}

void init();

জাভাস্ক্রিপ্ট

const CITIES = [
    { name: 'New York', id: 'ChIJOwg_06VPwokRYv534QaPC8g' },
    { name: 'London', id: 'ChIJdd4hrwug2EcRmSrV3Vo6llI' },
    { name: 'Paris', id: 'ChIJD7fiBh9u5kcRYJSMaMOCCwQ' },
    { name: 'Tokyo', id: 'ChIJ51cu8IcbXWARiRtXIothAS4' },
    { name: 'Rome', id: 'ChIJu46S-ZZhLxMROG5lkwZ3D7k' },
];

async function init() {
    const { Place } = await google.maps.importLibrary('places');

    const heading = document.getElementById('heading');
    const summary = document.getElementById('summary');
    const expandedImageDiv = document.getElementById('expanded-image');
    const randomizeBtn = document.getElementById('randomize-btn');

    async function showRandomCityPhoto() {
        randomizeBtn.disabled = true;

        // Pick a random city
        const city = CITIES[Math.floor(Math.random() * CITIES.length)];

        try {
            const place = new Place({ id: city.id });
            await place.fetchFields({
                fields: ['displayName', 'photos', 'editorialSummary'],
            });

            heading.textContent = place.displayName ?? city.name;
            summary.textContent = place.editorialSummary ?? '';
            expandedImageDiv.innerHTML = '';

            if (place.photos && place.photos.length > 0) {
                // Pick one of the first 10 photos
                const maxPhotos = Math.min(10, place.photos.length);
                const randomIndex = Math.floor(Math.random() * maxPhotos);
                const photo = place.photos[randomIndex];

                const img = document.createElement('img');
                img.alt = `Photo of ${place.displayName ?? city.name}`;
                img.src = photo.getURI({ maxHeight: 800 });
                expandedImageDiv.appendChild(img);

                if (photo.authorAttributions.length) {
                    expandedImageDiv.appendChild(
                        createAttribution(photo.authorAttributions[0])
                    );
                }
            } else {
                expandedImageDiv.textContent =
                    'No photos available for this location.';
            }
        } catch (error) {
            console.error('Failed to fetch place details:', error);
            summary.textContent = 'Failed to load data.';
        }

        // Re-enable button after 2 seconds
        setTimeout(() => {
            randomizeBtn.disabled = false;
        }, 2000);
    }

    // Helper function to create attribution DIV.
    function createAttribution(attribution) {
        const attributionLabel = document.createElement('a');
        attributionLabel.classList.add('attribution-label');
        attributionLabel.textContent = attribution.displayName;
        attributionLabel.href = attribution.uri;
        attributionLabel.target = '_blank';
        attributionLabel.rel = 'noopener noreferrer';
        return attributionLabel;
    }

    randomizeBtn.addEventListener('click', () => void showRandomCityPhoto());

    // Initial load
    void showRandomCityPhoto();
}

void init();

CSS

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
    font-family: 'Inter', sans-serif;
    background: linear-gradient(135deg, #1e1e2f, #252540);
    display: flex;
    align-items: center;
    justify-content: center;
}

#container {
    display: flex;
    background: rgba(255, 255, 255, 0.05);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    padding: 30px;
    max-width: 900px;
    width: 100%;
    box-sizing: border-box;
    box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
    color: white;
}

.place-overview {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-right: 40px;
}

#info {
    position: relative;
}

#heading {
    font-size: 2.5rem;
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 15px;
    background: linear-gradient(90deg, #fff, #a5b4fc);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

#summary {
    font-size: 1.1rem;
    line-height: 1.6;
    color: #cbd5e1;
}

#expanded-image {
    position: relative;
    width: 400px;
    height: 400px;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
    transform: perspective(1000px) rotateY(-5deg);
    transition: transform 0.5s ease;
}

#expanded-image:hover {
    transform: perspective(1000px) rotateY(0deg) scale(1.02);
}

#expanded-image img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

#randomize-btn {
    margin-top: 20px;
    padding: 12px 24px;
    font-size: 1.1rem;
    font-weight: bold;
    color: white;
    background: linear-gradient(90deg, #4f46e5, #3b82f6);
    border: none;
    border-radius: 12px;
    cursor: pointer;
    transition:
        transform 0.2s,
        background 0.3s;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    font-family: 'Inter', sans-serif;
    align-self: flex-start;
}

#randomize-btn:hover:not(:disabled) {
    transform: scale(1.05);
}

#randomize-btn:disabled {
    background: #475569;
    cursor: not-allowed;
    opacity: 0.7;
}

.attribution-label {
    position: absolute;
    bottom: 10px;
    right: 10px;
    background-color: rgba(0, 0, 0, 0.6);
    color: white;
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 0.8rem;
    text-decoration: none;
    backdrop-filter: blur(4px);
    transition: background-color 0.3s;
}

.attribution-label:hover {
    background-color: rgba(0, 0, 0, 0.8);
}

HTML

<html lang="en">
    <head>
        <title>Place Photos</title>
        <link
            href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
            rel="stylesheet" />
        <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>
        <div id="container">
            <div class="place-overview">
                <div id="info">
                    <h1 id="heading"></h1>
                    <div id="summary"></div>
                </div>
                <button id="randomize-btn">Random City Photo</button>
            </div>
            <div id="expanded-image"></div>
        </div>
    </body>
</html>

ফটো তুলুন

কোনও জায়গার ফটো পেতে, আপনার fetchFields() অনুরোধের প্যারামিটারে photos ফিল্ড অন্তর্ভুক্ত করুন। ফলাফল হিসেবে পাওয়া Place ইনস্ট্যান্সে সর্বাধিক ১০টি Photo অবজেক্টের অ্যারে থাকে, যেখান থেকে আপনি ছবি এবং সেগুলির প্রয়োজনীয় অ্যাট্রিবিউশন তথ্য অ্যাক্সেস করতে পারবেন। getURI() কল করুন যাতে সোর্স ফটো URI ফেরত পাওয়া যায়, PhotoOptions ব্যবহার করে ফেরত পাওয়া ছবির সর্বাধিক উচ্চতা এবং/অথবা প্রস্থ সেট করুন। আপনি maxHeight এবং maxWidth, দুটির জন্যই কোনও ভ্যালু নির্দিষ্ট করলে, ফটো পরিষেবা আসল অ্যাস্পেক্ট রেশিও বজায় রেখে, দুটি সাইজের মধ্যে যেটি ছোট, সেই সাইজে ছবিটিকে ছোট বড় করবে। কোনও ডাইমেনশন উল্লেখ করা না থাকলে, সম্পূর্ণ সাইজের ছবি দেখানো হবে।

Photo ক্লাস নিম্নলিখিত প্রপার্টি প্রকাশ করে:

  • authorAttributions: AuthorAttribution-এর একটি অ্যারে প্রয়োজনীয় অ্যাট্রিবিউশন টেক্সট ও URL সহ অবজেক্ট।
  • flagContentURI: এমন একটি লিঙ্ক যেখানে ব্যবহারকারী ফটো সংক্রান্ত কোনও সমস্যা ফ্ল্যাগ করতে পারবেন।
  • googleMapsURI: Google Maps-এ ফটো দেখানোর জন্য একটি লিঙ্ক।
  • heightPx: পিক্সেল হিসেবে ফটোর উচ্চতা।
  • widthPx: পিক্সেল হিসেবে ফটোর প্রস্থ।

নিচের উদাহরণে দেখানো হয়েছে যে কীভাবে ফটোর জন্য জায়গার বিবরণ সংক্রান্ত অনুরোধ করা হয়, ছবির সোর্স URI ফেরত পেতে ফটো ইনস্ট্যান্সে getURI() কল করা হয়, তারপর প্রথম ফটোর ফলাফল img এলিমেন্টে যোগ করা হয় (সংক্ষিপ্ত করার জন্য অ্যাট্রিবিউশন বাদ দেওয়া হয়েছে):

const { Place } = await google.maps.importLibrary('places');

// Use a place ID to create a new Place instance.
const place = new Place({
    id: 'ChIJydSuSkkUkFQRsqhB-cEtYnw', // Woodland Park Zoo, Seattle WA
});

// Call fetchFields, passing the desired data fields.
await place.fetchFields({ fields: ['photos'] });

// Add the first photo to an img element.
const photoImg = document.getElementById('image-container');
photoImg.src = place.photos[0].getURI({maxHeight: 400});

লেখক অ্যাট্রিবিউশন

আপনি কোনও ফটো দেখালে, আপনাকে অবশ্যই ফটোর জন্য লেখকের অ্যাট্রিবিউশন দেখাতে হবে। অ্যাট্রিবিউশন ফিরিয়ে দিতে AuthorAttribution ক্লাস ব্যবহার করুন। অ্যাট্রিবিউশনে লেখকের নাম (displayName), তার Google Maps প্রোফাইলের URI (uri) এবং লেখকের ফটোর URI (photoURI) অন্তর্ভুক্ত থাকে। নিম্নলিখিত স্নিপেটটি কোনও জায়গার ফটোর জন্য displayName, uri এবং photoURI রিটার্ন করা দেখায়।

  let name = place.photos[0].authorAttributions[0].displayName;
  let url = place.photos[0].authorAttributions[0].uri;
  let authorPhoto = place.photos[0].authorAttributions[0].photoURI;