地圖反查經緯度,將地圖顯示在立委服務地區旁。

本篇重點:
Vaadin direction組件 Google Maps Addon
本示例使用 Google Maps Addon 套件最基本功能 : 使用街道地圖、將地圖移到座標中心點、地圖放大、加地圖標記。從上方執行結果可看到執行結果,地圖可切換全螢幕顯示、zoom in/out、地圖顯示模式切換、街景服務,功能相當完備。
Vaadin Directory 內有大量開源組件,筆者在本系列文首篇簡介裡提到,Vaadin Directory 內已有近2000個組件。當開發出滿意的組件時,也可自由上傳供其他人使用。

通常 add-on 只提供 Maven dependency 如下,但本專案為 Gradle 專案,須轉換一下。
<dependency>
   <groupId>com.flowingcode.vaadin.addons</groupId>
   <artifactId>google-maps</artifactId>
   <version>1.4.0</version>
</dependency>
<repository>
   <id>vaadin-addons</id>
   <url>https://maven.vaadin.com/vaadin-addons</url>
</repository>
    repositories {
        maven("https://maven.vaadin.com/vaadin-addons")
        mavenCentral()
        google()
    }
因本套件使用 Google Map,所以除了Google Maps Addon外,還要導入Google Maps Services
implementation("com.flowingcode.vaadin.addons:google-maps:1.4.0")
implementation("com.google.maps:google-maps-services:1.0.0")
使用 Google 地圖服務需要啟用帳單收費功能,請留意收費標準
地址查經緯度 : Geocoding API
網頁顯示地圖 : Maps JavaScript API
雖然Vaadin使用kotlin開發,但別忘了,它畢竟是web application
請參考官網文件
這部份在很多地方都可查到上傳格式,在此不多加敘述,或者您可參考官網文件。本文取得座標方法在下方。
Geocoding API response json 如下,但我們需要的只有下述打 * 號的部份
{
  "addressComponents": [
    {
      "longName": "165",
      "shortName": "165",
      "types": [
        "STREET_NUMBER"
      ]
    },
    {
      "longName": "Section 4, Fengyuan Boulevard",
      "shortName": "Section 4, Fengyuan Blvd",
      "types": [
        "ROUTE"
      ]
    },
    {
      "longName": "北陽里",
      "shortName": "北陽里",
      "types": [
        "ADMINISTRATIVE_AREA_LEVEL_4",
        "POLITICAL"
      ]
    },
    {
      "longName": "Fengyuan District",
      "shortName": "Fengyuan District",
      "types": [
        "ADMINISTRATIVE_AREA_LEVEL_3",
        "POLITICAL"
      ]
    },
    {
      "longName": "Taichung City",
      "shortName": "Taichung City",
      "types": [
        "ADMINISTRATIVE_AREA_LEVEL_1",
        "POLITICAL"
      ]
    },
    {
      "longName": "Taiwan",
      "shortName": "TW",
      "types": [
        "COUNTRY",
        "POLITICAL"
      ]
    },
    {
      "longName": "420",
      "shortName": "420",
      "types": [
        "POSTAL_CODE"
      ]
    }
  ],
  "formattedAddress": "No. 165, Section 4, Fengyuan Blvd, Fengyuan District, Taichung City, Taiwan 420",
  "geometry": {
*    "location": {
*      "lat": 24.2467722,
*      "lng": 120.73373
*    },
    "locationType": "ROOFTOP",
    "viewport": {
      "northeast": {
        "lat": 24.2481211802915,
        "lng": 120.7350789802915
      },
      "southwest": {
        "lat": 24.2454232197085,
        "lng": 120.7323810197085
      }
    }
  },
  "types": [
    "STREET_ADDRESS"
  ],
  "partialMatch": false,
  "placeId": "ChIJVfZYFhgaaTQRxZpdnhApIp4",
  "plusCode": {
    "globalCode": "7QP26PWM+PF",
    "compoundCode": "6PWM+PF Fengyuan District, Taichung City, Taiwan"
  }
}
Google Maps Services API 查座標,取得 location    private fun getLatLng(addr: String): LatLng {
        val context = GeoApiContext.Builder()
            .apiKey(apiKey)
            .build()
        val result = GeocodingApi.geocode(context, addr).await()
        val gson = GsonBuilder().setPrettyPrinting().create()
        return result[0].geometry.location
    }
此自製組件傳入參數為地址,透過geocoding api查詢經緯度座標,再顯示地圖。一般實務上不這麼使用,通常會儲存查到的座標,節省重複查詢流量。
本示例使用 Google Maps Addon 套件最基本功能 : 使用街道地圖、將地圖移到座標中心點、地圖放大、加地圖標記。
class GoogleMapComponent(addr: String) : KComposite() {
    private lateinit var gmaps: GoogleMap
    private val apiKey = "AIzaSyD.............wXyRDoA"
    private val root = ui {
        verticalLayout {
            val latLng = getLatLng(addr)
            val latlon = LatLon(latLng.lat, latLng.lng)
            gmaps = GoogleMap(apiKey, null, null).apply {
                mapType = GoogleMap.MapType.ROADMAP
                zoom = 15
                center = latlo
                addMarker("Center", center, true, "")
                setSizeFull()
            }
            add(gmaps)
        }
    }
}
fun HasComponents.googleMapComponent(addr: String, block: GoogleMapComponent.() -> Unit = {}) = init(GoogleMapComponent(addr), block)
   horizontalLayout.add(this@verticalLayout.googleMapComponent(addr)