Google মানচিত্র প্ল্যাটফর্ম এবং Google ক্লাউড সহ একটি সম্পূর্ণ স্ট্যাক স্টোর লোকেটার তৈরি করুন৷

1. ভূমিকা

বিমূর্ত

কল্পনা করুন যে আপনার কাছে একটি মানচিত্রে রাখার জন্য অনেক জায়গা আছে এবং আপনি চান যে ব্যবহারকারীরা এই জায়গাগুলি কোথায় তা দেখতে সক্ষম হন এবং তারা কোন জায়গাটি দেখতে চান তা চিহ্নিত করতে পারেন৷ এর সাধারণ উদাহরণগুলির মধ্যে রয়েছে:

  • একটি খুচরা বিক্রেতার ওয়েবসাইটে একটি দোকান লোকেটার
  • একটি আসন্ন নির্বাচনের জন্য পোলিং অবস্থানের মানচিত্র
  • ব্যাটারি রিসাইক্লিং রিসেপ্ট্যাকলের মতো বিশেষ অবস্থানের একটি ডিরেক্টরি

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি একটি লোকেটার তৈরি করবেন যা বিশেষায়িত অবস্থানের একটি লাইভ ডেটা ফিড থেকে আঁকে এবং ব্যবহারকারীকে তাদের সূচনা পয়েন্টের কাছাকাছি অবস্থান খুঁজে পেতে সহায়তা করে। এই পূর্ণ-স্ট্যাক লোকেটারটি সাধারণ স্টোর লোকেটারের চেয়ে অনেক বড় সংখ্যক স্থান পরিচালনা করতে পারে, যা 25 বা তার কম স্টোর অবস্থানের মধ্যে সীমাবদ্ধ।

2ece59c64c06e9da.png

আপনি কি শিখবেন

এই কোডল্যাবটি প্রচুর সংখ্যক স্টোর অবস্থান সম্পর্কে প্রাক-জনসংখ্যাযুক্ত মেটাডেটা অনুকরণ করতে একটি খোলা ডেটা সেট ব্যবহার করে যাতে আপনি মূল প্রযুক্তিগত ধারণাগুলি শেখার উপর ফোকাস করতে পারেন।

  • মানচিত্র জাভাস্ক্রিপ্ট API: একটি কাস্টমাইজ করা ওয়েব মানচিত্রে প্রচুর সংখ্যক অবস্থান প্রদর্শন করুন
  • GeoJSON: একটি বিন্যাস যা অবস্থান সম্পর্কে মেটাডেটা সংরক্ষণ করে
  • স্থান স্বয়ংসম্পূর্ণ: ব্যবহারকারীদের দ্রুত এবং আরও সঠিকভাবে শুরুর অবস্থানগুলি প্রদান করতে সহায়তা করুন৷
  • যান: ব্যাক-এন্ড অ্যাপ্লিকেশন বিকাশ করতে ব্যবহৃত প্রোগ্রামিং ভাষা। ব্যাকএন্ড ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করবে এবং ফরম্যাট JSON-এ ফ্রন্ট-এন্ডে কোয়েরির ফলাফল পাঠাবে।
  • অ্যাপ ইঞ্জিন: ওয়েব অ্যাপ হোস্ট করার জন্য

পূর্বশর্ত

  • HTML এবং JavaScript এর প্রাথমিক জ্ঞান
  • একটি Google অ্যাকাউন্ট

2. সেট আপ করুন

নিম্নলিখিত বিভাগের ধাপ 3-এ, এই কোডল্যাবের জন্য Maps JavaScript API , Places API , এবং Distance Matrix API সক্ষম করুন৷

Google Maps প্ল্যাটফর্ম দিয়ে শুরু করুন

আপনি যদি আগে Google মানচিত্র প্ল্যাটফর্ম ব্যবহার না করে থাকেন তবে Google মানচিত্র প্ল্যাটফর্মের সাথে শুরু করুন নির্দেশিকা অনুসরণ করুন বা নিম্নলিখিত পদক্ষেপগুলি সম্পূর্ণ করতে Google মানচিত্র প্ল্যাটফর্ম প্লেলিস্টের সাথে শুরু করুন:

  1. একটি বিলিং অ্যাকাউন্ট তৈরি করুন।
  2. একটি প্রকল্প তৈরি করুন।
  3. Google মানচিত্র প্ল্যাটফর্ম API এবং SDK সক্ষম করুন (আগের বিভাগে তালিকাভুক্ত)৷
  4. একটি API কী তৈরি করুন।

ক্লাউড শেল সক্রিয় করুন

এই কোডল্যাবে আপনি ক্লাউড শেল ব্যবহার করেন, Google ক্লাউডে চলমান একটি কমান্ড-লাইন পরিবেশ যা Google ক্লাউডে চলমান পণ্য এবং সংস্থানগুলিতে অ্যাক্সেস প্রদান করে, যাতে আপনি আপনার ওয়েব ব্রাউজার থেকে সম্পূর্ণরূপে আপনার প্রকল্প হোস্ট এবং চালাতে পারেন৷

ক্লাউড কনসোল থেকে ক্লাউড শেল সক্রিয় করতে, ক্লাউড শেল সক্রিয় করুন ক্লিক করুন 89665d8d348105cd.png (পরিবেশের সাথে সংযোগ স্থাপন এবং সংযোগের জন্য এটি শুধুমাত্র কয়েক মুহূর্ত নিতে হবে)।

5f504766b9b3be17.png

এটি সম্ভবত একটি প্রাথমিক ইন্টারস্টিশিয়াল দেখানোর পরে আপনার ব্রাউজারের নীচের অংশে একটি নতুন শেল খোলে৷

d3bb67d514893d1f.png

আপনার প্রকল্প নিশ্চিত করুন

একবার ক্লাউড শেলের সাথে সংযুক্ত হয়ে গেলে, আপনি দেখতে পাবেন যে আপনি ইতিমধ্যেই প্রমাণীকরণ করেছেন এবং সেটআপের সময় আপনি যে প্রজেক্ট আইডিটি বেছে নিয়েছেন সেটি ইতিমধ্যেই সেট করা আছে।

$ gcloud auth list
Credentialed Accounts:
ACTIVE  ACCOUNT
  *     <myaccount>@<mydomain>.com
$ gcloud config list project
[core]
project = <YOUR_PROJECT_ID>

যদি কোনো কারণে প্রকল্পটি সেট করা না থাকে, তাহলে নিম্নলিখিত কমান্ডটি চালান:

gcloud config set project <YOUR_PROJECT_ID>

AppEngine Flex API সক্ষম করুন৷

AppEngine Flex API কে ক্লাউড কনসোল থেকে ম্যানুয়ালি সক্ষম করতে হবে। এটি করা শুধুমাত্র API-কে সক্ষম করবে না বরং AppEngine নমনীয় পরিবেশ পরিষেবা অ্যাকাউন্ট তৈরি করবে, একটি প্রমাণীকৃত অ্যাকাউন্ট যা ব্যবহারকারীর পক্ষে Google পরিষেবাগুলির (যেমন SQL ডেটাবেস) সাথে ইন্টারঅ্যাক্ট করবে৷

3. হ্যালো, বিশ্ব

ব্যাকএন্ড: হ্যালো ওয়ার্ল্ড ইন গো

আপনার ক্লাউড শেল ইনস্ট্যান্সে, আপনি একটি গো অ্যাপ ইঞ্জিন ফ্লেক্স অ্যাপ তৈরি করে শুরু করবেন যা কোডল্যাবের বাকি অংশের ভিত্তি হিসেবে কাজ করবে।

ক্লাউড শেলের টুলবারে, একটি নতুন ট্যাবে একটি কোড এডিটর খুলতে ওপেন এডিটর বোতামে ক্লিক করুন। এই ওয়েব ভিত্তিক কোড এডিটর আপনাকে ক্লাউড শেল ইনস্ট্যান্সে সহজেই ফাইল সম্পাদনা করতে দেয়।

b63f7baad67b6601.png

এর পরে, সম্পাদক এবং টার্মিনালটিকে একটি নতুন ট্যাবে সরানোর জন্য নতুন উইন্ডোতে খুলুন আইকনে ক্লিক করুন।

3f6625ff8461c551.png

নতুন ট্যাবের নিচের টার্মিনালে, একটি নতুন austin-recycling ডিরেক্টরি তৈরি করুন।

mkdir -p austin-recycling && cd $_

এর পরে আপনি সবকিছু কাজ করছে তা নিশ্চিত করতে একটি ছোট Go App Engine অ্যাপ তৈরি করবেন। হ্যালো ওয়ার্ল্ড!

austin-recycling ডিরেক্টরিটি বাম দিকে সম্পাদকের ফোল্ডার তালিকাতেও উপস্থিত হওয়া উচিত। austin-recycling ডিরেক্টরিতে, app.yaml নামে একটি ফাইল তৈরি করুন। app.yaml ফাইলে নিম্নলিখিত বিষয়বস্তু রাখুন:

app.yaml

runtime: go
env: flex

manual_scaling:
  instances: 1
resources:
  cpu: 1
  memory_gb: 0.5
  disk_size_gb: 10

এই কনফিগারেশন ফাইলটি Go Flex রানটাইম ব্যবহার করার জন্য আপনার অ্যাপ ইঞ্জিন অ্যাপটিকে কনফিগার করে। এই ফাইলের কনফিগারেশন আইটেমগুলির অর্থ সম্পর্কে ব্যাকগ্রাউন্ড তথ্যের জন্য, Google অ্যাপ ইঞ্জিন গো স্ট্যান্ডার্ড এনভায়রনমেন্ট ডকুমেন্টেশন দেখুন।

এরপর, app.yaml ফাইলের পাশাপাশি একটি main.go ফাইল তৈরি করুন:

main.go

package main

import (
        "fmt"
        "log"
        "net/http"
        "os"
)

func main() {
        http.HandleFunc("/", handle)
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }
        log.Printf("Listening on port %s", port)
        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
}

func handle(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path != "/" {
                http.NotFound(w, r)
                return
        }
        fmt.Fprint(w, "Hello world!")
}

এই কোডটি কী করে তা বোঝার জন্য এখানে একটি মুহূর্ত বিরতি দেওয়া মূল্যবান, অন্তত একটি উচ্চ স্তরে৷ আপনি একটি প্যাকেজ main সংজ্ঞায়িত করেছেন যা পোর্ট 8080-এ একটি HTTP সার্ভার শোনার শুরু করে এবং "/" পাথের সাথে মিলে যাওয়া HTTP অনুরোধগুলির জন্য একটি হ্যান্ডলার ফাংশন নিবন্ধন করে।

হ্যান্ডলার ফাংশন, যাকে হাতের handler বলা হয়, টেক্সট স্ট্রিং লিখে দেয় "Hello, world!" . এই পাঠ্যটি আপনার ব্রাউজারে রিলে করা হবে, যেখানে আপনি এটি পড়তে সক্ষম হবেন৷ ভবিষ্যতের ধাপে আপনি এমন হ্যান্ডলার তৈরি করবেন যেগুলি সাধারণ হার্ড কোডেড স্ট্রিংয়ের পরিবর্তে জিওজেএসএন ডেটার সাথে সাড়া দেয়।

এই পদক্ষেপগুলি সম্পাদন করার পরে, আপনার এখন এমন একটি সম্পাদক থাকা উচিত যা দেখতে এইরকম:

2084fdd5ef594ece.png

এটা পরীক্ষা করে দেখুন

এই অ্যাপ্লিকেশনটি পরীক্ষা করতে, আপনি ক্লাউড শেল ইন্সট্যান্সের মধ্যে অ্যাপ ইঞ্জিন ডেভেলপমেন্ট সার্ভার চালাতে পারেন। ক্লাউড শেল কমান্ড লাইনে ফিরে যান এবং নিম্নলিখিতটি টাইপ করুন:

go run *.go

আপনি লোকালহোস্ট পোর্ট 8080-এ হ্যালো ওয়ার্ল্ড ওয়েব অ্যাপ শোনার সাথে, আপনি ক্লাউড শেল ইন্সট্যান্সে ডেভেলপমেন্ট সার্ভার চালাচ্ছেন এমন কিছু লগ আউটপুট লাইন দেখতে পাবেন।

4155fc1dc717ac67.png

এই মেনু আইটেমটিতে ক্লিক করলে আপনার ওয়েব ব্রাউজারে একটি নতুন ট্যাব খুলবে যেখানে "হ্যালো, বিশ্ব!" অ্যাপ ইঞ্জিন ডেভেলপমেন্ট সার্ভার থেকে পরিবেশিত।

পরবর্তী ধাপে আপনি এই অ্যাপে সিটি অফ অস্টিন রিসাইক্লিং ডেটা যোগ করবেন এবং এটিকে কল্পনা করা শুরু করবেন।

4. বর্তমান তথ্য পান

GeoJSON, GIS বিশ্বের ভাষা ফ্রাঙ্কা

পূর্ববর্তী ধাপে উল্লেখ করা হয়েছে যে আপনি আপনার Go কোডে হ্যান্ডলার তৈরি করবেন যা ওয়েব ব্রাউজারে GeoJSON ডেটা রেন্ডার করবে। কিন্তু GeoJSON কি?

জিওগ্রাফিক ইনফরমেশন সিস্টেম (জিআইএস) বিশ্বে, আমাদের কম্পিউটার সিস্টেমের মধ্যে ভৌগলিক সত্তা সম্পর্কে জ্ঞান যোগাযোগ করতে সক্ষম হতে হবে। মানচিত্র মানুষের পড়ার জন্য দুর্দান্ত, তবে কম্পিউটারগুলি সাধারণত তাদের ডেটা আরও সহজে হজম করা ফর্ম্যাটে পছন্দ করে।

GeoJSON হল ভৌগলিক ডেটা স্ট্রাকচার এনকোড করার একটি ফর্ম্যাট, যেমন অস্টিন, টেক্সাসে ড্রপ-অফ অবস্থানগুলির পুনর্ব্যবহারযোগ্য স্থানাঙ্কগুলি৷ GeoJSON কে RFC7946 নামে একটি ইন্টারনেট ইঞ্জিনিয়ারিং টাস্ক ফোর্স স্ট্যান্ডার্ডে প্রমিত করা হয়েছে। GeoJSON-কে JSON , JavaScript অবজেক্ট নোটেশনের পরিপ্রেক্ষিতে সংজ্ঞায়িত করা হয়েছে, যেটি নিজেই ECMA-404- এ প্রমিত ছিল, একই সংস্থা যা জাভাস্ক্রিপ্ট, Ecma ইন্টারন্যাশনালকে প্রমিত করেছে।

গুরুত্বপূর্ণ বিষয় হল GeoJSON হল ভৌগলিক জ্ঞান যোগাযোগের জন্য একটি ব্যাপকভাবে সমর্থিত তারের বিন্যাস। এই কোডল্যাব নিম্নলিখিত উপায়ে GeoJSON ব্যবহার করে:

  • অস্টিন ডেটাকে একটি অভ্যন্তরীণ GIS নির্দিষ্ট ডেটা কাঠামোতে পার্স করতে Go প্যাকেজগুলি ব্যবহার করুন যা আপনি অনুরোধ করা ডেটা ফিল্টার করতে ব্যবহার করবেন৷
  • ওয়েব সার্ভার এবং ওয়েব ব্রাউজারের মধ্যে ট্রানজিটের জন্য অনুরোধ করা ডেটা সিরিয়ালাইজ করুন।
  • ম্যাপে প্রতিক্রিয়াটিকে মার্কারগুলিতে রূপান্তর করতে একটি জাভাস্ক্রিপ্ট লাইব্রেরি ব্যবহার করুন৷

এটি আপনাকে কোডে টাইপ করার উল্লেখযোগ্য পরিমাণ সংরক্ষণ করবে, কারণ অন-দ্য-ওয়্যার ডেটাস্ট্রিমকে ইন-মেমরি উপস্থাপনায় রূপান্তর করতে আপনাকে পার্সার এবং জেনারেটর লিখতে হবে না।

ডেটা পুনরুদ্ধার করুন

অস্টিন সিটি, টেক্সাস ওপেন ডেটা পোর্টাল জনসাধারণের ব্যবহারের জন্য জনসাধারণের সম্পদ সম্পর্কে ভূ-স্থানিক তথ্য উপলব্ধ করে। এই কোডল্যাবে, আপনি রিসাইক্লিং ড্রপ-অফ অবস্থানের ডেটা সেট কল্পনা করবেন।

ম্যাপ জাভাস্ক্রিপ্ট API-এর ডেটা লেয়ার ব্যবহার করে রেন্ডার করা ম্যাপে মার্কার দিয়ে ডেটা ভিজ্যুয়ালাইজ করবেন।

আপনার অ্যাপে সিটি অফ অস্টিন ওয়েবসাইট থেকে GeoJSON ডেটা ডাউনলোড করে শুরু করুন।

  1. আপনার ক্লাউড শেল ইনস্ট্যান্সের কমান্ড লাইন উইন্ডোতে, [CTRL] + [C] লিখে সার্ভারটি বন্ধ করুন।
  2. austin-recycling ডিরেক্টরির ভিতরে একটি data ডিরেক্টরি তৈরি করুন এবং সেই ডিরেক্টরিতে পরিবর্তন করুন:
mkdir -p data && cd data

এখন পুনর্ব্যবহারযোগ্য অবস্থানগুলি পুনরুদ্ধার করতে কার্ল ব্যবহার করুন:

curl "https://data.austintexas.gov/resource/qzi7-nx8g.geojson" -o recycling-locations.geojson

অবশেষে, প্যারেন্ট ডিরেক্টরিতে ব্যাক আপ পরিবর্তন করুন।

cd ..

5. অবস্থানগুলি ম্যাপ করুন

প্রথমে, app.yaml ফাইলটি আপডেট করুন যাতে আপনি আরও শক্তিশালী, "শুধু একটি হ্যালো ওয়ার্ল্ড অ্যাপ আর নয়" অ্যাপ্লিকেশনটি তৈরি করতে চলেছেন।

app.yaml

runtime: go
env: flex

handlers:
- url: /
  static_files: static/index.html
  upload: static/index.html
- url: /(.*\.(js|html|css))$
  static_files: static/\1
  upload: static/.*\.(js|html|css)$
- url: /.*
  script: auto

manual_scaling:
  instances: 1
resources:
  cpu: 1
  memory_gb: 0.5
  disk_size_gb: 10

এই app.yaml কনফিগারেশন / , /*.js , /*.css এবং /*.html এর জন্য অনুরোধগুলিকে স্ট্যাটিক ফাইলের সেটে নির্দেশ করে। এর মানে হল যে আপনার অ্যাপের স্ট্যাটিক এইচটিএমএল উপাদান সরাসরি অ্যাপ ইঞ্জিন ফাইল পরিবেশন পরিকাঠামো দ্বারা পরিবেশিত হবে, আপনার Go অ্যাপে নয়। এটি সার্ভারের লোড হ্রাস করে এবং পরিবেশন গতি বাড়ায়।

এখন গো-তে আপনার অ্যাপ্লিকেশনের ব্যাকএন্ড তৈরি করার সময়!

পিছনের প্রান্তটি তৈরি করুন

আপনি হয়তো লক্ষ্য করেছেন, একটি আকর্ষণীয় জিনিস আপনার app.yaml ফাইলটি করে না তা হল GeoJSON ফাইলটি প্রকাশ করা। এর কারণ হল GeoJSON প্রক্রিয়া করা হবে এবং আমাদের গো ব্যাকএন্ড দ্বারা পাঠানো হবে, আমাদের পরবর্তী ধাপে কিছু অভিনব বৈশিষ্ট্য তৈরি করতে দেয়। নিচের মত পড়তে আপনার main.go ফাইল পরিবর্তন করুন:

main.go

package main

import (
        "fmt"
        "log"
        "net/http"
        "os"
        "path/filepath"
)

var GeoJSON = make(map[string][]byte)

// cacheGeoJSON loads files under data into `GeoJSON`.
func cacheGeoJSON() {
        filenames, err := filepath.Glob("data/*")
        if err != nil {
                log.Fatal(err)
        }

        for _, f := range filenames {
                name := filepath.Base(f)
                dat, err := os.ReadFile(f)
                if err != nil {
                        log.Fatal(err)
                }
                GeoJSON[name] = dat
        }
}

func main() {
        // Cache the JSON so it doesn't have to be reloaded every time a request is made.
        cacheGeoJSON()


        // Request for data should be handled by Go.  Everything else should be directed
        // to the folder of static files.
        http.HandleFunc("/data/dropoffs", dropoffsHandler)
        http.Handle("/", http.FileServer(http.Dir("./static/")))

        // Open up a port for the webserver.
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }
        log.Printf("Listening on port %s", port)

        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
        // Writes Hello, World! to the user's web browser via `w`
        fmt.Fprint(w, "Hello, world!")
}

func dropoffsHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-type", "application/json")
        w.Write(GeoJSON["recycling-locations.geojson"])
}

ইতিমধ্যেই গো ব্যাকএন্ড আমাদের একটি মূল্যবান বৈশিষ্ট্য দিচ্ছে: অ্যাপইঞ্জিন ইনস্ট্যান্স শুরু হওয়ার সাথে সাথে সেই সমস্ত অবস্থানগুলিকে ক্যাশ করছে। এটি সময় সাশ্রয় করে কারণ ব্যাকএন্ডকে প্রত্যেক ব্যবহারকারীর কাছ থেকে প্রতি রিফ্রেশে ডিস্ক থেকে ফাইলটি পড়তে হবে না!

সামনের প্রান্তটি তৈরি করুন

আমাদের যা করতে হবে তা হল আমাদের সমস্ত স্ট্যাটিক সম্পদগুলিকে ধরে রাখার জন্য একটি ফোল্ডার তৈরি করা। আপনার প্রকল্পের মূল ফোল্ডার থেকে, একটি static ফোল্ডার তৈরি করুন।

mkdir -p static && cd static

আমরা এই ফোল্ডারে 3টি ফাইল তৈরি করতে যাচ্ছি।

  • index.html আপনার এক-পৃষ্ঠার স্টোর লোকেটার অ্যাপের জন্য সমস্ত HTML ধারণ করবে।
  • style.css , যেমন আপনি আশা করেন, স্টাইলিং ধারণ করবে
  • app.js GeoJSON পুনরুদ্ধার করার জন্য, Maps API এ কল করার জন্য এবং আপনার কাস্টম মানচিত্রে মার্কার স্থাপনের জন্য দায়ী থাকবে।

এই 3টি ফাইল তৈরি করুন, তাদের static/ এ রাখা নিশ্চিত করুন।

style.css

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

body {
  display: flex;
}

#map {
  height: 100%;
  flex-grow: 4;
  flex-basis: auto;
}

index.html

<html>
  <head>
    <title>Austin recycling drop-off locations</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script src="app.js"></script>

    <script
      defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=weekly&libraries=places&callback=initialize&solution_channel=GMP_codelabs_fullstackstorelocator_v1_a"
    ></script>
  </head>

  <body>
    <div id="map"></div>
    <!-- Autocomplete div goes here -->
  </body>
</html>

head এলিমেন্টের স্ক্রিপ্ট ট্যাগে src URL-এ বিশেষ মনোযোগ দিন।

  • প্লেসহোল্ডার টেক্সট " YOUR_API_KEY " প্রতিস্থাপন করুন সেটআপ ধাপের সময় আপনার তৈরি করা API কী দিয়ে। আপনি আপনার API কী পুনরুদ্ধার করতে বা একটি নতুন তৈরি করতে ক্লাউড কনসোলে API এবং পরিষেবা -> শংসাপত্র পৃষ্ঠাতে যেতে পারেন৷
  • মনে রাখবেন যে URL-এ callback=initialize. আমরা এখন সেই কলব্যাক ফাংশন ধারণকারী জাভাস্ক্রিপ্ট ফাইল তৈরি করতে যাচ্ছি। এখানেই আপনার অ্যাপটি ব্যাকএন্ড থেকে অবস্থানগুলি লোড করবে, সেগুলিকে মানচিত্র API এ পাঠাবে এবং মানচিত্রে কাস্টম অবস্থানগুলি চিহ্নিত করতে ফলাফলটি ব্যবহার করবে, যা আপনার ওয়েব পৃষ্ঠায় সুন্দরভাবে রেন্ডার করা হয়েছে৷
  • পরামিতি libraries=places স্থান লাইব্রেরি লোড করে, যা ঠিকানা স্বয়ংসম্পূর্ণতার মতো বৈশিষ্ট্যগুলির জন্য প্রয়োজনীয় যা পরে যোগ করা হবে।

app.js

let distanceMatrixService;
let map;
let originMarker;
let infowindow;
let circles = [];
let stores = [];
// The location of Austin, TX
const AUSTIN = { lat: 30.262129, lng: -97.7468 };

async function initialize() {
  initMap();

  // TODO: Initialize an infoWindow

  // Fetch and render stores as circles on map
  fetchAndRenderStores(AUSTIN);

  // TODO: Initialize the Autocomplete widget
}

const initMap = () => {
  // TODO: Start Distance Matrix service

  // The map, centered on Austin, TX
  map = new google.maps.Map(document.querySelector("#map"), {
    center: AUSTIN,
    zoom: 14,
    // mapId: 'YOUR_MAP_ID_HERE',
    clickableIcons: false,
    fullscreenControl: false,
    mapTypeControl: false,
    rotateControl: true,
    scaleControl: false,
    streetViewControl: true,
    zoomControl: true,
  });
};

const fetchAndRenderStores = async (center) => {
  // Fetch the stores from the data source
  stores = (await fetchStores(center)).features;

  // Create circular markers based on the stores
  circles = stores.map((store) => storeToCircle(store, map));
};

const fetchStores = async (center) => {
  const url = `/data/dropoffs`;
  const response = await fetch(url);
  return response.json();
};

const storeToCircle = (store, map) => {
  const [lng, lat] = store.geometry.coordinates;
  const circle = new google.maps.Circle({
    radius: 50,
    strokeColor: "#579d42",
    strokeOpacity: 0.8,
    strokeWeight: 5,
    center: { lat, lng },
    map,
  });

  return circle;
};

এই কোড একটি মানচিত্রে দোকান অবস্থান রেন্ডার. আমাদের এখন পর্যন্ত যা আছে তা পরীক্ষা করতে, কমান্ড লাইন থেকে মূল ডিরেক্টরিতে ফিরে যান:

cd ..

এখন, এটি ব্যবহার করে আবার ডেভেলপমেন্ট মোডে আপনার অ্যাপ চালান:

go run *.go

আপনি আগের মত এটি পূর্বরূপ. আপনি এই মত ছোট সবুজ বৃত্ত সঙ্গে একটি মানচিত্র দেখতে হবে.

58a6680e9c8e7396.png

আপনি ইতিমধ্যেই মানচিত্রের অবস্থানগুলি রেন্ডার করছেন, এবং আমরা কোডল্যাবের অর্ধেক পথের মধ্যেই আছি! আশ্চর্যজনক। এখন কিছু ইন্টারঅ্যাকটিভিটি যোগ করা যাক।

6. চাহিদা অনুযায়ী বিস্তারিত দেখান

ম্যাপ মার্কারগুলিতে ক্লিক ইভেন্টগুলিতে সাড়া দিন

মানচিত্রে একগুচ্ছ মার্কার প্রদর্শন করা একটি দুর্দান্ত সূচনা, কিন্তু সেই মার্কারগুলির একটিতে ক্লিক করতে এবং সেই অবস্থান (যেমন ব্যবসার নাম, ঠিকানা ইত্যাদি) সম্পর্কে তথ্য দেখতে সক্ষম হওয়ার জন্য আমাদের সত্যিই একজন দর্শকের প্রয়োজন৷ আপনি যখন Google Maps মার্কারে ক্লিক করেন তখন সাধারণত যে ছোট তথ্য উইন্ডোটি পপ আপ হয় তার নাম হল একটি তথ্য উইন্ডো

একটি infoWindow অবজেক্ট তৈরি করুন। initialize ফাংশনে নিম্নলিখিতটি যোগ করুন, মন্তব্য করা লাইনটি প্রতিস্থাপন করুন যেখানে লেখা আছে " // TODO: Initialize an info window "।

app.js - আরম্ভ করুন

  // Add an info window that pops up when user clicks on an individual
  // location. Content of info window is entirely up to us.
  infowindow = new google.maps.InfoWindow();

এই সামান্য ভিন্ন সংস্করণের সাথে fetchAndRenderStores ফাংশন সংজ্ঞা প্রতিস্থাপন করুন, যা একটি অতিরিক্ত যুক্তি, infowindow সহ storeToCircle কল করার চূড়ান্ত লাইন পরিবর্তন করে:

app.js - fetchAndRenderStores

const fetchAndRenderStores = async (center) => {
  // Fetch the stores from the data source
  stores = (await fetchStores(center)).features;

  // Create circular markers based on the stores
  circles = stores.map((store) => storeToCircle(store, map, infowindow));
};

storeToCircle সংজ্ঞাটিকে এই সামান্য দীর্ঘ সংস্করণের সাথে প্রতিস্থাপন করুন, যা এখন তৃতীয় যুক্তি হিসাবে একটি তথ্য উইন্ডো নেয়:

app.js - storeToCircle

const storeToCircle = (store, map, infowindow) => {
  const [lng, lat] = store.geometry.coordinates;
  const circle = new google.maps.Circle({
    radius: 50,
    strokeColor: "#579d42",
    strokeOpacity: 0.8,
    strokeWeight: 5,
    center: { lat, lng },
    map,
  });
  circle.addListener("click", () => {
    infowindow.setContent(`${store.properties.business_name}<br />
      ${store.properties.address_address}<br />
      Austin, TX ${store.properties.zip_code}`);
    infowindow.setPosition({ lat, lng });
    infowindow.setOptions({ pixelOffset: new google.maps.Size(0, -30) });
    infowindow.open(map);
  });
  return circle;
};

উপরের নতুন কোডটি নির্বাচিত স্টোরের তথ্য সহ একটি infoWindow প্রদর্শন করে যখনই মানচিত্রে একটি স্টোর মার্কার ক্লিক করা হয়।

আপনার সার্ভার এখনও চলমান থাকলে, এটি বন্ধ করুন এবং এটি পুনরায় চালু করুন। আপনার মানচিত্র পৃষ্ঠা রিফ্রেশ করুন এবং একটি মানচিত্র চিহ্নিতকারীতে ক্লিক করার চেষ্টা করুন। একটি ছোট তথ্য উইন্ডো ব্যবসার নাম এবং ঠিকানা সহ পপ আপ করা উচিত, এই মত কিছু দেখতে:

1af0ab72ad0eadc5.png

7. ব্যবহারকারীর শুরুর অবস্থান পান

স্টোর লোকেটার ব্যবহারকারীরা সাধারণত জানতে চায় কোন দোকান তাদের সবচেয়ে কাছের বা কোন ঠিকানা যেখানে তারা তাদের যাত্রা শুরু করার পরিকল্পনা করছে। ব্যবহারকারীকে সহজে একটি প্রারম্ভিক ঠিকানা লিখতে অনুমতি দিতে একটি স্থান স্বয়ংসম্পূর্ণ অনুসন্ধান বার যুক্ত করুন৷ প্লেস স্বয়ংসম্পূর্ণ অন্যান্য Google সার্চ বারে যেভাবে স্বয়ংসম্পূর্ণ কাজ করে তার অনুরূপ টাইপহেড কার্যকারিতা প্রদান করে, ভবিষ্যদ্বাণীগুলি ব্যতীত সমস্ত স্থানগুলি Google মানচিত্র প্ল্যাটফর্মে।

একটি ব্যবহারকারী ইনপুট ক্ষেত্র তৈরি করুন

স্বয়ংসম্পূর্ণ অনুসন্ধান বার এবং ফলাফলের সংশ্লিষ্ট পার্শ্ব প্যানেলের জন্য স্টাইলিং যোগ করতে style.css সম্পাদনায় ফিরে যান। আমরা যখন CSS শৈলীগুলি আপডেট করছি, তখন আমরা ভবিষ্যতের সাইডবারের জন্য শৈলীগুলিও যুক্ত করব যা স্টোরের তথ্যকে মানচিত্রের সাথে একটি তালিকা হিসাবে প্রদর্শন করে৷

ফাইলের শেষে এই কোডটি যোগ করুন।

style.css

#panel {
  height: 100%;
  flex-basis: 0;
  flex-grow: 0;
  overflow: auto;
  transition: all 0.2s ease-out;
}

#panel.open {
  flex-basis: auto;
}

#panel .place {
  font-family: "open sans", arial, sans-serif;
  font-size: 1.2em;
  font-weight: 500;
  margin-block-end: 0px;
  padding-left: 18px;
  padding-right: 18px;
}

#panel .distanceText {
  color: silver;
  font-family: "open sans", arial, sans-serif;
  font-size: 1em;
  font-weight: 400;
  margin-block-start: 0.25em;
  padding-left: 18px;
  padding-right: 18px;
}

/* Styling for Autocomplete search bar */
#pac-card {
  background-color: #fff;
  border-radius: 2px 0 0 2px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
  font-family: Roboto;
  margin: 10px 10px 0 0;
  -moz-box-sizing: border-box;
  outline: none;
}

#pac-container {
  padding-top: 12px;
  padding-bottom: 12px;
  margin-right: 12px;
}

#pac-input {
  background-color: #fff;
  font-family: Roboto;
  font-size: 15px;
  font-weight: 300;
  margin-left: 12px;
  padding: 0 11px 0 13px;
  text-overflow: ellipsis;
  width: 400px;
}

#pac-input:focus {
  border-color: #4d90fe;
}

#pac-title {
  color: #fff;
  background-color: #acbcc9;
  font-size: 18px;
  font-weight: 400;
  padding: 6px 12px;
}

.hidden {
  display: none;
}

স্বয়ংসম্পূর্ণ অনুসন্ধান বার এবং স্লাইডআউট প্যানেল উভয়ই প্রাথমিকভাবে লুকানো থাকে যতক্ষণ না তাদের প্রয়োজন হয়।

স্বয়ংসম্পূর্ণ উইজেটের জন্য একটি div প্রস্তুত করুন index.html-এ মন্তব্যটি প্রতিস্থাপন করে যেখানে লেখা আছে "<!-- Autocomplete div goes here --> " নিচের কোড দিয়ে। এই সম্পাদনা করার সময়, আমরা স্লাইড আউট প্যানেলের জন্য ডিভ যোগ করব।

index.html

     <div id="panel" class="closed"></div>
     <div class="hidden">
      <div id="pac-card">
        <div id="pac-title">Find the nearest location</div>
        <div id="pac-container">
          <input
            id="pac-input"
            type="text"
            placeholder="Enter an address"
            class="pac-target-input"
            autocomplete="off"
          />
        </div>
      </div>
    </div>

এখন, app.js এর শেষে নিম্নলিখিত কোড যোগ করে মানচিত্রে স্বয়ংসম্পূর্ণ উইজেট যোগ করার জন্য একটি ফাংশন সংজ্ঞায়িত করুন।

app.js

const initAutocompleteWidget = () => {
  // Add search bar for auto-complete
  // Build and add the search bar
  const placesAutoCompleteCardElement = document.getElementById("pac-card");
  const placesAutoCompleteInputElement = placesAutoCompleteCardElement.querySelector(
    "input"
  );
  const options = {
    types: ["address"],
    componentRestrictions: { country: "us" },
    map,
  };
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(
    placesAutoCompleteCardElement
  );
  // Make the search bar into a Places Autocomplete search bar and select
  // which detail fields should be returned about the place that
  // the user selects from the suggestions.
  const autocomplete = new google.maps.places.Autocomplete(
    placesAutoCompleteInputElement,
    options
  );
  autocomplete.setFields(["address_components", "geometry", "name"]);
  map.addListener("bounds_changed", () => {
    autocomplete.setBounds(map.getBounds());
  });

  // TODO: Respond when a user selects an address
};

কোডটি স্বয়ংসম্পূর্ণ পরামর্শগুলিকে শুধুমাত্র ঠিকানা ফেরাতে সীমাবদ্ধ করে (কারণ স্থান স্বয়ংসম্পূর্ণ প্রতিষ্ঠানের নাম এবং প্রশাসনিক অবস্থানগুলির সাথেও মিলতে পারে) এবং শুধুমাত্র মার্কিন যুক্তরাষ্ট্রে ফিরে আসা ঠিকানাগুলিকে সীমাবদ্ধ করে৷ এই ঐচ্ছিক স্পেসিফিকেশনগুলি যোগ করা হলে ব্যবহারকারীকে যে ঠিকানাটি খুঁজছেন তা দেখানোর জন্য ভবিষ্যদ্বাণীগুলিকে সংকুচিত করার জন্য অক্ষরের সংখ্যা কমিয়ে দেবে৷

তারপরে, এটি আপনার তৈরি করা স্বয়ংসম্পূর্ণ div মানচিত্রের উপরের-ডান কোণায় নিয়ে যায় এবং প্রতিক্রিয়াতে প্রতিটি স্থান সম্পর্কে কোন ক্ষেত্রগুলি ফেরত দেওয়া উচিত তা নির্দিষ্ট করে।

অবশেষে, initialize ফাংশনের শেষে initAutocompleteWidget ফাংশনটিকে কল করুন, " // TODO: Initialize the Autocomplete widget " লেখা মন্তব্যটি প্রতিস্থাপন করুন।

app.js - আরম্ভ করুন

 // Initialize the Places Autocomplete Widget
 initAutocompleteWidget();

নিম্নলিখিত কমান্ড চালিয়ে আপনার সার্ভার পুনরায় চালু করুন, তারপর আপনার পূর্বরূপ রিফ্রেশ করুন।

go run *.go

আপনি এখন আপনার মানচিত্রের উপরের-ডানদিকে একটি স্বয়ংসম্পূর্ণ উইজেট দেখতে পাবেন, যা আপনাকে দেখায় যে আপনি যা টাইপ করেন তার সাথে মিলে যাওয়া মার্কিন ঠিকানাগুলি, মানচিত্রের দৃশ্যমান এলাকার দিকে পক্ষপাতদুষ্ট।

58e9bbbcc4bf18d1.png

ব্যবহারকারী একটি প্রারম্ভিক ঠিকানা নির্বাচন করলে মানচিত্রটি আপডেট করুন

এখন, ব্যবহারকারী যখন স্বয়ংসম্পূর্ণ উইজেট থেকে একটি ভবিষ্যদ্বাণী নির্বাচন করে তখন আপনাকে পরিচালনা করতে হবে এবং আপনার স্টোরের দূরত্ব গণনা করার জন্য সেই অবস্থানটিকে ভিত্তি হিসাবে ব্যবহার করতে হবে।

app.jsinitAutocompleteWidget এর শেষে নিম্নলিখিত কোডটি যোগ করুন, মন্তব্যটি প্রতিস্থাপন করুন " // TODO: Respond when a user selects an address "।

app.js - initAutocompleteWidget

  // Respond when a user selects an address
  // Set the origin point when the user selects an address
  originMarker = new google.maps.Marker({ map: map });
  originMarker.setVisible(false);
  let originLocation = map.getCenter();
  autocomplete.addListener("place_changed", async () => {
    // circles.forEach((c) => c.setMap(null)); // clear existing stores
    originMarker.setVisible(false);
    originLocation = map.getCenter();
    const place = autocomplete.getPlace();

    if (!place.geometry) {
      // User entered the name of a Place that was not suggested and
      // pressed the Enter key, or the Place Details request failed.
      window.alert("No address available for input: '" + place.name + "'");
      return;
    }
    // Recenter the map to the selected address
    originLocation = place.geometry.location;
    map.setCenter(originLocation);
    map.setZoom(15);
    originMarker.setPosition(originLocation);
    originMarker.setVisible(true);

    // await fetchAndRenderStores(originLocation.toJSON());
    // TODO: Calculate the closest stores
  });

কোডটি একজন শ্রোতাকে যুক্ত করে যাতে ব্যবহারকারী যখন একটি পরামর্শে ক্লিক করেন, তখন মানচিত্রটি নির্বাচিত ঠিকানায় রিসেন্টার করে এবং আপনার দূরত্ব গণনার ভিত্তি হিসাবে উত্স সেট করে। আপনি একটি ভবিষ্যত ধাপে দূরত্ব গণনা বাস্তবায়ন করুন।

বন্ধ করুন এবং আপনার সার্ভার পুনরায় চালু করুন এবং স্বয়ংসম্পূর্ণ অনুসন্ধান বারে একটি ঠিকানা ইনপুট করার পরে মানচিত্র পুনরায় কেন্দ্রীভূত করার জন্য আপনার পূর্বরূপ রিফ্রেশ করুন।

8. ক্লাউড এসকিউএল দিয়ে স্কেল করুন

এখনও অবধি, আমাদের কাছে একটি দুর্দান্ত স্টোর লোকেটার রয়েছে। এটি ব্যাকএন্ডে মেমরিতে লোড করে (ফাইল থেকে বারবার পড়ার পরিবর্তে) অ্যাপটি ব্যবহার করবে এমন প্রায় একশটি অবস্থানের সুবিধা নেয়। কিন্তু যদি আপনার লোকেটারকে ভিন্ন স্কেলে কাজ করতে হয়? আপনার যদি একটি বৃহৎ ভৌগলিক এলাকা (অথবা সারা বিশ্বে হাজার হাজার) চারপাশে ছড়িয়ে ছিটিয়ে থাকা শতাধিক অবস্থান থাকে, তবে সেই সমস্ত অবস্থানগুলিকে মেমরিতে রাখা আর সেরা ধারণা নয়, এবং পৃথক ফাইলগুলিতে জোনগুলি ভেঙে দেওয়া তার নিজস্ব সমস্যাগুলি প্রবর্তন করতে চলেছে।

এটি একটি ডাটাবেস থেকে আপনার অবস্থান লোড করার সময়. এই পদক্ষেপের জন্য আমরা আপনার জিওজেএসএন ফাইলের সমস্ত অবস্থানগুলিকে একটি ক্লাউড এসকিউএল ডাটাবেসে স্থানান্তর করতে যাচ্ছি, এবং যখনই কোনও অনুরোধ আসে তখনই সেই ডাটাবেসের পরিবর্তে স্থানীয় ক্যাশে থেকে ফলাফলগুলি টেনে আনতে Go ব্যাকএন্ড আপডেট করব৷

পোস্টগ্রেস ডাটাবেসের সাথে একটি ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করুন

আপনি Google ক্লাউড কনসোলের মাধ্যমে একটি ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করতে পারেন, তবে কমান্ড লাইন থেকে একটি তৈরি করতে gcloud ইউটিলিটি ব্যবহার করা আরও সহজ। ক্লাউড শেলে, নিম্নলিখিত কমান্ডের সাহায্যে একটি ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করুন:

gcloud sql instances create locations \
--database-version=POSTGRES_12 \
--tier=db-custom-1-3840 --region=us-central1
  • ক্লাউড এসকিউএল-এর এই উদাহরণ দিতে আমরা যে নামটি বেছে নিয়েছি তা হল আর্গুমেন্ট locations
  • tier পতাকা হল কিছু সুবিধাজনকভাবে পূর্ব-সংজ্ঞায়িত মেশিন থেকে নির্বাচন করার একটি উপায়।
  • মান db-custom-1-3840 নির্দেশ করে যে উদাহরণ তৈরি করা হচ্ছে তার একটি vCPU এবং প্রায় 3.75GB মেমরি থাকা উচিত।

ক্লাউড এসকিউএল ইনস্ট্যান্স তৈরি করা হবে এবং একটি PostGresSQL ডাটাবেস দিয়ে শুরু করা হবে, ডিফল্ট ব্যবহারকারী postgres সহ। এই ব্যবহারকারীর পাসওয়ার্ড কি? দারুণ প্রশ্ন! তাদের একটা নেই। আপনি লগ ইন করার আগে আপনাকে একটি কনফিগার করতে হবে৷

নিম্নলিখিত কমান্ড দিয়ে পাসওয়ার্ড সেট করুন:

gcloud sql users set-password postgres \
    --instance=locations --prompt-for-password

তারপর আপনার নির্বাচিত পাসওয়ার্ড লিখুন যখন এটি করতে বলা হবে।

পোস্টজিআইএস এক্সটেনশন সক্ষম করুন

PostGIS হল PostGresSQL-এর জন্য একটি এক্সটেনশন যা মানসম্মত ধরনের ভূ-স্থানিক ডেটা সংরক্ষণ করা সহজ করে তোলে। সাধারণ পরিস্থিতিতে আমাদের ডাটাবেসে PostGIS যোগ করার জন্য আমাদের একটি সম্পূর্ণ ইনস্টলেশন প্রক্রিয়ার মধ্য দিয়ে যেতে হবে। সৌভাগ্যবশত, এটি PostGresSQL-এর জন্য ক্লাউড এসকিউএল-এর সমর্থিত এক্সটেনশনগুলির মধ্যে একটি।

ক্লাউড শেল টার্মিনালে নিম্নলিখিত কমান্ডটি ব্যবহার করে ব্যবহারকারী postgres সাথে সাথে লগ ইন করে ডাটাবেস ইনস্ট্যান্সের সাথে সংযোগ করুন।

gcloud sql connect locations --user=postgres --quiet

আপনার তৈরি পাসওয়ার্ড লিখুন. এখন postgres=> কমান্ড প্রম্পটে PostGIS এক্সটেনশন যোগ করুন।

CREATE EXTENSION postgis;

সফল হলে, আউটপুটটি ক্রিয়েট এক্সটেনশন পড়তে হবে, যেমনটি নীচে দেখানো হয়েছে।

কমান্ড আউটপুট উদাহরণ

CREATE EXTENSION

অবশেষে, postgres=> কমান্ড প্রম্পটে quit কমান্ড প্রবেশ করে ডাটাবেস সংযোগ প্রস্থান করুন।

\q

ডাটাবেসে ভৌগলিক ডেটা আমদানি করুন

এখন আমাদের নতুন ডাটাবেসে GeoJSON ফাইলগুলি থেকে সেই সমস্ত অবস্থানের ডেটা আমদানি করতে হবে।

সৌভাগ্যবশত, এটি একটি ভাল ভ্রমণের সমস্যা এবং আপনার জন্য এটি স্বয়ংক্রিয় করার জন্য ইন্টারনেটে বেশ কয়েকটি সরঞ্জাম পাওয়া যেতে পারে। আমরা ogr2ogr নামক একটি টুল ব্যবহার করতে যাচ্ছি যা ভূ-স্থানিক ডেটা সংরক্ষণের জন্য একাধিক সাধারণ ফর্ম্যাটের মধ্যে রূপান্তরিত করে। এই বিকল্পগুলির মধ্যে, হ্যাঁ, আপনি এটি অনুমান করেছেন, একটি SQL ডাম্প ফাইলে GeoJSON রূপান্তর করা। SQL ডাম্প ফাইলটি ডাটাবেসের জন্য আপনার টেবিল এবং কলাম তৈরি করতে ব্যবহার করা যেতে পারে এবং আপনার জিওজেএসএন ফাইলে বিদ্যমান সমস্ত ডেটা দিয়ে এটি লোড করতে পারে।

এসকিউএল ডাম্প ফাইল তৈরি করুন

প্রথমে ogr2ogr ইন্সটল করুন।

sudo apt-get install gdal-bin

এরপর, SQL ডাম্প ফাইল তৈরি করতে ogr2ogr ব্যবহার করুন। এই ফাইলটি austinrecycling নামে একটি টেবিল তৈরি করবে।

ogr2ogr --config PG_USE_COPY YES -f PGDump datadump.sql \
data/recycling-locations.geojson -nln austinrecycling

উপরের কমান্ডটি austin-recycling ফোল্ডার থেকে চালানোর উপর ভিত্তি করে। আপনার যদি অন্য ডিরেক্টরি থেকে এটি চালানোর প্রয়োজন হয়, যেখানে recycling-locations.geojson সংরক্ষণ করা হয় সেই ডিরেক্টরির পাথ দিয়ে data প্রতিস্থাপন করুন।

পুনর্ব্যবহারযোগ্য অবস্থানের সাথে আপনার ডাটাবেস পপুলেট করুন

সেই শেষ কমান্ডটি সম্পন্ন করার পরে, আপনার এখন একটি ফাইল থাকা উচিত, datadump.sql, একই ডিরেক্টরিতে যেখানে আপনি কমান্ডটি চালান। আপনি এটি খুললে আপনি এসকিউএল-এর একশত লাইনের একটু বেশি দেখতে পাবেন, একটি টেবিল austinrecycling তৈরি করে এবং এটিকে অবস্থানের সাথে পপুলেট করে।

এখন, ডাটাবেসের সাথে একটি সংযোগ খুলুন এবং নিম্নলিখিত কমান্ডটি দিয়ে সেই স্ক্রিপ্টটি চালান।

gcloud sql connect locations --user=postgres --quiet < datadump.sql

যদি স্ক্রিপ্টটি সফলভাবে চলে, তাহলে আউটপুটের শেষ কয়েকটি লাইন এইরকম দেখাবে:

নমুনা কমান্ড আউটপুট

ALTER TABLE
ALTER TABLE
ATLER TABLE
ALTER TABLE
COPY 103
COMMIT
WARNING: there is no transaction in progress
COMMIT

ক্লাউড এসকিউএল ব্যবহার করতে গো ব্যাক এন্ড আপডেট করুন

এখন যেহেতু আমাদের ডাটাবেসে এই সমস্ত ডেটা রয়েছে, এটি আমাদের কোড আপডেট করার সময়।

অবস্থানের তথ্য পাঠাতে ফ্রন্ট এন্ড আপডেট করুন

ফ্রন্ট-এন্ডে একটি খুব ছোট আপডেট দিয়ে শুরু করা যাক: যেহেতু আমরা এখন এই অ্যাপটি এমন একটি স্কেলের জন্য লিখছি যেখানে আমরা চাই না যে প্রতিটি একক অবস্থান ফ্রন্ট-এন্ডে বিতরিত হোক প্রতিবার ক্যোয়ারী চালানোর সময়, আমাদের ব্যবহারকারীর যত্নশীল অবস্থান সম্পর্কে ফ্রন্ট-এন্ড থেকে কিছু প্রাথমিক তথ্য পাস করতে হবে।

URL-এ আগ্রহের অক্ষাংশ এবং দ্রাঘিমাংশ অন্তর্ভুক্ত করতে app.js খুলুন এবং এই সংস্করণের সাথে fetchStores ফাংশন সংজ্ঞা প্রতিস্থাপন করুন।

app.js - fetchStores

const fetchStores = async (center) => {
  const url = `/data/dropoffs?centerLat=${center.lat}&centerLng=${center.lng}`;
  const response = await fetch(url);
  return response.json();
};

কোডল্যাবের এই ধাপটি সম্পূর্ণ করার পরে, প্রতিক্রিয়া শুধুমাত্র center প্যারামিটারে দেওয়া মানচিত্রের স্থানাঙ্কের নিকটতম স্টোরগুলিকে ফিরিয়ে দেবে। initialize ফাংশনে প্রাথমিক আনার জন্য, এই ল্যাবে প্রদত্ত নমুনা কোডটি অস্টিন, টেক্সাসের কেন্দ্রীয় স্থানাঙ্ক ব্যবহার করে।

যেহেতু fetchStores এখন শুধুমাত্র স্টোরের অবস্থানগুলির একটি উপসেট ফেরত দেবে, তাই যখনই ব্যবহারকারী তাদের শুরুর অবস্থান পরিবর্তন করবে তখনই আমাদের স্টোরগুলিকে পুনরায় আনতে হবে।

যখনই একটি নতুন উত্স সেট করা হয় তখন অবস্থানগুলি রিফ্রেশ করতে initAutocompleteWidget ফাংশন আপডেট করুন৷ এর জন্য দুটি সম্পাদনা প্রয়োজন:

  1. initAutocompleteWidget-এর মধ্যে, place_changed শ্রোতার জন্য কলব্যাক খুঁজুন। যে লাইনটি বিদ্যমান চেনাশোনাগুলিকে সাফ করে তা আন-মন্তব্য করুন, যাতে প্রতিটি ব্যবহারকারী প্লেস স্বয়ংসম্পূর্ণ অনুসন্ধান abr থেকে একটি ঠিকানা নির্বাচন করার সময় সেই লাইনটি এখন চলবে৷

app.js - initAutocompleteWidget

  autocomplete.addListener("place_changed", async () => {
    circles.forEach((c) => c.setMap(null)); // clear existing stores
    // ...
  1. যখনই নির্বাচিত মূল পরিবর্তন করা হয়, পরিবর্তনশীল মূল অবস্থান আপডেট করা হয়। " place_changed " কলব্যাকের শেষে, " // TODO এর উপরের লাইনটি আন-কমেন্ট করুন: fetchAndRenderStores ফাংশনে একটি নতুন কলে এই নতুন উত্সটি পাস করতে // TODO: Calculate the closest stores

app.js - initAutocompleteWidget

    await fetchAndRenderStores(originLocation.toJSON());
    // TODO: Calculate the closest stores

একটি ফ্ল্যাট JSON ফাইলের পরিবর্তে CloudSQL ব্যবহার করতে পিছনের প্রান্তটি আপডেট করুন৷

ফ্ল্যাট-ফাইল GeoJSON রিডিং এবং ক্যাশিং সরান

প্রথমে, ফ্ল্যাট GeoJSON ফাইলটি লোড এবং ক্যাশে করা কোডটি সরাতে main.go পরিবর্তন করুন। আমরা dropoffsHandler ফাংশন থেকেও মুক্তি পেতে পারি, কারণ আমরা ক্লাউড এসকিউএল দ্বারা চালিত একটি ভিন্ন ফাইলে লিখব।

আপনার নতুন main.go অনেক ছোট হবে।

main.go

package main

import (

        "log"
        "net/http"
        "os"
)

func main() {

        initConnectionPool()

        // Request for data should be handled by Go.  Everything else should be directed
        // to the folder of static files.
        http.HandleFunc("/data/dropoffs", dropoffsHandler)
        http.Handle("/", http.FileServer(http.Dir("./static/")))

        // Open up a port for the webserver.
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }
        log.Printf("Listening on port %s", port)
        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
}

অবস্থানের অনুরোধের জন্য একটি নতুন হ্যান্ডলার তৈরি করুন৷

এখন আরেকটি ফাইল তৈরি করা যাক, locations.go , অস্টিন-রিসাইক্লিং ডিরেক্টরিতেও। অবস্থানের অনুরোধের জন্য হ্যান্ডলার পুনরায় প্রয়োগ করে শুরু করুন।

locations.go

package main

import (
        "database/sql"
        "fmt"
        "log"
        "net/http"
        "os"

        _ "github.com/jackc/pgx/stdlib"
)

// queryBasic demonstrates issuing a query and reading results.
func dropoffsHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-type", "application/json")
        centerLat := r.FormValue("centerLat")
        centerLng := r.FormValue("centerLng")
        geoJSON, err := getGeoJSONFromDatabase(centerLat, centerLng)
        if err != nil {
                str := fmt.Sprintf("Couldn't encode results: %s", err)
                http.Error(w, str, 500)
                return
        }
        fmt.Fprintf(w, geoJSON)
}

হ্যান্ডলার নিম্নলিখিত উল্লেখযোগ্য কাজগুলি সম্পাদন করে:

  • এটি অনুরোধ বস্তু থেকে অক্ষাংশ এবং দ্রাঘিমাংশ টানে (মনে রাখবেন কিভাবে আমরা সেগুলি URL এ যোগ করেছি?)
  • এটি getGeoJsonFromDatabase কলটি বন্ধ করে দেয়, যা একটি GeoJSON স্ট্রিং প্রদান করে (আমরা এটি পরে লিখব।)
  • এটি প্রতিক্রিয়ায় সেই GeoJSON স্ট্রিংটি মুদ্রণ করতে ResponseWriter ব্যবহার করে।

পরবর্তীতে আমরা একযোগে ব্যবহারকারীদের সাথে ডাটাবেসের ব্যবহারকে ভালোভাবে মাপতে সাহায্য করার জন্য একটি সংযোগ পুল তৈরি করতে যাচ্ছি।

একটি সংযোগ পুল তৈরি করুন

একটি সংযোগ পুল হল সক্রিয় ডাটাবেস সংযোগের একটি সংগ্রহ যা সার্ভার ব্যবহারকারীর অনুরোধের জন্য পুনরায় ব্যবহার করতে পারে। আপনার সক্রিয় ব্যবহারকারীর সংখ্যা বাড়ার সাথে সাথে এটি অনেকগুলি ওভারহেড সরিয়ে দেয়, যেহেতু সার্ভারকে প্রতিটি সক্রিয় ব্যবহারকারীর জন্য সংযোগ তৈরি এবং ধ্বংস করতে সময় ব্যয় করতে হবে না। আপনি আগের বিভাগে লক্ষ্য করেছেন যে আমরা লাইব্রেরি github.com/jackc/pgx/stdlib. গো-তে সংযোগ পুলের সাথে কাজ করার জন্য এটি একটি জনপ্রিয় লাইব্রেরি।

locations.go এর শেষে, একটি ফাংশন initConnectionPool ( main.go থেকে বলা হয়) তৈরি করুন যা একটি সংযোগ পুল শুরু করে। স্পষ্টতার জন্য, এই স্নিপেটে কয়েকটি সহায়ক পদ্ধতি ব্যবহার করা হয়েছে। configureConnectionPool সংযোগের সংখ্যা এবং প্রতি সংযোগের জীবনকালের মতো পুল সেটিংস সামঞ্জস্য করার জন্য একটি সহজ স্থান প্রদান করে। mustGetEnv প্রয়োজনীয় এনভায়রনমেন্ট ভেরিয়েবল পেতে কলগুলিকে র‍্যাপ করে, তাই ইন্সট্যান্সে গুরুত্বপূর্ণ তথ্য (যেমন আইপি বা ডাটাবেসের সাথে সংযোগ করার জন্য নাম) অনুপস্থিত থাকলে দরকারী ত্রুটির বার্তাগুলি নিক্ষেপ করা যেতে পারে।

locations.go

// The connection pool
var db *sql.DB

// Each struct instance contains a single row from the query result.
type result struct {
        featureCollection string
}

func initConnectionPool() {
        // If the optional DB_TCP_HOST environment variable is set, it contains
        // the IP address and port number of a TCP connection pool to be created,
        // such as "127.0.0.1:5432". If DB_TCP_HOST is not set, a Unix socket
        // connection pool will be created instead.
        if os.Getenv("DB_TCP_HOST") != "" {
                var (
                        dbUser    = mustGetenv("DB_USER")
                        dbPwd     = mustGetenv("DB_PASS")
                        dbTCPHost = mustGetenv("DB_TCP_HOST")
                        dbPort    = mustGetenv("DB_PORT")
                        dbName    = mustGetenv("DB_NAME")
                )

                var dbURI string
                dbURI = fmt.Sprintf("host=%s user=%s password=%s port=%s database=%s", dbTCPHost, dbUser, dbPwd, dbPort, dbName)

                // dbPool is the pool of database connections.
                dbPool, err := sql.Open("pgx", dbURI)
                if err != nil {
                        dbPool = nil
                        log.Fatalf("sql.Open: %v", err)
                }

                configureConnectionPool(dbPool)

                if err != nil {

                        log.Fatalf("initConnectionPool: unable to connect: %s", err)
                }
                db = dbPool
        }
}

// configureConnectionPool sets database connection pool properties.
// For more information, see https://golang.org/pkg/database/sql
func configureConnectionPool(dbPool *sql.DB) {
        // Set maximum number of connections in idle connection pool.
        dbPool.SetMaxIdleConns(5)
        // Set maximum number of open connections to the database.
        dbPool.SetMaxOpenConns(7)
        // Set Maximum time (in seconds) that a connection can remain open.
        dbPool.SetConnMaxLifetime(1800)
}

// mustGetEnv is a helper function for getting environment variables.
// Displays a warning if the environment variable is not set.
func mustGetenv(k string) string {
        v := os.Getenv(k)
        if v == "" {
                log.Fatalf("Warning: %s environment variable not set.\n", k)
        }
        return v
}

অবস্থানের জন্য ডেটাবেস অনুসন্ধান করুন, বিনিময়ে JSON পান।

এখন আমরা একটি ডাটাবেস কোয়েরি লিখতে যাচ্ছি যা মানচিত্র স্থানাঙ্ক নেয় এবং নিকটতম 25টি অবস্থান প্রদান করে। শুধু তাই নয়, কিছু অভিনব আধুনিক ডাটাবেস কার্যকারিতার জন্য ধন্যবাদ এটি সেই ডেটাটিকে জিওজেএসএন হিসাবে ফিরিয়ে দেবে। এই সবের শেষ ফলাফল হল যে যতদূর ফ্রন্ট-এন্ড কোড বলতে পারে, কিছুই পরিবর্তন হয়নি। এটি একটি URL-এ একটি অনুরোধ বন্ধ করার আগে এবং জিওজেএসএন-এর একটি গুচ্ছ পেয়েছিল৷ এখন এটি একটি URL-এ একটি অনুরোধ বন্ধ করে দেয় এবং... জিওজেএসএন-এর একটি গুচ্ছ ফিরে পায়৷

এখানে যে জাদু সঞ্চালন ফাংশন. হ্যান্ডলার এবং সংযোগ পুলিং কোডের পরে নিম্নলিখিত ফাংশনটি যুক্ত করুন আপনি এইমাত্র locations.go এর নীচে লিখেছেন।

locations.go

func getGeoJSONFromDatabase(centerLat string, centerLng string) (string, error) {

        // Obviously you can one-line this, but for testing purposes let's make it easy to modify on the fly.
        const milesRadius = 10
        const milesToMeters = 1609
        const radiusInMeters = milesRadius * milesToMeters

        const tableName = "austinrecycling"

        var queryStr = fmt.Sprintf(
                `SELECT jsonb_build_object(
                        'type',
                        'FeatureCollection',
                        'features',
                        jsonb_agg(feature)
                )
        FROM (
                        SELECT jsonb_build_object(
                                        'type',
                                        'Feature',
                                        'id',
                                        ogc_fid,
                                        'geometry',
                                        ST_AsGeoJSON(wkb_geometry)::jsonb,
                                        'properties',
                                        to_jsonb(row) - 'ogc_fid' - 'wkb_geometry'
                                ) AS feature
                        FROM (
                                        SELECT *,
                                                ST_Distance(
                                                        ST_GEOGFromWKB(wkb_geometry),
                                                        -- Los Angeles (LAX)
                                                        ST_GEOGFromWKB(st_makepoint(%v, %v))
                                                ) as distance
                                        from %v
                                        order by distance
                                        limit 25
                                ) row
                        where distance < %v
                ) features
                `, centerLng, centerLat, tableName, radiusInMeters)

        log.Println(queryStr)

        rows, err := db.Query(queryStr)

        defer rows.Close()

        rows.Next()
        queryResult := result{}
        err = rows.Scan(&queryResult.featureCollection)
        return queryResult.featureCollection, err
}

এই ফাংশনটি বেশিরভাগই শুধু সেটআপ, টিয়ারডাউন, এবং ডাটাবেসের একটি অনুরোধ ফায়ার করার জন্য ত্রুটি পরিচালনা করে। আসুন প্রকৃত এসকিউএল-এর দিকে তাকাই, যা ডাটাবেস স্তরে সত্যিই অনেক আকর্ষণীয় জিনিস করছে, তাই আপনাকে কোডে সেগুলির কোনওটি বাস্তবায়নের বিষয়ে চিন্তা করতে হবে না।

স্ট্রিং পার্স করা হয়ে গেলে এবং সমস্ত স্ট্রিং লিটারেল তাদের সঠিক জায়গায় ঢোকানো হয়ে গেলে যে কাঁচা ক্যোয়ারীটি বন্ধ হয়ে যায়, তা এইরকম দেখায়:

parsed.sql

SELECT jsonb_build_object(
        'type',
        'FeatureCollection',
        'features',
        jsonb_agg(feature)
    )
FROM (
        SELECT jsonb_build_object(
                'type',
                'Feature',
                'id',
                ogc_fid,
                'geometry',
                ST_AsGeoJSON(wkb_geometry)::jsonb,
                'properties',
                to_jsonb(row) - 'ogc_fid' - 'wkb_geometry'
            ) AS feature
        FROM (
                SELECT *,
                    ST_Distance(
                        ST_GEOGFromWKB(wkb_geometry),
                        -- Los Angeles (LAX)
                        ST_GEOGFromWKB(st_makepoint(-97.7624043, 30.523725))
                    ) as distance
                from austinrecycling
                order by distance
                limit 25
            ) row
        where distance < 16090
    ) features

এই ক্যোয়ারীটিকে একটি প্রাথমিক ক্যোয়ারী এবং কিছু JSON মোড়ানো ফাংশন হিসাবে দেখা যেতে পারে।

SELECT * ... LIMIT 25 প্রতিটি অবস্থানের জন্য সমস্ত ক্ষেত্র নির্বাচন করে। তারপরে এটি ST_DISTANCE ফাংশন (পোস্টজিআইএস-এর ভূগোল পরিমাপের ফাংশনের স্যুটের অংশ) ব্যবহার করে ডাটাবেসের প্রতিটি অবস্থান এবং ব্যবহারকারীর সামনের প্রান্তে প্রদত্ত অবস্থানের ল্যাট/লং জোড়ার মধ্যে দূরত্ব নির্ধারণ করতে। মনে রাখবেন যে দূরত্ব ম্যাট্রিক্সের বিপরীতে, যা আপনাকে ড্রাইভিং দূরত্ব দিতে পারে, এইগুলি হল জিওস্পেশিয়াল দূরত্ব। দক্ষতার জন্য এটি তারপর সেই দূরত্বটি সাজানোর জন্য ব্যবহার করে এবং 25টি নিকটতম অবস্থানগুলিকে ব্যবহারকারীর নির্দিষ্ট স্থানে ফিরিয়ে দেয়।

** SELECT json_build_object('type', 'F **eature') পূর্ববর্তী ক্যোয়ারী মোড়ানো, ফলাফল গ্রহণ করে এবং একটি GeoJSON বৈশিষ্ট্য অবজেক্ট তৈরি করতে ব্যবহার করে। অপ্রত্যাশিতভাবে, এই ক্যোয়ারীটিও যেখানে সর্বোচ্চ ব্যাসার্ধ প্রয়োগ করা হয় "16090" হল 10 মাইলে মিটারের সংখ্যা, গো ব্যাকএন্ড দ্বারা নির্দিষ্ট করা কঠিন সীমা৷ আপনি যদি ভাবছেন কেন এই WHERE ধারাটি অভ্যন্তরীণ ক্যোয়ারীতে যোগ করা হয়নি (যেখানে প্রতিটি অবস্থানের দূরত্ব নির্ধারণ করা হয়) পরিবর্তে, এর কারণ হল পর্দার পিছনে SQL যেভাবে কার্যকর করে, সেই ক্ষেত্রটি হয়ত গণনা করা হয়নি যখন WHERE ধারাটি পরীক্ষা করা হয়েছিল। আসলে আপনি যদি এই WHERE ক্লজটিকে ভিতরের ক্যোয়ারীতে সরানোর চেষ্টা করেন তবে এটি একটি ত্রুটি নিক্ষেপ করবে।

** SELECT json_build_object('type', 'FeatureColl করুন

আপনার প্রকল্পে PGX লাইব্রেরি যোগ করুন

আমাদের আপনার প্রকল্পে একটি নির্ভরতা যোগ করতে হবে: পোস্টগ্রেস ড্রাইভার এবং টুলকিট , যা সংযোগ পুলিং সক্ষম করে। এটি করার সবচেয়ে সহজ উপায় হল Go মডিউল দিয়ে। ক্লাউড শেলে এই কমান্ড দিয়ে একটি মডিউল শুরু করুন:

go mod init my_locator

এরপরে, নির্ভরতার জন্য কোড স্ক্যান করতে এই কমান্ডটি চালান, মোড ফাইলে নির্ভরতাগুলির একটি তালিকা যোগ করুন এবং সেগুলি ডাউনলোড করুন।

go mod tidy

অবশেষে, আপনার প্রজেক্ট ডিরেক্টরিতে সরাসরি নির্ভরতা টানতে এই কমান্ডটি চালান যাতে AppEngine Flex-এর জন্য ধারকটি সহজেই তৈরি করা যায়।

go mod vendor

ঠিক আছে, আপনি এটি পরীক্ষা করার জন্য প্রস্তুত!

এটা পরীক্ষা করে দেখুন

ঠিক আছে, আমরা অনেক কাজ করেছি। এর কাজ দেখা যাক!

আপনার ডেভেলপমেন্ট মেশিন (হ্যাঁ, এমনকি ক্লাউড শেল) ডাটাবেসের সাথে সংযোগ করার জন্য, ডাটাবেস সংযোগ পরিচালনা করতে আমাদের ক্লাউড এসকিউএল প্রক্সি ব্যবহার করতে হবে। ক্লাউড এসকিউএল প্রক্সি সেট আপ করতে:

  1. Cloud SQL Admin API সক্ষম করতে এখানে যান
  2. আপনি যদি স্থানীয় ডেভেলপমেন্ট মেশিনে থাকেন, তাহলে ক্লাউড এসকিউএল প্রক্সি টুল ইনস্টল করুন। আপনি যদি ক্লাউড শেল ব্যবহার করেন তবে আপনি এই ধাপটি এড়িয়ে যেতে পারেন, এটি ইতিমধ্যেই ইনস্টল করা আছে! নোট করুন যে নির্দেশাবলী একটি পরিষেবা অ্যাকাউন্ট উল্লেখ করবে। আপনার জন্য ইতিমধ্যেই একটি তৈরি করা হয়েছে, এবং আমরা নিম্নলিখিত বিভাগে সেই অ্যাকাউন্টে প্রয়োজনীয় অনুমতিগুলি যুক্ত করব৷
  3. প্রক্সি শুরু করতে একটি নতুন ট্যাব তৈরি করুন (ক্লাউড শেল বা আপনার নিজস্ব টার্মিনালে)।

bcca42933bfbd497.png

  1. https://console.cloud.google.com/sql/instances/locations/overview এ যান এবং সংযোগ নামের ক্ষেত্রটি খুঁজতে নিচে স্ক্রোল করুন। পরবর্তী কমান্ডে ব্যবহার করার জন্য সেই নামটি অনুলিপি করুন।
  2. সেই ট্যাবে, পূর্ববর্তী ধাপে দেখানো সংযোগের নাম দিয়ে CONNECTION_NAME প্রতিস্থাপন করে এই কমান্ডের সাহায্যে Cloud SQL প্রক্সি চালান।
cloud_sql_proxy -instances=CONNECTION_NAME=tcp:5432

আপনার ক্লাউড শেলের প্রথম ট্যাবে ফিরে যান এবং ডাটাবেস ব্যাকএন্ডের সাথে যোগাযোগ করার জন্য Go-এর প্রয়োজনীয় পরিবেশের ভেরিয়েবলগুলি সংজ্ঞায়িত করুন এবং তারপরে আপনি আগে যেভাবে করেছিলেন সেভাবে সার্ভারটি চালান:

আপনি যদি ইতিমধ্যে সেখানে না থাকেন তবে প্রকল্পের রুট ডিরেক্টরিতে নেভিগেট করুন।

cd YOUR_PROJECT_ROOT

নিম্নলিখিত পাঁচটি এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন (আপনার উপরে তৈরি পাসওয়ার্ড দিয়ে YOUR_PASSWORD_HERE প্রতিস্থাপন করুন)।

export DB_USER=postgres
export DB_PASS=YOUR_PASSWORD_HERE
export DB_TCP_HOST=127.0.0.1 # Proxy
export DB_PORT=5432 #Default for PostGres
export DB_NAME=postgres

আপনার স্থানীয় উদাহরণ চালান.

go run *.go

পূর্বরূপ উইন্ডো খুলুন, এবং এটি এমনভাবে কাজ করা উচিত যেন কিছুই পরিবর্তন হয়নি: আপনি একটি শুরুর ঠিকানা লিখতে পারেন, মানচিত্রের চারপাশে জুম করতে পারেন এবং পুনর্ব্যবহারযোগ্য অবস্থানগুলিতে ক্লিক করতে পারেন। কিন্তু এখন এটি একটি ডাটাবেস দ্বারা সমর্থিত, এবং স্কেলের জন্য প্রস্তুত!

9. নিকটতম দোকানের তালিকা করুন

দিকনির্দেশ এপিআই অনেকটা Google মানচিত্র অ্যাপে দিকনির্দেশের অনুরোধ করার অভিজ্ঞতার মতো কাজ করে—দুটির মধ্যে একটি রুট পেতে একটি একক উত্স এবং একটি গন্তব্যে প্রবেশ করা। দূরত্ব ম্যাট্রিক্স এপিআই ভ্রমণের সময় এবং দূরত্বের উপর ভিত্তি করে একাধিক সম্ভাব্য উত্স এবং একাধিক সম্ভাব্য গন্তব্যগুলির মধ্যে সর্বোত্তম জোড়া সনাক্ত করার জন্য এই ধারণাটিকে আরও এগিয়ে নিয়ে যায়। এই ক্ষেত্রে, ব্যবহারকারীকে নির্বাচিত ঠিকানার নিকটতম দোকান খুঁজে পেতে সাহায্য করার জন্য, আপনি গন্তব্য হিসাবে একটি উত্স এবং দোকান অবস্থানগুলির একটি অ্যারে প্রদান করেন৷

প্রতিটি দোকান থেকে দূরত্ব যোগ করুন

initMap ফাংশনের সংজ্ঞার শুরুতে, " // TODO: Start Distance Matrix service " মন্তব্যটি নিম্নলিখিত কোড দিয়ে প্রতিস্থাপন করুন:

app.js - initMap

distanceMatrixService = new google.maps.DistanceMatrixService();

calculateDistances নামে app.js এর শেষে একটি নতুন ফাংশন যোগ করুন।

app.js

async function calculateDistances(origin, stores) {
  // Retrieve the distances of each store from the origin
  // The returned list will be in the same order as the destinations list
  const response = await getDistanceMatrix({
    origins: [origin],
    destinations: stores.map((store) => {
      const [lng, lat] = store.geometry.coordinates;
      return { lat, lng };
    }),
    travelMode: google.maps.TravelMode.DRIVING,
    unitSystem: google.maps.UnitSystem.METRIC,
  });
  response.rows[0].elements.forEach((element, index) => {
    stores[index].properties.distanceText = element.distance.text;
    stores[index].properties.distanceValue = element.distance.value;
  });
}

const getDistanceMatrix = (request) => {
  return new Promise((resolve, reject) => {
    const callback = (response, status) => {
      if (status === google.maps.DistanceMatrixStatus.OK) {
        resolve(response);
      } else {
        reject(response);
      }
    };
    distanceMatrixService.getDistanceMatrix(request, callback);
  });
};

ফাংশনটি ডিসট্যান্স ম্যাট্রিক্স এপিআইকে একটি একক উৎপত্তি হিসাবে এবং স্টোরের অবস্থানগুলিকে গন্তব্যগুলির একটি অ্যারে হিসাবে প্রেরণ করে। তারপরে, এটি স্টোরের আইডি সংরক্ষণ করে বস্তুর একটি বিন্যাস তৈরি করে, একটি মানব-পঠনযোগ্য স্ট্রিংয়ে দূরত্ব প্রকাশ করে, একটি সংখ্যাসূচক মান হিসাবে মিটারে দূরত্ব, এবং অ্যারে সাজায়।

যখনই স্থান স্বয়ংসম্পূর্ণ অনুসন্ধান বার থেকে একটি নতুন উত্স নির্বাচন করা হয় তখনই স্টোরের দূরত্ব গণনা করতে initAutocompleteWidget ফাংশন আপডেট করুন। initAutocompleteWidget ফাংশনের নীচে, মন্তব্যটি প্রতিস্থাপন করুন " // TODO: Calculate the closest stores :

app.js - initutotocumpletewidget

    // Use the selected address as the origin to calculate distances
    // to each of the store locations
    await calculateDistances(originLocation, stores);
    renderStoresPanel();

দূরত্ব অনুসারে বাছাই করা স্টোরগুলির একটি তালিকা ভিউ প্রদর্শন করুন

ব্যবহারকারী প্রত্যাশা করে যে স্টোরগুলির একটি তালিকা নিকটতম থেকে সবচেয়ে দূরে অর্ডার করা হয়েছে। স্টোরগুলির ডিসপ্লে অর্ডার অবহিত করতে calculateDistances ফাংশন দ্বারা সংশোধিত তালিকাটি ব্যবহার করে প্রতিটি স্টোরের জন্য একটি সাইড-প্যানেল তালিকা তৈরি করুন।

renderStoresPanel() এবং storeToPanelRow() নামে পরিচিত app.js শেষে একটি নতুন ফাংশন যুক্ত করুন।

app.js

function renderStoresPanel() {
  const panel = document.getElementById("panel");

  if (stores.length == 0) {
    panel.classList.remove("open");
    return;
  }

  // Clear the previous panel rows
  while (panel.lastChild) {
    panel.removeChild(panel.lastChild);
  }
  stores
    .sort((a, b) => a.properties.distanceValue - b.properties.distanceValue)
    .forEach((store) => {
      panel.appendChild(storeToPanelRow(store));
    });
  // Open the panel
  panel.classList.add("open");
  return;
}

const storeToPanelRow = (store) => {
  // Add store details with text formatting
  const rowElement = document.createElement("div");
  const nameElement = document.createElement("p");
  nameElement.classList.add("place");
  nameElement.textContent = store.properties.business_name;
  rowElement.appendChild(nameElement);
  const distanceTextElement = document.createElement("p");
  distanceTextElement.classList.add("distanceText");
  distanceTextElement.textContent = store.properties.distanceText;
  rowElement.appendChild(distanceTextElement);
  return rowElement;
};

আপনার সার্ভারটি পুনরায় চালু করুন এবং নিম্নলিখিত কমান্ডটি চালিয়ে আপনার পূর্বরূপ রিফ্রেশ করুন।

go run *.go

অবশেষে, অটোকটিন, টিএক্স ঠিকানাটি অটো কমপ্লিট অনুসন্ধান বারে প্রবেশ করুন এবং পরামর্শগুলির মধ্যে একটিতে ক্লিক করুন।

মানচিত্রে সেই ঠিকানায় কেন্দ্র করা উচিত এবং একটি সাইডবার নির্বাচিত ঠিকানা থেকে দূরত্বের ক্রমে স্টোরের অবস্থানগুলি তালিকাভুক্ত করা উচিত। একটি উদাহরণ নিম্নলিখিত হিসাবে চিত্রিত:

96E35794DD0E88C9.png

10। মানচিত্রটি স্টাইল করুন

আপনার মানচিত্রটি দৃশ্যত আলাদা করার জন্য একটি উচ্চ-প্রভাবের উপায় হ'ল এটিতে স্টাইলিং যুক্ত করা। ক্লাউড-ভিত্তিক মানচিত্র স্টাইলিং সহ, আপনার মানচিত্রের কাস্টমাইজেশন ক্লাউড-ভিত্তিক মানচিত্র স্টাইলিং (বিটা) ব্যবহার করে ক্লাউড কনসোল থেকে নিয়ন্ত্রণ করা হয়। আপনি যদি নন-বিটা বৈশিষ্ট্য সহ আপনার মানচিত্রটি স্টাইল করতে চান তবে আপনি মানচিত্রটি স্টাইলিংয়ের জন্য জেএসএন তৈরি করতে সহায়তা করতে মানচিত্রের স্টাইলিং ডকুমেন্টেশন ব্যবহার করতে পারেন। নীচের নির্দেশাবলী আপনাকে ক্লাউড-ভিত্তিক মানচিত্র স্টাইলিং (বিটা) এর মাধ্যমে গাইড করে।

একটি মানচিত্র আইডি তৈরি করুন

প্রথমে ক্লাউড কনসোল এবং অনুসন্ধান বাক্সে খুলুন এবং "মানচিত্র পরিচালনা" টাইপ করুন। "মানচিত্র পরিচালনা (গুগল ম্যাপস)" বলে ফলাফলটি ক্লিক করুন। 64036DD0ED200200.png

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

70F55A759B4C4212.png

"নেক্সট" ক্লিক করুন এবং আপনি একেবারে নতুন মানচিত্র আইডি দিয়ে আকৃষ্ট হবেন। আপনি চাইলে এখনই এটি অনুলিপি করতে পারেন, তবে চিন্তা করবেন না, পরে সন্ধান করা সহজ।

এরপরে আমরা সেই মানচিত্রে প্রয়োগ করার জন্য একটি স্টাইল তৈরি করতে যাচ্ছি।

একটি মানচিত্র শৈলী তৈরি করুন

আপনি যদি এখনও ক্লাউড কনসোলের মানচিত্র বিভাগে থাকেন তবে "বাম দিকে নেভিগেশন মেনুর নীচে মানচিত্রের স্টাইলগুলি ক্লিক করুন Otherwise

9284CD200F1A9223.png

পরবর্তী শীর্ষের নিকটবর্তী বোতামে ক্লিক করুন যা " + নতুন মানচিত্রের স্টাইল তৈরি করুন " বলে

  1. আপনি যদি এই ল্যাবটিতে প্রদর্শিত মানচিত্রে স্টাইলিংয়ের সাথে মেলে না, " আমদানি জেএসএন " ট্যাবটি ক্লিক করুন এবং নীচের জেএসএন ব্লবটি আটকান। অন্যথায় আপনি যদি নিজের তৈরি করতে চান তবে আপনি যে মানচিত্রের স্টাইলটি শুরু করতে চান তা নির্বাচন করুন। তারপর Next এ ক্লিক করুন।
  2. এই শৈলীর সাথে সেই মানচিত্রের আইডিটি সংযুক্ত করতে আপনি সবেমাত্র তৈরি করা মানচিত্র আইডিটি নির্বাচন করুন এবং আবার পরবর্তী ক্লিক করুন।
  3. এই মুহুর্তে আপনাকে আপনার মানচিত্রের স্টাইলিংটি আরও কাস্টমাইজ করার বিকল্প দেওয়া হয়েছে। যদি এটি আপনি অন্বেষণ করতে চান এমন কিছু হয় তবে স্টাইল এডিটর কাস্টমাইজ ক্লিক করুন এবং আপনার পছন্দ মতো মানচিত্রের স্টাইল না পাওয়া পর্যন্ত রঙ এবং বিকল্পগুলির সাথে চারপাশে খেলুন। অন্যথায় এড়িয়ে যান ক্লিক করুন।
  4. পরবর্তী পদক্ষেপে, আপনার স্টাইলের নাম এবং বিবরণ লিখুন এবং তারপরে সংরক্ষণ এবং প্রকাশ করুন ক্লিক করুন।

প্রথম ধাপে আমদানি করার জন্য এখানে একটি al চ্ছিক জেএসএন ব্লব রয়েছে।

[
  {
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#d6d2c4"
      }
    ]
  },
  {
    "elementType": "labels.icon",
    "stylers": [
      {
        "visibility": "off"
      }
    ]
  },
  {
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#616161"
      }
    ]
  },
  {
    "elementType": "labels.text.stroke",
    "stylers": [
      {
        "color": "#f5f5f5"
      }
    ]
  },
  {
    "featureType": "administrative.land_parcel",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#bdbdbd"
      }
    ]
  },
  {
    "featureType": "landscape.man_made",
    "elementType": "geometry.fill",
    "stylers": [
      {
        "color": "#c0baa5"
      },
      {
        "visibility": "on"
      }
    ]
  },
  {
    "featureType": "landscape.man_made",
    "elementType": "geometry.stroke",
    "stylers": [
      {
        "color": "#9cadb7"
      },
      {
        "visibility": "on"
      }
    ]
  },
  {
    "featureType": "poi",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#757575"
      }
    ]
  },
  {
    "featureType": "poi.park",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#9e9e9e"
      }
    ]
  },
  {
    "featureType": "road",
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#ffffff"
      }
    ]
  },
  {
    "featureType": "road.arterial",
    "elementType": "geometry",
    "stylers": [
      {
        "weight": 1
      }
    ]
  },
  {
    "featureType": "road.arterial",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#757575"
      }
    ]
  },
  {
    "featureType": "road.highway",
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#bf5700"
      }
    ]
  },
  {
    "featureType": "road.highway",
    "elementType": "geometry.stroke",
    "stylers": [
      {
        "visibility": "off"
      }
    ]
  },
  {
    "featureType": "road.highway",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#616161"
      }
    ]
  },
  {
    "featureType": "road.local",
    "elementType": "geometry",
    "stylers": [
      {
        "weight": 0.5
      }
    ]
  },
  {
    "featureType": "road.local",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#9e9e9e"
      }
    ]
  },
  {
    "featureType": "transit.line",
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#e5e5e5"
      }
    ]
  },
  {
    "featureType": "transit.station",
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#eeeeee"
      }
    ]
  },
  {
    "featureType": "water",
    "elementType": "geometry",
    "stylers": [
      {
        "color": "#333f48"
      }
    ]
  },
  {
    "featureType": "water",
    "elementType": "labels.text.fill",
    "stylers": [
      {
        "color": "#9e9e9e"
      }
    ]
  }
]

আপনার কোডে মানচিত্র আইডি যুক্ত করুন

এখন আপনি এই মানচিত্রের শৈলী তৈরির সমস্যায় পড়েছেন, আপনি কীভাবে এই মানচিত্রের স্টাইলটি নিজের মানচিত্রে ব্যবহার করবেন? আপনার দুটি ছোট পরিবর্তন করা দরকার:

  1. index.html এ স্ক্রিপ্ট ট্যাগে URL প্যারামিটার হিসাবে মানচিত্রের আইডি যুক্ত করুন
  2. আপনি যখন আপনার initMap() পদ্ধতিতে মানচিত্রটি তৈরি করেন তখন মানচিত্রের আইডিটি কনস্ট্রাক্টর আর্গুমেন্ট হিসাবে Add

স্ক্রিপ্ট ট্যাগটি প্রতিস্থাপন করুন যা এইচটিএমএল ফাইলের মানচিত্র জাভাস্ক্রিপ্ট এপিআই লোড করে নীচের লোডার ইউআরএল দিয়ে, " YOUR_API_KEY " এবং " YOUR_MAP_ID " এর জন্য স্থানধারীদের প্রতিস্থাপন করে:

index.html

...
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=weekly&libraries=places&callback=initialize&map_ids=YOUR_MAP_ID&solution_channel=GMP_codelabs_fullstackstorelocator_v1_a">
  </script>
...

app.js initMap পদ্ধতিতে যেখানে ধ্রুবক map সংজ্ঞায়িত করা হয়, mapId সম্পত্তিটির জন্য লাইনটি অনিয়ন্ত্রিত করুন এবং আপনি সবেমাত্র তৈরি করা মানচিত্রের আইডি দিয়ে " YOUR_MAP_ID_HERE " প্রতিস্থাপন করুন:

app.js - initmap

...

// The map, centered on Austin, TX
 const map = new google.maps.Map(document.querySelector('#map'), {
   center: austin,
   zoom: 14,
   mapId: 'YOUR_MAP_ID_HERE',
// ...
});
...

আপনার সার্ভার পুনরায় চালু করুন.

go run *.go

আপনার পূর্বরূপটি সতেজ করার পরে, মানচিত্রটি আপনার পছন্দ অনুযায়ী স্টাইল করা উচিত। উপরে JSON স্টাইলিং ব্যবহার করে এখানে একটি উদাহরণ রয়েছে।

2ECE59C64C06E9DA.PNG

11। উত্পাদন মোতায়েন

আপনি যদি অ্যাপেনগাইন ফ্লেক্স থেকে আপনার অ্যাপটি চলমান দেখতে চান (এবং আপনার বিকাশ মেশিন / ক্লাউড শেলটিতে কেবল কোনও স্থানীয় ওয়েবসার্ভার নয়, যা আপনি যা করছেন) তবে এটি খুব সহজ। উত্পাদন পরিবেশে কাজের জন্য ডাটাবেস অ্যাক্সেসের জন্য আমাদের কেবল কয়েকটি জিনিস যুক্ত করতে হবে। এটি সমস্ত অ্যাপ্লিকেশন ইঞ্জিন ফ্লেক্স থেকে ক্লাউড এসকিউএল -তে সংযোগের জন্য ডকুমেন্টেশন পৃষ্ঠায় বর্ণিত।

অ্যাপ.ইমলে পরিবেশের ভেরিয়েবলগুলি যুক্ত করুন

প্রথমত, স্থানীয়ভাবে পরীক্ষা করার জন্য আপনি যে সমস্ত পরিবেশের ভেরিয়েবল ব্যবহার করছিলেন তা আপনার অ্যাপ্লিকেশনটির app.yaml ফাইলের নীচে যুক্ত করা দরকার।

  1. উদাহরণস্বরূপ সংযোগের নামটি সন্ধান করতে https://console.cloud.google.com/sql/instances/locations/overview দেখুন।
  2. app.yaml এর শেষে নিম্নলিখিত কোডটি আটকান।
  3. YOUR_DB_PASSWORD_HERE postgres ব্যবহারকারীর নামের জন্য তৈরি পাসওয়ার্ডটি আগে প্রতিস্থাপন করুন।
  4. YOUR_CONNECTION_NAME_HERE 1 ধাপ 1 থেকে মান সহ প্রতিস্থাপন করুন।

app.yaml

# ...
# Set environment variables
env_variables:
    DB_USER: postgres
    DB_PASS: YOUR_DB_PASSWORD_HERE
    DB_NAME: postgres
    DB_TCP_HOST: 172.17.0.1
    DB_PORT: 5432

#Enable TCP Port
# You can look up your instance connection name by going to the page for
# your instance in the Cloud Console here : https://console.cloud.google.com/sql/instances/
beta_settings:
  cloud_sql_instances: YOUR_CONNECTION_NAME_HERE=tcp:5432

নোট করুন যে DB_TCP_HOST মান 172.17.0.1 এর মান থাকা উচিত যেহেতু এই অ্যাপ্লিকেশনটি অ্যাপেনগাইন ফ্লেক্স ** এর মাধ্যমে সংযুক্ত হয়েছে **

অ্যাপেনগাইন ফ্লেক্স পরিষেবা অ্যাকাউন্টে এসকিউএল ক্লায়েন্টের অনুমতি যুক্ত করুন

ক্লাউড কনসোলে আইএএম-অ্যাডমিন পৃষ্ঠায় যান এবং এমন একটি পরিষেবা অ্যাকাউন্টের সন্ধান করুন যার নাম ফর্ম্যাটটি service-PROJECT_NUMBER@gae-api-prod.google.com.iam.gserviceaccount.com @gae-api-prod.google.com.aiam.gserviceaccount.com এর সাথে মেলে। এটি পরিষেবা অ্যাকাউন্ট অ্যাপ্লিকেশন ইঞ্জিন ফ্লেক্সটি ডাটাবেসের সাথে সংযোগ করতে ব্যবহার করবে। সারিটির শেষে সম্পাদনা বোতামটি ক্লিক করুন এবং " ক্লাউড এসকিউএল ক্লায়েন্ট " ভূমিকাটি যুক্ত করুন।

b04ccc0b4022b905.png

আপনার প্রকল্প কোডটি যেতে যেতে অনুলিপি করুন

অ্যাপেনজিনকে আপনার কোড চালানোর জন্য, এটি জিও পাথের প্রাসঙ্গিক ফাইলগুলি সন্ধান করতে সক্ষম হওয়া দরকার। আপনি আপনার প্রকল্পের রুট ডিরেক্টরিতে রয়েছেন তা নিশ্চিত করুন।

cd YOUR_PROJECT_ROOT

ডিরেক্টরিটি যেতে যেতে পথে অনুলিপি করুন।

mkdir -p ~/gopath/src/austin-recycling
cp -r ./ ~/gopath/src/austin-recycling

যে ডিরেক্টরিতে পরিবর্তন করুন.

cd ~/gopath/src/austin-recycling

আপনার অ্যাপ স্থাপন করুন

আপনার অ্যাপটি স্থাপন করতে gcloud CLI ব্যবহার করুন। এটি মোতায়েন করতে কিছুটা সময় লাগবে।

gcloud app deploy

আপনার সম্পূর্ণরূপে মোতায়েন করা, এন্টারপ্রাইজ-গ্রেড, নান্দনিকভাবে অত্যাশ্চর্য স্টোর লোকেটারকে অ্যাকশনে দেখতে আপনি ক্লিক করতে পারেন এমন একটি লিঙ্ক পেতে browse কমান্ডটি ব্যবহার করুন।

gcloud app browse

আপনি যদি ক্লাউড শেলের বাইরে gcloud চালাচ্ছিলেন, তবে gcloud app browse চালানো একটি নতুন ব্রাউজার ট্যাব খুলবে।

12। (প্রস্তাবিত) পরিষ্কার করুন

এই কোডল্যাব সম্পাদন করা বিগকোয়ারি প্রসেসিং এবং মানচিত্র প্ল্যাটফর্ম এপিআই কলগুলির জন্য নিখরচায় স্তরের সীমার মধ্যে থাকবে, তবে আপনি যদি এটি কেবলমাত্র একটি শিক্ষামূলক অনুশীলন হিসাবে সম্পাদন করেন এবং ভবিষ্যতের কোনও চার্জ ব্যয় এড়াতে চান তবে এই প্রকল্পের সাথে সম্পর্কিত সংস্থানগুলি মুছে ফেলার সহজতম উপায় হ'ল প্রকল্পটি নিজেই মুছে ফেলা।

প্রকল্পটি মুছুন

জিসিপি কনসোলে ক্লাউড রিসোর্স ম্যানেজার পৃষ্ঠায় যান:

প্রকল্পের তালিকায়, আমরা যে প্রকল্পে কাজ করছি তা নির্বাচন করুন এবং মুছুন ক্লিক করুন। আপনাকে প্রজেক্ট আইডি টাইপ করার অনুরোধ জানানো হবে। এটি প্রবেশ করুন এবং শাট ডাউন ক্লিক করুন।

বিকল্পভাবে, আপনি নিম্নলিখিত কমান্ডটি চালিয়ে এবং আপনার প্রকল্পের আইডি দিয়ে স্থানধারক GOOGLE_CLOUD_PROJECT প্রতিস্থাপন করে gcloud সাথে ক্লাউড শেল থেকে সরাসরি পুরো প্রকল্পটি মুছতে পারেন:

gcloud projects delete GOOGLE_CLOUD_PROJECT

13। অভিনন্দন

অভিনন্দন! আপনি সফলভাবে কোডেল্যাব শেষ করেছেন !

অথবা আপনি শেষ পৃষ্ঠায় স্কিম করেছেন। অভিনন্দন! আপনি শেষ পৃষ্ঠায় স্কিম করেছেন !

এই কোডল্যাব চলাকালীন, আপনি নিম্নলিখিত প্রযুক্তিগুলির সাথে কাজ করেছেন:

আরও পড়া

এই সমস্ত প্রযুক্তি সম্পর্কে এখনও অনেক কিছু শিখতে হবে। নীচে এই কোডল্যাবটিতে কভার করার জন্য আমাদের কাছে সময় নেই এমন বিষয়গুলির জন্য কয়েকটি সহায়ক লিঙ্ক রয়েছে, তবে আপনার নির্দিষ্ট প্রয়োজনের সাথে খাপ খায় এমন কোনও স্টোর লোকেটার সমাধান তৈরি করতে অবশ্যই আপনার পক্ষে কার্যকর হতে পারে।