赞
踩
mapbox-gl.js - leaflet的插件
前端渲染矢量瓦片交互地图的工具
mapbox-gl.js必须要支持WebGL(旧浏览器不支持)
GIS需要处理的两部分:数据来源+数据在界面显示的样子,style中的source、layer对应这两个部分
首先是注册登录,银行卡号的部分使用了随机生成器,邮编随便填一个,可能会报错但依然会发送确认邮件,确认后可以成功注册。
随机生成器网址:银行卡随机生成器
1、头部引入mapbox
<script src='https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css' rel='stylesheet' />
2、定义一个容器来显示地图
<div id='map' style='width: 100%; height: 100%;'></div>
3、script里设置map对象和相关参数
<script>
mapboxgl.accessToken = '这里填官网获取的token';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [118.38, 31.33],//芜湖市的经纬度(可以填你想要显示的城市经纬度)
zoom: 9
});
此时可以显示芜湖为中心的地图了
在头部引入mapbox-gl-language.js,将地图上显示的文字转换为中文
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-language/v1.0.0/mapbox-gl-language.js'></script>
在srcipt内部设置:
mapboxgl.setRTLTextPlugin('https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-rtl-text/v0.1.0/mapbox-gl-rtl-text.js');
map.addControl(new MapboxLanguage({defaultLanguage: "zh-Hans"}));
数组形式[A,B],A是经度,B是维度
1、获取想显示的区域json数据:进入阿里云数据可视化平台获取DataV.GeoAtlas地理小工具系列 (aliyun.com)
在jiujiang.js文件中定义变量
var jiujiangJSON = {...}//此处放从网站上复制下来的json数据
2、在头部引入区域的js文件
<script src="./jiujiang.js"></script>
3、在地图加载后,增加图层,在这个图层上绘制type='fill'
也就是区域,在'paint'
里设置绘制的区域样式
map.on('load', function () {
map.addLayer({
'id': 'jiujiang',
'type': 'fill',
'source': {
'type': 'geojson',
'data': jiujiangJSON
},
'layout': {},
'paint': {
'fill-color': '#088',
'fill-opacity': 0.4,
}
});
});
其中:
type - 放的是绘制的类型,此处是fill,如果要绘制线条,就设置为line
source - 其中的data放json数据,由于头部引入了js文件,直接使用js文件里的变量名jiujiang JSON来获取json数据
paint - 在这里配置绘图的样式,比如区域颜色,透明度等,这里设置的属性应该和type对应,可以去查看开发文档,有详细说明。或者看此链接地图样式有详细整理
4、如果希望区域的边界线条更明显,则需要另外实现一个图层来绘制线条,因为fill相关属性没有设置线条宽度的属性
map.addLayer({
'id': 'jiujiangline',
'type': 'line',
'source': {
'type': 'geojson',
'data': jiujiangJSON
},
'layout': {},
'paint': {
'line-color': 'blue',
'line-width': 3
}
});
效果如下:
1、获取这个区域的一些点坐标,放入json文件
var pointsJSON = { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [118.176944, 31.18] }, }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [118.103611, 31.261944] }, }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [118.039654, 31.19909] }, }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [118.0209734, 31.282277] }, }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [118.109444, 31.284444] }, } ] }
2、由于要使用自定义的点图标,因此使用loadImage方法,加载图标
*注意:如果使用vscode练习,会出现本地路径访问异常的问题,下载一个Live Server的插件,并点击右下角GoLive可以解决问题。
map.loadImage('./site.png', function(error, image) { if (error) throw error; map.addImage('pointImg', image); map.addLayer({ "id": "points", "type": "symbol", "source": { "type": "geojson", "data": pointsJSON }, "layout": { "icon-image": "pointImg", "icon-size": 0.1 } }); });
data里的数据和区域部分处理方式相同,icon-size设置图标在地图上的显示大小,效果如下:
正确加载主要是依托经纬度和瓦片的互转算法
瓦片分层理解:
图上分了三层,可以想象最开始地图展示的中国地图是最上层,只需要一张瓦片(256px*256px);接着对地图进行放大,页面展示出了某省地图,此时信息量变多,像素变高,需要很多张瓦片显示。
瓦片的坐标原点在世界地图的左上角,西经180 º北纬85 º左右,Z表示缩放层级,瓦片编号规则如下图所示:
使用的地图商:
高德地图、谷歌地图、OpenStreetMap
瓦片坐标的原点在本初子午线和赤道的交汇处(经度0纬度0),Z从1开始,在最高级就把地图分为四块瓦片,瓦片编号规则如下图所示:
mapbox的地图资源基于OSM,其坐标系使用的是WGS84
高德地图和腾讯地图坐标系是GCJ02
const {PI} = Math // 球体长半径 const SPHERE_RADIUS = 6378245.0 // 扁率 const FLATNESS = 0.00669342162296594323 const ER = 20037508.342789 function transformLat(inputLng, inputLat) { const lat = +inputLat const lng = +inputLng let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)) ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0 ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0 ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0 return ret } function transformLng(inputLng, inputLat) { const lat = +inputLat const lng = +inputLng let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)) ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0 ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0 ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0 return ret } /** * 判断是否在国内,不在国内则不做偏移 * @param lng * @param lat * @returns {boolean} */ function outOfChina(inputLng, inputLat) { const lat = +inputLat const lng = +inputLng // 纬度 3.86~53.55, 经度 73.66~135.05 return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55) }
function wgs84ToGcj02(inputLng, inputLat) { const lat = +inputLat const lng = +inputLng if (outOfChina(lng, lat)) { return [lng, lat] } else { let dLat = transformLat(lng - 105.0, lat - 35.0) let dLng = transformLng(lng - 105.0, lat - 35.0) const radLat = lat / 180.0 * PI let magic = Math.sin(radLat) magic = 1 - FLATNESS * magic * magic const sqrtMagic = Math.sqrt(magic) dLat = (dLat * 180.0) / ((SPHERE_RADIUS * (1 - FLATNESS)) / (magic * sqrtMagic) * PI) dLng = (dLng * 180.0) / (SPHERE_RADIUS / sqrtMagic * Math.cos(radLat) * PI) const mgLat = lat + dLat const mgLng = lng + dLng return [mgLng, mgLat] } }
function gcj02towgs84(lng, lat){ if (outOfChina(lng, lat)){ return [lng, lat] }else { dlat = transformLat(lng - 105.0, lat - 35.0) dlng = transformLng(lng - 105.0, lat - 35.0) radlat = lat / 180.0 * PI magic = Math.sin(radlat) magic = 1 - FLATNESS * magic * magic sqrtmagic = Math.sqrt(magic) dlat = (dlat * 180.0) / ((SPHERE_RADIUS * (1 - FLATNESS)) / (magic * sqrtmagic) * PI) dlng = (dlng * 180.0) / (SPHERE_RADIUS / sqrtmagic * Math.cos(radlat) * PI) mglat = lat + dlat mglng = lng + dlng return [lng * 2 - mglng, lat * 2 - mglat] } }
1、尝试在mapbox上再加载高德API(更美观,道路等更全)
//头部加上
<!-- 加载地图JSAPI脚本 -->
<script src="https://webapi.amap.com/maps?v=2.0&key=096ec74ca9fc2c8f7958c064fc918827"></script>
2、设置全局变量,确定中心和图层
const center = [118.450393,31.341593]
const zoom = 11
3、初始化地图
const amapMap = new AMap.Map('amap', {
viewMode: '3D',
pitch: 0,
zoom: zoom + 1, //初始化地图层级
center: aMapCenter //初始化地图中心点
})
4、由于center此时的经纬度是WGS84下的,因此需要通过转换的方法,转换成GJC02,这样高德地图的中心就可以定在正确的位置
const aMapCenter = wgs84ToGcj02(center[0],center[1])
5、监听mapbox的move和zoom事件(也就是拖动和放大缩小)
mapboxMap.on('move', () => {
linkAMap()
})
mapboxMap.on('zoom', () => {
linkAMap()
});
6、linkAMap方法,就是让地图的中心变化,setZoom和setCenter方法中第二个参数定为true,作用是地图不是缓慢变化的,不会呈现移动的效果
function linkAMap(){
const mapboxZoom = mapboxMap.getZoom() + 1
const mapboxCenter = mapboxMap.getCenter()
amapMap.setZoom(mapboxZoom,true)
amapMap.setCenter(wgs84ToGcj02(mapboxCenter.lng,mapboxCenter.lat),true)
}
其中调用了坐标系转换方法
同步去通过转换让高德的定位和mapbox重合,此时两个容器就重叠了
此时上点,由于是以WGS84为坐标系,因此坐标还应是wgs84下坐标可以看到成功显示,位置正确:
结果也显示正确
插件介绍地址:mapboxgl 纠偏百度地图 - 知乎 (zhihu.com)
效果:
此原理和整合不同,是加载每张瓦片时进行一个对应
此文主要是我对于mapbox的学习和实验,在实践中加强对地图知识的认知,其中借鉴了许多优秀的文章,希望能帮助到有需要的人,如有问题欢迎交流~
个人demo链接,可供参考:mapbox本文demo
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。