یافتن آدرس با مختصات به وسیله Google Maps API در لاراول

اکثر اوقات، نیاز داریم تا آدرس‌ها را در دیتابیس ذخیره کنیم و می‌خواهیم که به درستی ذخیره شوند. در این مقاله روش انجام این کار را در لاراول و با استفاده از Google Maps API می‌آموزیم.


یافتن آدرس با مختصات به وسیله Google Maps API در لاراول

شاید بهترین روش برای این که مطمئن شویم آدرس‌هایی که در دیتابیس ذخیره می‌شوند صحیح هستند، این است که فیلدهای ورودی در اختیار کاربران قرار دهیم که بتوانند در حین تایپ از قابلیت auto-complete استفاده کنند. در این مقاله از لیداوب روش انجام این کار را در لاراول خواهید آموخت. می‌خواهیم با Google Maps API یک "location picker" ایجاد کنیم. ابتدا تصویری از آنچه می‌خواهیم بسازیم را مشاهده کنید:

یافتن آدرس با مختصات به وسیله Google Maps API

فرم ما برای ایجاد کمپانی‌ها شامل چند مورد است:

- فیلد ورودی متنی برای آدرس که از طریق Google Maps API به صورت خودکار پر می‌شود

- Google Map تعبیه شده که وقتی کاربر، آدرس را از لیست انتخاب می‌کند، یک مارکر روی آدرس موجود بر نقشه قرار می‌دهد

- دو فیلد مخفی برای طول و عرض جغرافیایی که وقتی کاربر آدرسی را از لیست انتخاب می‌کند، به صورت خودکار پر می‌شود

مرحله اول: آماده کردن دیتابیس و مدل

فایل مایگریشن ما باید به صورت زیر باشد:

Schema::create('companies', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('address_address')->nullable();
    $table->double('address_latitude')->nullable();
    $table->double('address_longitude')->nullable();
    $table->timestamps();
});

همانطور که می‌بینید، سه ستون وجود دارد نه یک ستون. از میان این سه ستون، یکی برای رشته آدرس واقعی و دو تا برای مختصات جغرافیایی می‌باشند. ما همچنین آن‌ها را در مدل app/company.php به صورت قابل پر کردن، ایجاد کرده‌ایم:

class Company extends Model
{
    protected $fillable = [
        'name',
        'address_address',
        'address_latitude',
        'address_longitude',
    ];

در نهایت، ذخیره کردن این مقادیر بسیار ساده است. در واقع، CompaniesController ما به صورت زیر خواهد بود:

public function store(StoreCompanyRequest $request)
{
    abort_unless(\Gate::allows('company_create'), 403);
    $company = Company::create($request->all());
    return redirect()->route('admin.companies.index');
}

به عبارت دیگر، ما تمام فیلدهایی که درون فرم وجود دارند را پر کرده و نیز address_latitude و address_longitude به صورت خودکار پر می‌شوند که به زبان جاوا اسکریپت هستند.

مرحله دوم: آماده کردن Google Maps API

احتمالا این مرحله‌ای است که تمام مقالات آموزشی از آن عبور می‌کنند. چون ربطی به کدنویسی ندارد، بلکه مربوط به دسترسی به Google Maps API می‌باشد. برای استفاده از آن، باید یک اپلیکیشن در Google Developer Console ایجاد کرده و API‌های مربوط به Maps را فعال کنید. در ژوئن سال ۲۰۱۸، گوگل کاربری و قیمت گذاری API‌های نقشه را تغییر داد. در اصل، شما نمی‌توانید بدون فعال کردن گزینه پرداخت در Google Developer Console از Google API استفاده کنید. به عبارت دیگر، باید مشخصات کارت اعتباری خود را وارد کنید. در زمان نوشتن این مقاله، هزینه آن ۲۰۰ دلار به ازای هر ماه اعتبار رایگان است اما به محض اینکه این مدت تمام شود، قیمت‌ها بسیار بالا می‌رود. در اینجا، گرافی از یکی از پروژه‌ها را مشاهده می‌کنید. در سیزدهم ماه به انتهای مدت زمان اعتبار رایگان رسیده و از آنجا به بعد، قیمت‌ها بستگی به تعداد بازدیدکننده‌ای که صفحه را با استفاده از نقشه باز می‌کنند، دارد:

یافتن آدرس با مختصات به وسیله Google Maps API

این هم صورت حساب برای چهل هزار بازدید کننده در ماه:

یافتن آدرس با مختصات به وسیله Google Maps API

بنابراین، توصیه نهایی ما به شما این است:

- باید اطلاعات کارت اعتباری خود را برای استفاده از Google Maps API وارد کنید

- اما شدیدا مراقب استفاده از نقشه‌ها باشید چون ممکن است هزینه بالایی برای شما در پی داشته باشد

حالا اگر برای ادامه کار آماده هستید، باید کلید Google Maps API را به دست بیاورید. بنابراین، لازم است یک اپلیکیشن در Google Console ایجاد کرده و چند API را فعال کنید. برای انجام مثال موجود در این مقاله، باید سه API داشته باشید. در اینجا لیست را مشاهده می‌کنید:

یافتن آدرس با مختصات به وسیله Google Maps API

به مواردی که عددی هستند نگاه کنید. شما به موارد زیر نیاز دارید:

- Maps JavaScript API: برای نشان دادن نقشه تعبیه شده در صفحه

- Places API for Web: برای ایجاد قابلیت تکمیل خودکار برای آدرس‌ها

- Geocoding API: برای جستجوی طول و عرض جغرافیایی آدرس‌ها

حالا در این فرآیند باید کلید API خود را به دست آورید که کلید همه این‌ها است. ما آن را در فایل .env پروژه لاراول خود قرار می‌دهیم:

GOOGLE_MAPS_API_KEY=AIzaSyBi2dVBkdQSUcV8_uwwa**************

مرحله سوم: پر کردن آدرس ها و مختصات با جاوا اسکریپت

فرم ما در فایل resources/views/admin/companies/create.blade.php قرار دارد. فقط کدهای بخش مربوطه آورده شده است. فیلد آدرس باید به صورت زیر باشد:

<div class="form-group">
    <label for="address_address">Address</label>
    <input type="text" id="address-input" name="address_address" class="form-control map-input">
    <input type="hidden" name="address_latitude" id="address-latitude" value="0" />
    <input type="hidden" name="address_longitude" id="address-longitude" value="0" />
</div>
<div id="address-map-container" style="width:100%;height:400px; ">
    <div style="width: 100%; height: 100%" id="address-map"></div>
</div>

همانطور که قبلا گفته شد، در اینجا سه فیلد و یک کانتینر نقشه برای نمایش وجود دارد. حالا در انتهای این فایل Blade، این کد جاوا اسکرپیت را اضافه می‌کنیم:

@section('scripts')
    @parent
    <script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAPS_API_KEY') }}&libraries=places&callback=initialize" async defer></script>
    <script src="/js/mapInput.js"></script>
@stop

دیدید که کلید API خود را به فایل .env اضافه کردیم حالا در اینجا از آن استفاده می‌کنیم. برای این که این روش اجرا شود لازم است در فایل Blade خود یک بلوک @yield(‘scripts’) داشته باشیم. در نهایت، وارد فایل public/js/mapInput.js خود می‌شویم. کد کامل آن به این شکل است:

function initialize() {

    $('form').on('keyup keypress', function(e) {
        var keyCode = e.keyCode || e.which;
        if (keyCode === 13) {
            e.preventDefault();
            return false;
        }
    });
    const locationInputs = document.getElementsByClassName("map-input");

    const autocompletes = [];
    const geocoder = new google.maps.Geocoder;
    for (let i = 0; i < locationInputs.length; i++) {

        const input = locationInputs[i];
        const fieldKey = input.id.replace("-input", "");
        const isEdit = document.getElementById(fieldKey + "-latitude").value != '' && document.getElementById(fieldKey + "-longitude").value != '';

        const latitude = parseFloat(document.getElementById(fieldKey + "-latitude").value) || -33.8688;
        const longitude = parseFloat(document.getElementById(fieldKey + "-longitude").value) || 151.2195;

        const map = new google.maps.Map(document.getElementById(fieldKey + '-map'), {
            center: {lat: latitude, lng: longitude},
            zoom: 13
        });
        const marker = new google.maps.Marker({
            map: map,
            position: {lat: latitude, lng: longitude},
        });

        marker.setVisible(isEdit);

        const autocomplete = new google.maps.places.Autocomplete(input);
        autocomplete.key = fieldKey;
        autocompletes.push({input: input, map: map, marker: marker, autocomplete: autocomplete});
    }

    for (let i = 0; i < autocompletes.length; i++) {
        const input = autocompletes[i].input;
        const autocomplete = autocompletes[i].autocomplete;
        const map = autocompletes[i].map;
        const marker = autocompletes[i].marker;

        google.maps.event.addListener(autocomplete, 'place_changed', function () {
            marker.setVisible(false);
            const place = autocomplete.getPlace();

            geocoder.geocode({'placeId': place.place_id}, function (results, status) {
                if (status === google.maps.GeocoderStatus.OK) {
                    const lat = results[0].geometry.location.lat();
                    const lng = results[0].geometry.location.lng();
                    setLocationCoordinates(autocomplete.key, lat, lng);
                }
            });

            if (!place.geometry) {
                window.alert("No details available for input: '" + place.name + "'");
                input.value = "";
                return;
            }

            if (place.geometry.viewport) {
                map.fitBounds(place.geometry.viewport);
            } else {
                map.setCenter(place.geometry.location);
                map.setZoom(17);
            }
            marker.setPosition(place.geometry.location);
            marker.setVisible(true);

        });
    }
}

function setLocationCoordinates(key, lat, lng) {
    const latitudeField = document.getElementById(key + "-" + "latitude");
    const longitudeField = document.getElementById(key + "-" + "longitude");
    latitudeField.value = lat;
    longitudeField.value = lng;
}

این بخش نقشه را بارگذاری کرده و مارکر مرکزی را قرار می‌دهد:

const map = new google.maps.Map(document.getElementById(fieldKey + '-map'), {
            center: {lat: latitude, lng: longitude},
            zoom: 13
        });
const marker = new google.maps.Marker({
    map: map,
    position: {lat: latitude, lng: longitude},
});

این بخش مربوط به تکمیل خودکار آدرس است:

const autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.key = fieldKey;
autocompletes.push({input: input, map: map, marker: marker, autocomplete: autocomplete});

این قسمت هم مربوط به جستجوی طول و عرض جغرافیایی است:

geocoder.geocode({'placeId': place.place_id}, function (results, status) {
    if (status === google.maps.GeocoderStatus.OK) {

        const lat = results[0].geometry.location.lat();
        const lng = results[0].geometry.location.lng();

        setLocationCoordinates(autocomplete.key, lat, lng);
    }
});

مطالعه مقالات بیشتر در لیداوب:

برای کسب اطلاعات بیشتر و آموزش مثال‌های بیشتر می‌توانید از مستندات Google Maps API استفاده کنید. با استفاده از مقالات تخصصی ما در زمینه طراحی سایت و فریم ورک لاراول می‌توانید بهترین سایت‌ها را طراحی کرده و از آن‌ها در پیشبرد اهداف خود استفاده کنید.