• Google Maps Embed API & JavaScript API


    前言

    很多年前写过一篇 Google Map 谷歌地图, 这篇算是翻新版本.

    Google Map Registration

    Google Maps Platform 是整个 Google Map 的大本营. 里面有许许多多的 Services. Embed 和 JavaScript API 只是其中的两个.

    首先, Services 不是免费的. 只是 Google 每个月有 free USD 200 块让你花. 可以算是间接免费.

    但是申请账户需要绑定银行卡哦 (以前是不需要的, 如果只是用 Maps Embed API 则不需要绑定卡)

    下图是它的 Documentation

    这篇的内容, 大部分都是来自 JS API 和 Embed API 文档.

    申请的部分我就不 step by step 讲了. 大概有几个东西需要弄:

    1. 申请 Google Cloud (Map 属于 Cloud 的一部分)

    2. 绑卡

    3. Create New Project

    4. Enable Services (Maps Embed / JavaScript API)

    5. 做 API Key (API Key 要设定只有在指定的 Domain 内能用哦 (这个叫 Key restrictions), 因为 API Key 是放在 HTML 公开的, 任何人都可以直接拿到.

    Google Maps Embed API

    Embed Map 就是把 Map 嵌套进网站里. 效果:

    它是通过 iframe 完成的. 左上角是一个 location info. 中间有一个 drop point 就是目标地点 (通常就是公司的地址)

    要制作 iframe 不需要什么 coding. 用 Generating an iframe 就可以了.

    输入查询, 比如公司名字 > 点击 Looks good!

    然后输入 API Key

    API 在 Cloud 里面

    接着 copy iframe 的 code, 放到要 display 的页面区域就可以了.

    Options

    想配置 config 可以通过 parameters. 参考: Embedding a map

    上面我们使用了 iframe generator, 但其实它就是替我们生成 parameters 而已.

    下面这个是手写的 iframe src

    https://www.google.com/maps/embed/v1/place?q=place_id:ChIJcXt2BFgZ2jERY1RQlGLGTzU&zoom=10&key=your-key

    通常可能需要配置的变量是: version, place_id (或者直接用 q, q stand for query), zoom, key, language. 参考: place mode

    局限

    Embed API 虽然简单, 但是也有不少局限性.

    1. 不支持 multiple location. 它只可以放一个地点. 如果公司有许多分行. 那就不够用了.

    2. marker (中间的 drop point 术语叫 marker) 没有任何点击事件. location info 在右上角并不显眼. 用户可能会点击 marker, 但却没有任何反应.

    而这两个局限可以通过 Maps JavaScript API 来解决.

    Google Maps JavaScript API

    最终效果

    一开始有 3 个 location, 点击 location 会出现 location info.

    Simple Map

    最终效果有几个难点, 我们先从最简单的开始.

    setup HTML

    首先是 HTML 引入 Script 和一个 div 作为 map 的渲染位置

    bundle.js 是我们的 main.ts

    <script src="./bundle.js" defer></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=your-key&libraries=places&callback=initMap"
      defer
    ></script>

    这个 Script 可以直接放在 HTML 或者用 JavaScript 动态 append 出去都可以. 确保执行的顺序就可以了.

    有 3 个 parameters 需要注意

    1. key 和 Embed API 是相同的 key

    2. libraries, 由于会使用到 PlacesService 所以这里需要 "import" 它.

    3. callback, 当 Script 加载好后会调用 initMap 这个全局函数. 所以在 main.ts 我们 assign callback 方法到 window.initMap 里.

    setup JavaScript

    先安装 types 

    yarn add @types/google.maps --dev

    然后定义 callback

    declare global {
      interface Window {
        initMap: () => void;
      }
    }
    
    window.initMap = () => {
      new google.maps.Map(document.querySelector(".map")!, {
        center: {
          lat: 1.284491,
          lng: 103.845951,
        },
        zoom: 10,
      });
    };

    效果

    这个就是最简单的 map 了.

    center 和 zoom 是一定要 set 的, 不然什么都看不见哦.

    Scolling Problem

    默认情况下, 在 map 上 scrolling 的效果是 zoom. 这个体验不一定是期望的, 用户可能是想 scroll 页面, 只是鼠标碰巧放在 map 上面.

    解决方法是在 config 添加 gestureHandling

    new google.maps.Map(document.querySelector(".map")!, {
      gestureHandling: "cooperative",
    });

    效果

    当用户不小心 scroll 到的, 不会有 zoom 的效果, 同时会出现提示. 用 zoom 请使用 ctrl + scroll.

    Custom Map Style

    上面最终效果的主题颜色并不是默认的. 它是灰色系的.

    主题可以到这里 mapstyle.withgoogle.com, 它有 2 种方法.

    1. 用 Cloud, 这样代码就不需要包含 styling 逻辑. 它在一开始的 Script API 就会链接到 Cloud 设置好的 Styling.

    2. 下载 JSON 文件.

    下面就是最终效果的配置

     

    它默认的 labels.icon 会把 Singapore 给 hide 起来, 所以我修改了它的 JSON file.

    最后把 style 掉进去就可以了.

    new google.maps.Map(document.querySelector(".map")!, {
      styles: [], // <-- put json array here
    });

    Places Library

    参考: Docs – Places Library 

    它是一个 service, 可以通过 query 找到 place info. 比如 query=my-company-name

    它会返回坐标, 地址, reviews count, reviews rating, opening hours 等等.

    它有许多方法可以用来 search, 但目前只用到 Find Place from Query 就足够了. 

    代码

    const map = new google.maps.Map(document.querySelector(".map")!);
    const service = new google.maps.places.PlacesService(map);
    service.findPlaceFromQuery(
      {
        query: "Coolman Aircon",
        fields: [
          "place_id",
          "geometry",
          "name",
          "formatted_address",
          "rating",
          "user_ratings_total",
        ],
      },
      (results, status) => {
        if (status === google.maps.places.PlacesServiceStatus.OK) {
          console.log("callback", results!.filter(result => result.name! === query)[0]);
        }
      }
    );

    还有什么可用的 fields 可以参考这里

    注: query=my-company-name 是有可能会找到超过 1 个 results 的哦, 我会通过 filter name 来获取准确的那一个.

    效果

     

    分别对应了 info window 需要的内容

    name, formatted_address, rating, user_ratings_total

    view larger map 需要 place_id

    directions 则是 name + formatted_address

    geometry 是给 marker 用的

    Marker

    const map = new google.maps.Map(document.querySelector(".map")!, {
      center: {
        lat: 1.284491,
        lng: 103.845951,
      },
      zoom: 10,
    });
    new google.maps.Marker({
      map,
      position: {
        lat: 1.284491,
        lng: 103.845951,
      },
    });

    position 就拿上面 place info 的 geometry.

    Marker Styling

    参考: 

    Docs – Markers

    Docs – Custom Markers

    默认的 marker 是红色的. 通常和网站主题颜色不搭.

    有 2 种替换方式.

    1. 用 svg path. 这个挺难搞的, 它长这样.

    首先那个 path 可以从 .svg file 里面抄出来. 如果有多个 path 就用逗号分割, 然后拼接到后面就可以了.

    fillColor 控制颜色, fillOpacity 默认是 0 哦. 如果要颜色记得配置

    stroke 是控制 border 

    最难搞的是 icon 的 size. 它只能通过 scale 去控制大小. 然后 origin 老是抓不准. 所以会一直跑位. 估计是修改配置 anchor 或者 origin 之类的.

    但我已经没有耐性玩了. 所以还是用第 2 种方法吧.

    2. 用 .svg 图片

    提前把 svg 图片弄好. fill, width, heigth 都 set 好. 然后直接 link 就可以了.

    不嫌弃的话, 也可以用 Google 提供的 icon: Google Earth/Maps Icons

    Zoom to All Marker

    上面 create map 的时候, 我们 hardcode 了 center 和 zoom. 这样是不 ok 的.

    正确的做法是依据所有的 marker 调整 zoom, 尽可能的显示所有 markers.

    参考: Stack Overflow – Auto-center map with multiple markers in Google Maps API v3

    const map = new google.maps.Map(document.querySelector(".map")!, {
      maxZoom: 10, // 避免 auto zoom 太大
    });
    const bounds = new google.maps.LatLngBounds();
    bounds.extend({
      // 收集 marker 坐标 1
      lat: 1.284491,
      lng: 103.845951,
    });
    bounds.extend({
      // 收集 marker 坐标 2
      lat: 1.284491,
      lng: 103.845951,
    });
    map.fitBounds(bounds); // 调整 map zoom 和 center

    主要用到了 LatLngBounds 和 fitBounds 方法. 担心自动 zoom 太大的话, 可以 set 一个 maxZoom.

    Info Window

    参考: Docs – Info Windows

    const map = new google.maps.Map(document.querySelector(".map")!, {
      center: {
        lat: 1.284491,
        lng: 103.845951,
      },
      zoom: 10,
    });
    
    const marker = new google.maps.Marker({
      position: {
        lat: 1.284491,
        lng: 103.845951,
      },
      map,
      clickable: true,
    });
    
    const infowindow = new google.maps.InfoWindow({
      content: `<h1 class="my-h1">Hello World</h1>`,
    });
    
    marker.addListener("click", () => {
      infowindow.open({
        anchor: marker,
        map,
        shouldFocus: false,
      });
    });

    assign Raw HTML 给 InfoWindow.content 就可以了. CSS Selector 可以直接 select 到 .map .my-h1

    所以 apply style 不是问题. (以前好像是不可以的, 在 Stack Overflow 有看到以前的许多提问)

    Google Map Link

    最后说一下 reviews, view larger map, directions 的 link

    参考:

    Stack Overflow – Link to Google Maps Directions using place_id

    Stack Overflow – Getting Google Maps link from place_id

    Docs – directions

    reviews link

    const reviewsLink = `https://search.google.com/local/reviews?placeid=${data.placeId}`

    placeId 到 place info 里拿.

    view larger map link

    const viewLargerMapLink = `https://maps.google.com/maps?q=place_id:${data.placeId}`

    directions link

    const directionsLink = `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(
            `${data.name},${data.address}`
          )}`

    direction 没有用到 placeId, 反而是用到了 name 和 formatted_address

  • 相关阅读:
    【笔记】Maven使用入门
    【笔记】c++文件
    【笔记】IntelliJ IDEA配置Hibernate
    【HTML5校企公益课】第四天
    【c++习题】【17/4/16】动态分配内存
    C#
    C#
    C#
    C#
    C#
  • 原文地址:https://www.cnblogs.com/keatkeat/p/16467565.html
Copyright © 2020-2023  润新知