文章目录
Mapbox地图使用矢量切片技术和地图渲染技术(Mapbox GL)实现。前端通过Mapbox GL JS进行渲染,Mapbox GL JS是一个Java Script库,使用WebGL渲染交互式矢量瓦片地图和栅格瓦片地图,渲染性能高。它能够解析各种来源的矢量数据,然后在客户端实时渲染生成带有几何图形、文字标注、图示符号3D场景地图。Mapbox GL JS不仅能够渲染大数据量的地图要素,拥有流畅的交互以及动画效果,而且还可以显示立体地图。
1. 显示地图:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<-- 引入相关的库 -->
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// 访问令牌accessToken
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
// 地图对象Map
var map = new mapboxgl.Map({
container: 'map', // Mapbox GL JS 进行地图渲染的 HTML 元素
style: 'mapbox://styles/mapbox/streets-v11', // 地图的 Mapbox 配置样式
center: [-74.5, 40], // 地图初始化时的地理中心点 [lng, lat]
zoom: 9 // 地图初始化时的层级
});
</script>
</body>
</html>
地图对象Map有参数,实例成员和事件。
参数:
就是上面的container
、style
等;
实例成员:
比如on(type,listener)
,可以为特定类型的事件添加监听器,其中type(string)
添加监听器的事件类型,(包括'mousedown'
, 'mouseup'
,'mousemove'
、'click'
、'load'
),listener(Function)
事件被触发时调用的函数;
事件:
就是上面的'mousedown'
, 'mouseup'
,'mousemove'
、'click'
、'load'
。
地图上常见的操作包括绘制点,绘制路径、添加标记、按钮等。看下面的实例:
2.在地图上添加一个图标
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add an icon to the map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11'
});
// 添加地图初始化监听事件
map.on('load', function() {
// loadImage(url,callback)从外部 URL 载入图像,参数callback(Function)形式为 callback(error, data)
map.loadImage(
'https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png',
function(error, image) {
if (error) throw error;
map.addImage('cat', image); // 给样式添加图像
map.addSource('point', { // 为地图的样式添加数据源
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [0, 0]
}
}]
}
});
// 添加一个 Mapbox 样式的图层 到地图样式
map.addLayer({
'id': 'points',
'type': 'symbol',
'source': 'point',
'layout': {
'icon-image': 'cat',
'icon-size': 0.25
}
});
}
);
});
</script>
</body>
</html>
上面用到了on(type,listener)
、loadImage(url,callback)
、addImage(id,image,options)
、addSource(id,source)
、addLayer(layer,beforeId?)
等实例成员。
这里其实是添加了一个图层,该图层需要数据源所以先从互联网上加载图片,之后添加图片,将位置和图片传给图层之后显示。其中涉及到了mapbox数据源、Geojson格式的数据和mapbox图层定义。
mapbox数据源:
source
表明地图应显示哪些数据。使用“type”
属性指定源的类型,该属性必须是 vector, raster, raster-dem, geojson, image, video(矢量,栅格,栅格dem,geojson,图像,视频)之一。
添加一个source
不足以使数据显示在地图上,因为source
不包含颜色或宽度等样式细节。图层Layer
为source
提供可视化表示。这样就可以以不同的方式对同一source
进行样式设置。
GeoJSON源数据必须通过data
属性提供,其属性可以是URL或内联GeoJSON。
"geojson-marker": {
"type": "geojson",
"data": {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-77.0323, 38.9131]
},
"properties": {
"title": "Mapbox DC",
"marker-symbol": "monument"
}
}
}
Geojson格式数据:
地理空间分析工具库:基于JAVA语言的JTS
库,基于Javascript的JSTS
、Turf.js
库(由Mapbox 提供),以及基于c++的geos
库等。
GeoJSON是一种基于JSON的地理空间数据交换格式,GeoJSON对象可以表示几何(Geometry)、特征(Feature)或者特征集合(FeatureCollection)。GeoJSON支持下面几何类型:点(Point)、线(LineString)、面(Polygon)、多点(MultiPoint)、多线(MultiLineString)、多面(MultiPolygon)和几何集合(GeometryCollection)。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。
GeoJSON使用唯一地理坐标参考系统WGS1984和十进制度单位。
![image-20200721114408312](https://i-blog.csdnimg.cn/blog_migrate/9c8cf0b6a68422a5bfe65b3b9883da50.png)
![image-20200721114541627](https://i-blog.csdnimg.cn/blog_migrate/4c1d7b172381c76f4d44bd323aa78b23.png)
一个完整的GeoJSON数据结构总是一个(JSON术语里的)对象。
GeoJSON对象必须有一个名字为"type"
的成员,type成员的值必须是下面之一:“Point”, “MultiPoint”, “LineString”, “MultiLineString”, “Polygon”, “MultiPolygon”, “GeometryCollection”, “Feature”, 或者 “FeatureCollection”。
几何对象是一种GeoJSON对象,这时type成员的值是下面字符串之一:“Point”, “MultiPoint”, “LineString”, “MultiLineString”, “Polygon”, “MultiPolygon”, 或者"GeometryCollection"。 除了“GeometryCollection”外的其他任何类型的GeoJSON几何对象必须由一个名字为"coordinates"
的成员。coordinates成员的值总是数组,其中元素遵从经度、纬度、高度的顺序。这个数组里的元素的结构由几何类型来确定。
类型type为"Feature"
的GeoJSON对象是特征对象。特征对象必须由一个名字为"geometry"
的成员,这个几何成员的值是上面定义的几何对象或者JSON的null值;特征对象还必须有一个名字为“properties"
的成员,这个属性成员的值是一个对象(任何JSON对象或者JSON的null值)。
类型type为"FeatureCollection"
的GeoJSON对象是特征集合对象。类型为"FeatureCollection"的对象必须由一个名字为"features"的成员。与“features"
相对应的值是一个数组。这个数组中的每个元素都是上面定义的特征对象。
例如一个 GeoJSON (特征集合)对象:
{
"type": "FeatureCollection", // 特征集合
"features": [ // 特征对象
{
"type": "Feature",
"geometry": // 几何对象
{
"type": "Point", //点
"coordinates": [102.0, 0.5]
},
"properties": // 属性
{
"prop0": "value0"
}
},
{
"type": "Feature",
"geometry": // 线段
{
"type": "LineString",
"coordinates": [
[102.0, 0.0],
[103.0, 1.0],
[104.0, 0.0],
[105.0, 1.0]
]
},
"properties":
{
"prop0": "value0",
"prop1": 0.0
}
},
{
"type": "Feature",
"geometry":
{
"type": "Polygon", // 多边形
"coordinates": [
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
},
"properties":
{
"prop0": "value0",
"prop1":
{
"this": "that"
}
}
}]
}
mapbox图层:
"layers": [
{
"id": "water",
"type": "fill",
"source": "mapbox-streets",
"paint": {
"fill-color": "#00ffff"
}
}
]
'id'
是唯一的图层名称。
图层的类型由'type'
属性指定,并且必须是background
, fill
, line
, symbol
, raster
, circle
, fill-extrusion
, heatmap
, hillshade
(背景(颜色或者图案),填充(具有可选描边边框的填充多边形),线,符号(图标或文字标签),栅格,实心圆,拉伸的(3D)多边形,热图,山体阴影)。
除了背景类型的图层外,每个图层都需要引用源source
。图层将从源中获取数据。
图层具有两个子属性,这些子属性确定如何渲染该图层中的数据:布局layout
和绘画paint
属性。
布局属性显示在图层的layout
对象中。它们将在渲染过程的早期应用,绘画属性将在稍后的渲染过程中应用。绘画属性显示在图层的paint
对象中。
3.添加GeoJSON线:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>添加 GeoJSON 线</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.1/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-122.486052, 37.830348],
zoom: 15
});
map.on('load', function() {
map.addLayer({
"id": "route",
"type": "line",
"source": {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[-122.48369693756104, 37.83381888486939],
[-122.48348236083984, 37.83317489144141],
[-122.48339653015138, 37.83270036637107],
[-122.48356819152832, 37.832056363179625],
[-122.48404026031496, 37.83114119107971],
[-122.48404026031496, 37.83049717427869],
[-122.48348236083984, 37.829920943955045],
[-122.48356819152832, 37.82954808664175],
[-122.48507022857666, 37.82944639795659],
[-122.48610019683838, 37.82880236636284],
[-122.48695850372314, 37.82931081282506],
[-122.48700141906738, 37.83080223556934],
[-122.48751640319824, 37.83168351665737],
[-122.48803138732912, 37.832158048267786],
[-122.48888969421387, 37.83297152392784],
[-122.48987674713133, 37.83263257682617],
[-122.49043464660643, 37.832937629287755],
[-122.49125003814696, 37.832429207817725],
[-122.49163627624512, 37.832564787218985],
[-122.49223709106445, 37.83337825839438],
[-122.49378204345702, 37.83368330777276]
]
}
}
},
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#888",
"line-width": 8
}
});
});
</script>
</body>
</html>
4.鼠标单击显示弹窗:
Controls
对象(地图控件), markers
对象(创建标记组件), 和 popups
对象(弹窗组件)为地图添加了新的用户界面元素。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a popup on click</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-77.04, 38.907],
zoom: 11.15
});
map.on('load', function() {
// 添加geojson数据源
map.addSource('places', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'properties': {
'description': '<strong>Make it Mount Pleasant</strong><p><a href="http://www.mtpleasantdc.com/makeitmtpleasant" target="_blank" title="Opens in a new window">Make it Mount Pleasant</a> is a handmade and vintage market and afternoon of live entertainment and kids activities. 12:00-6:00 p.m.</p>',
'icon': 'theatre'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.038659, 38.931567]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Mad Men Season Five Finale Watch Party</strong><p>Head to Lounge 201 (201 Massachusetts Avenue NE) Sunday for a <a href="http://madmens5finale.eventbrite.com/" target="_blank" title="Opens in a new window">Mad Men Season Five Finale Watch Party</a>, complete with 60s costume contest, Mad Men trivia, and retro food and drink. 8:00-11:00 p.m. $10 general admission, $20 admission and two hour open bar.</p>',
'icon': 'theatre'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.003168, 38.894651]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Big Backyard Beach Bash and Wine Fest</strong><p>EatBar (2761 Washington Boulevard Arlington VA) is throwing a <a href="http://tallulaeatbar.ticketleap.com/2012beachblanket/" target="_blank" title="Opens in a new window">Big Backyard Beach Bash and Wine Fest</a> on Saturday, serving up conch fritters, fish tacos and crab sliders, and Red Apron hot dogs. 12:00-3:00 p.m. $25.grill hot dogs.</p>',
'icon': 'bar'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.090372, 38.881189]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Ballston Arts & Crafts Market</strong><p>The <a href="http://ballstonarts-craftsmarket.blogspot.com/" target="_blank" title="Opens in a new window">Ballston Arts & Crafts Market</a> sets up shop next to the Ballston metro this Saturday for the first of five dates this summer. Nearly 35 artists and crafters will be on hand selling their wares. 10:00-4:00 p.m.</p>',
'icon': 'art-gallery'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.111561, 38.882342]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Seersucker Bike Ride and Social</strong><p>Feeling dandy? Get fancy, grab your bike, and take part in this year\'s <a href="http://dandiesandquaintrelles.com/2012/04/the-seersucker-social-is-set-for-june-9th-save-the-date-and-start-planning-your-look/" target="_blank" title="Opens in a new window">Seersucker Social</a> bike ride from Dandies and Quaintrelles. After the ride enjoy a lawn party at Hillwood with jazz, cocktails, paper hat-making, and more. 11:00-7:00 p.m.</p>',
'icon': 'bicycle'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.052477, 38.943951]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Capital Pride Parade</strong><p>The annual <a href="http://www.capitalpride.org/parade" target="_blank" title="Opens in a new window">Capital Pride Parade</a> makes its way through Dupont this Saturday. 4:30 p.m. Free.</p>',
'icon': 'rocket'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.043444, 38.909664]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Muhsinah</strong><p>Jazz-influenced hip hop artist <a href="http://www.muhsinah.com" target="_blank" title="Opens in a new window">Muhsinah</a> plays the <a href="http://www.blackcatdc.com">Black Cat</a> (1811 14th Street NW) tonight with <a href="http://www.exitclov.com" target="_blank" title="Opens in a new window">Exit Clov</a> and <a href="http://godsilla.bandcamp.com" target="_blank" title="Opens in a new window">Gods’illa</a>. 9:00 p.m. $12.</p>',
'icon': 'music'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.031706, 38.914581]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>A Little Night Music</strong><p>The Arlington Players\' production of Stephen Sondheim\'s <a href="http://www.thearlingtonplayers.org/drupal-6.20/node/4661/show" target="_blank" title="Opens in a new window"><em>A Little Night Music</em></a> comes to the Kogod Cradle at The Mead Center for American Theater (1101 6th Street SW) this weekend and next. 8:00 p.m.</p>',
'icon': 'music'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.020945, 38.878241]
}
},
{
'type': 'Feature',
'properties': {
'description': '<strong>Truckeroo</strong><p><a href="http://www.truckeroodc.com/www/" target="_blank">Truckeroo</a> brings dozens of food trucks, live music, and games to half and M Street SE (across from Navy Yard Metro Station) today from 11:00 a.m. to 11:00 p.m.</p>',
'icon': 'music'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.007481, 38.876516]
}
}
]
}
});
// 添加一个图层显示源中的所有数据
map.addLayer({
'id': 'places',
'type': 'symbol',
'source': 'places',
'layout': {
'icon-image': '{icon}-15',
'icon-allow-overlap': true
}
});
// on(type, layerId, listener) 为发生在特定样式图层要素上的特定事件添加监听器
// 事件将会得到一组包含匹配要素的 features 属性
map.on('click', 'places', function(e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;
// 确保将地图缩小,以使多个该功能的副本可见,并显示弹出窗口在指向的副本上
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup() // 新加一个popup对象
// 实例对象
.setLngLat(coordinates) // 设置好弹窗的锚的地理位置后使弹窗移动过去
.setHTML(description) // 将弹窗内容设置为以字符串形式提供的 HTML
.addTo(map); // 在地图上添加弹窗
});
// 当鼠标悬停在places图层上时,将光标更改为指针
map.on('mouseenter', 'places', function() {
map.getCanvas().style.cursor = 'pointer';
});
// 离开时将其更改回指针
map.on('mouseleave', 'places', function() {
map.getCanvas().style.cursor = '';
});
});
</script>
<style>
.mapboxgl-popup {
max-width: 400px;
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
}
</style>
</body>
</html>
5.添加标记
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add custom icons with Markers</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [123.38,41.8],
zoom: 5
});
// 绘制marker
var marker = new mapboxgl.Marker()
.setLngLat([123.38,41.8])
.setPopup(new mapboxgl.Popup() //为maeker标记设置弹窗
.setLngLat([123.38,41.8])
.setHTML("markerList_desc")
.addTo(map))
.addTo(map);
</script>
</body>
</html>
6.添加功能按钮
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add custom icons with Markers</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#menu {
position: absolute;
background: #fff;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
#menu2 {
position: absolute;
background: #fff;
padding: 10px;
font-family: 'Open Sans', sans-serif;
right: 0px;
bottom: 0px;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="menu">
<button onclick="changeSize(true);" style="width:40px;height:40px"><img src="icons/Zoomin.png" width="25" height="25" alt="放大" /></button>
<button onclick="changeSize(false);" style="width:40px;height:40px"><img src="icons/Zoomout.png" width="25" height="25" alt="缩小" /></button>
</div>
<div id="menu2">
<input name="style" type="radio" checked="true" onclick="changeStyle(0);" style="width:20px;height:20px" value="阳光白">阳光白
<input name="style" type="radio" onclick="changeStyle(1);" style="width:20px;height:20px" value="暗夜蓝">暗夜蓝
<input name="style" type="radio" onclick="changeStyle(2);" style="width:20px;height:20px" value="清淡蓝">清淡蓝
<input name="style" type="radio" onclick="changeStyle(3);" style="width:20px;height:20px" value="遥感">遥感
</div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
let mapboxStyle = [
'http://61.161.150.90:5081/api/v1/styles/aolutong/Bkl7eaQNyU',
'http://61.161.150.90:5081/api/v1/styles/aolutong/HJeN6h7VyL',
'http://61.161.150.90:5081/api/v1/styles/aolutong/ByetWaXVJL',
'mapbox://styles/mapbox/satellite-v9',
]
var map = new mapboxgl.Map({
container: 'map',
style: mapboxStyle[0],
center: [123.38, 41.8],
zoom: 5
});
function changeSize(bool) {
if (bool) {
map.setZoom(map.getZoom() + 1);
} else {
map.setZoom(map.getZoom() - 1);
}
}
function changeStyle(num) {
map.setStyle(mapboxStyle[num]);
}
</script>
</body>
</html>
7.绘制点聚类
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Create and style clusters</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb3NoaWhkIiwiYSI6ImNrNngzYnRhdzBqNm0zZnJ4eWZjdndrYzkifQ.qQjf8zANr9PsMpwq2NsRWQ';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [-103.59179687498357, 40.66995747013945],
zoom: 3
});
map.on('load', function() {
// Add a new source from our GeoJSON data and
// set the 'cluster' option to true. GL-JS will
// add the point_count property to your source data.
map.addSource('earthquakes', {
type: 'geojson',
// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes
// from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.
data:
'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson',
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
});
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'earthquakes',
filter: ['has', 'point_count'],
paint: {
// Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
// with three steps to implement three types of circles:
// * Blue, 20px circles when point count is less than 100
// * Yellow, 30px circles when point count is between 100 and 750
// * Pink, 40px circles when point count is greater than or equal to 750
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'earthquakes',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12
}
});
map.addLayer({
id: 'unclustered-point',
type: 'circle',
source: 'earthquakes',
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#11b4da',
'circle-radius': 4,
'circle-stroke-width': 1,
'circle-stroke-color': '#fff'
}
});
// inspect a cluster on click
map.on('click', 'clusters', function(e) {
var features = map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
var clusterId = features[0].properties.cluster_id;
map.getSource('earthquakes').getClusterExpansionZoom(
clusterId,
function(err, zoom) {
if (err) return;
map.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom
});
}
);
});
// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
map.on('click', 'unclustered-point', function(e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var mag = e.features[0].properties.mag;
var tsunami;
if (e.features[0].properties.tsunami === 1) {
tsunami = 'yes';
} else {
tsunami = 'no';
}
// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(
'magnitude: ' + mag + '<br>Was there a tsunami?: ' + tsunami
)
.addTo(map);
});
map.on('mouseenter', 'clusters', function() {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', function() {
map.getCanvas().style.cursor = '';
});
});
</script>
</body>
</html>