Google Map 系列「一」

1,069 阅读4分钟

一、注册账号

  1. Google map platform 去Get started。

二、使用Google Cloud

三、使用API密钥

四、开始使用

准备工作 加载MAPJS

  1. 方式一 旧版本脚本加载(适用于非SPA应用)
    index.html插入

  2. 方式二 旧版本脚本加载(适用SPA/微前端)
    这种方式本质上和方式一是一致的,不过此种方式多一种弊端,多次进入页面会导致页面上一直append 这段js进去,不推荐此方式

    const MAPAPISCHEME = "maps.googleapis.com/maps/api/js… YOUR GOOGLE MAP KEY }&callback=initMap&libraries=drawing" const script = document.createElement('script'); script.src = MAPAPISCHEME; document.body.appendChild(script);

必需参数(旧版)

加载 Maps JavaScript API 时必须提供以下参数。

  • key:您的 API 密钥。除非指定了有效的 API 密钥,否则 Maps JavaScript API 不会加载。
  • callback:Maps JavaScript API 完全加载后要调用的全局函数的名称。

可选参数(旧版)

使用这些参数可以请求特定版本的 Maps JavaScript API、加载其他库、将地图本地化或指定 HTTP 引荐来源网址检查政策

  • v:要使用的 Maps JavaScript API 的版本
  • libraries:要加载的其他 Maps JavaScript API 的逗号分隔列表。
  • language:要使用的语言。该参数会影响控件名称、版权通知、行车路线、控件标签和对服务请求的响应。请参阅支持的语言列表
  • region:要使用的区域代码。它会根据给定国家或地区更改地图的行为。
  • solution_channel:Google Maps Platform 提供了许多类型的示例代码,可帮助您快速上手。为了跟踪更复杂的代码示例的采用情况并提高解决方案质量,Google 在示例代码的 API 调用中添加了 solution_channel 查询参数。注意:此查询参数仅供 Google 使用。如需了解详情,请参阅 Google Maps Platform 解决方案参数
  • auth_referrer_policy:Maps JS 客户可以在 Cloud 控制台中配置 HTTP 引荐来源网址限制,以限制哪些网址可以使用特定的 API 密钥。默认情况下,这类限制可以配置为仅允许某些路径使用某个 API 密钥。如果同一网域或同一来源的任何网址都可以使用该 API 密钥,您可以在授权来自 Maps JavaScript API 的请求时设置 auth_referrer_policy=origin,以限制发送的数据量。此参数从版本 3.46 开始提供。如果指定了此参数并且在 Cloud 控制台中启用了 HTTP 引荐来源网址限制,则只有在 HTTP 引荐来源网址限制与当前网站的网域匹配(未指定路径)的情况下,Maps JavaScript API 才能加载。
  1. 方式三 使用NPM加载

  2. 安装 npm install @googlemaps/js-api-loader

    import { Loader } from "@googlemaps/js-api-loader"

    const loader = new Loader({ apiKey: "YOUR_API_KEY", version: "weekly", ...additionalOptions, });

    loader.load().then(async () => { const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary; map = new Map(document.getElementById("map") as HTMLElement, { center: { lat: -34.397, lng: 150.644 }, zoom: 8, }); });

  3. 方式三 使用动态库(适用非SPA/SPA/微前端)
    异步加载,没有那么多乱七八糟的bug,推荐此方式

  4. 将内嵌引导加载程序加载器添加到应用代码中,以加载 Maps JavaScript API,如以下代码段所示:

其中参数示意如下:

必填参数

  • key:您的 API 密钥。除非指定了有效的 API 密钥,否则 Maps JavaScript API 不会加载。

可选参数

  • v:要加载的 Maps JavaScript API 的版本
  • libraries:要加载的其他 Maps JavaScript API 的逗号分隔列表。通常不建议指定一组固定的库,但对于希望微调其网站上的缓存行为的开发者,不妨使用。
  • language:要使用的语言。该参数会影响控件名称、版权通知、行车路线、控件标签和对服务请求的响应。请参阅支持的语言列表
  • region:要使用的区域代码。它会根据给定国家或地区更改地图的行为。
  • solutionChannel:Google Maps Platform 提供了许多类型的示例代码,可帮助您快速上手。为了跟踪更复杂的代码示例的采用情况并提高解决方案质量,Google 在示例代码的 API 调用中添加了 solutionChannel 查询参数。
  • authReferrerPolicy:Maps JS 客户可以在 Cloud 控制台中配置 HTTP 引荐来源网址限制,以限制哪些网址可以使用特定的 API 密钥。默认情况下,这类限制可以配置为仅允许某些路径使用某个 API 密钥。如果同一网域或同一来源的任何网址都可以使用该 API 密钥,您可以在授权来自 Maps JavaScript API 的请求时设置 authReferrerPolicy: "origin",以限制发送的数据量。如果指定了此参数并且在 Cloud 控制台中启用了 HTTP 引荐来源网址限制,则只有在 HTTP 引荐来源网址限制与当前网站的网域(未指定路径)匹配的情况下,Maps JavaScript API 才会加载。

迁移到 Dynamic Library Import API

首先,将旧版脚本加载代码替换为内嵌引导加载程序加载器代码。

之前

<script async
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
  </script>

之后

接下来,更新您的应用代码:

  • 将 initMap() 函数更改为异步函数。
  • 调用 importLibrary() 以加载并访问所需的库。

之前

let map;

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: -34.397, lng: 150.644 },
    zoom: 8,
  });
}

window.initMap = initMap;

之后

let map;
// initMap is now async
async function initMap() {
  // Request libraries when needed, not in the script tag.
  const { Map } = await google.maps.importLibrary("maps");
  // Short namespaces can be used.
  map = new Map(document.getElementById("map"), {
    center: { lat: -34.397, lng: 150.644 },
    zoom: 8,
  });
}

initMap();

typescript

  1. 安装类型语言包

    npm i -D @types/google.maps

  2. 使用

    let map: google.maps.Map; const center: google.maps.LatLngLiteral = {lat: 30, lng: -110};

    function initMap(): void { map = new google.maps.Map(document.getElementById("map") as HTMLElement, { center, zoom: 8 }); }

最佳实践

<script>
  (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: "YOUR_API_KEY_HERE",
    libraries:'drawing'
    // Add other bootstrap parameters as needed, using camel case.
    // Use the 'v' parameter to indicate the version to load (alpha, beta, weekly, etc.)
  });
</script>


<script setup lang="ts">
import { IndoesiaPoint } from '@/global/const'
import { watchEffect } from 'vue'
let map: google.maps

const initMap = async () => {
  const center = IndoesiaPoint
  const { Map } = await google.maps.importLibrary('maps')
  map = new Map(document.getElementById('map'), {
    zoom: 8,
    center,
    mapTypeControl: true,
    zoomControl: true
  })
}

watchEffect(() => {
  console.log('watchEffect')
  initMap()
})
</script>
<template>
  <div class="page-map">
    <div id="map"></div>
  </div>
</template>
<style scoped lang="less">
.page-map {
  height: 100vh;
  width: 100vw;
}
#map {
  /* The height is 400 pixels */
  width: 100%;
  height: 100%;
  /* The width is the width of the web page */
  border-radius: 10px;
  #content {
    color: red;
  }
}
</style>

效果

五、Marker

Google Marker 文档

使用marker

google.maps.Marker 类

通过调用 const {Marker} = await google.maps.importLibrary("marker")进行使用。

最佳实践

marker

<script setup lang="ts">
  import { IndoesiaPoint } from '@/global/const'
  import { watchEffect } from 'vue'
  let map: any
  let markers: google.maps.Marker[] = []

  const initMap = async () => {
    const center = IndoesiaPoint
    // @ts-ignore
    const { Map } = await google.maps.importLibrary('maps')
    map = new Map(document.getElementById('map'), {
      zoom: 10,
      center,
      mapTypeControl: true,
      zoomControl: true
    })

    // 加载marker
    initMarker()
  }

  const initMarker = async () => {
    // @ts-ignore
    const { Marker } = await google.maps.importLibrary('marker')
    // 可以循环加载多个
    const marker = new Marker({
      optimized: true,
      position: { lat: -6.905924, lng: 107.59888 },
      title: `印尼唐格朗`,
      icon: '//static.xyb2b.com/images/bd56d0f777c22d4286b206ff71e7259d.svg',
      map
    })
    markers.push(marker)
  }

  watchEffect(() => {
    console.log('watchEffect')
    initMap()
  })
</script>
<template>
  <div class="page-map">
    <div id="map"></div>
  </div>
</template>
<style scoped lang="less">
  .page-map {
    height: 100vh;
    width: 100vw;
  }
  #map {
    /* The height is 400 pixels */
    width: 100%;
    height: 100%;
    /* The width is the width of the web page */
    border-radius: 10px;
    #content {
      color: red;
    }
  }
</style>

添加点击事件

const initMarker = async () => {
...
  marker.addListener('click', () => {
    infowindow.setContent('loading...')
    infowindow?.open({
      anchor: marker,
      map: map
    })
    let contentStr = '这是我想放置的数据' // 这里可以放你想显示的任何数据
    infowindow.setContent(contentStr)
  })

....

}

删除maerker

Tips可以通过setMap(null)来消除已经渲染的marker

外层定义一个markers ,将每一个marker push进去后每次需要删除的时候,循环markers去setMap(null)

// 删除marker
const deleteMarker = () => {
  markers?.forEach((m) => {
    m?.setMap(null)
  })
}

六、多边形

Google 多边形 文档

Polyline 类 (多段线)

google.maps.Polyline 类

折线是地图上的连接线段的线性叠加层。

此类扩展了 MVCObject

通过调用 const {Polyline} = await google.maps.importLibrary("maps") 访问。

最佳实践

<script setup lang="ts">
import { IndoesiaPoint } from '@/global/const'
import { watchEffect } from 'vue'
import type { Points } from './interface'
const iconUrl = '//static.xyb2b.com/images/a666c7fd32b9cf97848f1d271de0f1bf.svg'
let map: any
let markers: google.maps.Marker[] = []
let infowindow: google.maps.InfoWindow
let polylines: google.maps.Polyline = []

// 模拟多段线
const polylinePaths: Points[] = [
  { lat: -7.101935050883591, lng: 107.4588552036972 },
  { lat: -6.694838728520297, lng: 107.75462324500616 },
  { lat: -6.847630347242984, lng: 108.19105762732289 },
  { lat: -7.178153561208554, lng: 108.13234630024549 },
  { lat: -7.5499689900116005, lng: 107.909873169182 },
  { lat: -6.64506887158396, lng: 106.31099036415657 },
  { lat: -8.021581922136363, lng: 108.26073130399932 }
]

const initMap = async () => {
  const center = IndoesiaPoint
  // @ts-ignore
  const { Map } = await google.maps.importLibrary('maps')
  map = new Map(document.getElementById('map'), {
    zoom: 10,
    center,
    mapTypeControl: true,
    zoomControl: true
  })

  // @ts-ignore
  const { InfoWindow } = await google.maps.importLibrary('maps')
  infowindow = new InfoWindow()
  // 加载marker
  initMarker()
  // 多段线Polyline 类
  initPolyline()
}

const initMarker = async () => {
  deleteMarker()
  // @ts-ignore
  const { Marker } = await google.maps.importLibrary('marker')
  // 可以循环加载多个
  const marker = new Marker({
    optimized: true,
    position: { lat: -6.905924, lng: 107.59888 },
    title: `印尼唐格朗`,
    icon: iconUrl,
    map
  })

  marker.addListener('click', () => {
    infowindow.setContent('loading...')
    infowindow?.open({
      anchor: marker,
      map: map
    })
    let contentStr = '这是我想放置的数据' // 这里可以放你想显示的任何数据
    infowindow.setContent(contentStr)
  })

  markers.push(marker)
}

// 删除marker
const deleteMarker = () => {
  markers?.forEach((m) => {
    m?.setMap(null)
  })
}

// 批量设置marker
const setMarker = async (position: Points) => {
  // @ts-ignore
  const { Marker } = await google.maps.importLibrary('marker')
  // 可以循环加载多个
  const marker = new Marker({
    optimized: true,
    position: position,
    title: `${Object.values(position).join(',')}`,
    icon: iconUrl,
    map
  })

  marker.addListener('click', () => {
    infowindow.setContent('loading...')
    infowindow?.open({
      anchor: marker,
      map: map
    })
    let contentStr = '这是我想放置的数据' // 这里可以放你想显示的任何数据
    infowindow.setContent(contentStr)
  })

  markers.push(marker)
}

// 多段线
const initPolyline = async () => {
  //@ts-ignore
  const { Polyline } = await google.maps.importLibrary('maps')
  const polyline = new Polyline({
    map,
    path: polylinePaths,
    strokeColor: '#FF6801',
    strokeOpacity: 0.9,
    strokeWeight: 3,
    clickable: false
  })
  polylines.push(polyline)

  // 可以配合 设置marker 让路线更具体
  polylinePaths.forEach((position: Points) => {
    setMarker(position)
  })
}

watchEffect(() => {
  console.log('watchEffect')
  initMap()
})
</script>
<template>
  <div class="page-map">
    <div id="map"></div>
  </div>
</template>
<style scoped lang="less">
.page-map {
  height: 100vh;
  width: 100vw;
}
#map {
  /* The height is 400 pixels */
  width: 100%;
  height: 100%;
  /* The width is the width of the web page */
  border-radius: 10px;
  #content {
    color: red;
  }
}
</style>

Polygon 类(多段线闭合)

google.maps.Polygon 类

多边形(类似于折线)可定义一系列有序的相连坐标。此外,多边形会形成一个闭合环并定义一个填充区域。请参阅开发者指南中的示例,从简单的多边形带孔的多边形开始,等等。请注意,您还可以使用数据层创建多边形。数据图层可让您更轻松地创建内环,因为它会为您处理内外侧路径的顺序。

此类扩展了 MVCObject

通过调用 const {Polygon} = await google.maps.importLibrary("maps") 访问

最佳实践

...
// polygon类 闭合线
const initPolygon = async () => {
  // @ts-ignore
  const { Polygon } = await google.maps.importLibrary('maps')
  const polygon = new Polygon({
    path: polylinePaths,
    strokeColor: '#FF6801',
    strokeOpacity: 0.9,
    strokeWeight: 3,
    clickable: false,
    fillColor: '#FF6801',
    map
  })
  polyons.push(polygon)
}
...

附:本文源码 github.com/JolyI/googl…

未完待续

下一节:

Polygon类补充(自定义画框框)

Rectangle 类(四边形)

Circle 类(圆形)

地位位置反编码