maptalk介绍
maptalks 是一个开源的地图框架,可以自定义地图资源,支持多种插件和功能
官方网站案例,尽管有时候地图可能由于网络问题加载不出来,但是这个是最为详细的了。
地图在uniapp的展示
首先需要在hybrid下的html新建html文档,以maptalk网站提供的案例为例
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>瓦片图层与地理投影 - WMS瓦片图层</title>
<style type="text/css">
html,body{margin:0px;height:100%;width:100%}
.container{width:100%;height:100%}
</style>
<link rel="stylesheet" href="https://unpkg.com/maptalks/dist/maptalks.css">
<script type="text/javascript" src="https://unpkg.com/maptalks/dist/maptalks.min.js"></script>
<body>
<div id="map" class="container"></div>
<script>
var map = new maptalks.Map('map', {
center: [-0.113049, 51.498568],
zoom: 6,
spatialReference: {
projection: 'EPSG:4326'
},
baseLayer: new maptalks.WMSTileLayer('wms', {
'tileSystem': [1, -1, -180, 90],
'urlTemplate': 'https://ows.terrestris.de/osm/service',
'crs': 'EPSG:4326',
'layers': 'OSM-WMS',
'styles': '',
'version': '1.3.0',
'format': 'image/png',
'transparent': true,
'uppercase': true
}),
attribution: {
content: '© ows.terrestris.de'
}
});
</script>
</body>
</html>
接着在view下面需要展示该内容的页面或者组件,先以页面为例
<view
style="background-color: aqua;height: 100vh;">
<web-view id="webview" @message="onMessage"
:update-title="false"
:fullscreen="false"
:webview-styles="webviewStyle"
src="/hybrid/html/map11.html?latitude=117.690828&longitude=39.016343&height=300px"></web-view>
</view>
其中webviewStyle决定了初始样式,这在h5页面可能是可以正常展示的,通过该样式调节在app存在异常,比如
在这个案例中
webviewStyle:{
height: 350,
width: 200,
left:50,
top:100,
// position:"relative"
},
但结果是
可以看到并没有上下进行移动,但进行了左右的移动。
事实上,官网提供的方法中只存在宽高设定,不存在top和left,但这个字段确实是有用的,可以用来调整嵌入位置,但得通过元素进行操作。
onReady() {
// // this.locate()
// const self = this;
// // #ifdef APP-PLUS
// self.currentWebview = this.$scope.$getAppWebview()
// // #endif
this.latitude = '115.5'
this.longitude = '35.5'
// self.currentWebview = self.$scope.$getAppWebview().children()[0]
console.log("wozai on readay");
const self = this;
// #ifdef APP-PLUS
self.currentWebview = this.$scope.$getAppWebview()
setTimeout(function() {
const wv = self.currentWebview.children()[0]
console.log("wv", wv, "这是wv");
// wv.setStyle({top:150,height:300})
wv.setStyle(self.webviewStyle)
}, 800)
// #endif
},
上处案例之中,我们通过onReady后天地改变了弹窗大小,使得他向下向右移动。
闪屏问题
不过此时存在一个问题,就是onReady的速度是较慢的,webview的渲染时间是在onReady之前的,所以会出现webview突然出现在屏幕中,然后突然大小发生变化,闪屏的体验极差。因此需要进行处置。
webviewStyle: {
height: 1,
width: 1,
}
设置最开始的页面大小只占一个像素,让他在最左侧不被注意,这样的显示就是正常的了。
组件中引用webview调整大小
通过以上步骤我们完成了一个基础地图的展示。不过当运用到组件的时候就是另一回事了,因为OnReady是页面的生命周期,在组件中无法生效。如果你尝试在组件使用mounted,这个时候会出现错误:
如果你使用OnReady,则什么都不会发生!!
如果你使用OnReady,则什么都不会发生!!
如果你使用OnReady,则什么都不会发生!!
这意味着我们在组件是无法正常去修改其大小的,必须要去页面上进行获取。这并不难解决。
但是这样并不能满足我想要的效果,我需要的是一个列表页面,点击列表中的每个内容都会弹框弹出一个地图,展示内容的位置。
这个需求的实现是这样,我要在弹窗打开的时候将v-if的webview放开,然后重新设定webview的大小,之后将经纬度传递给webview,此时webview根据传递的经纬度创建地图,添加图层上的点后移动到指定点的位置。
//处理地图创建于webview大小重置的函数,不处理弹窗打开
//页面.vue
refreshMap(dataObject){
//动态获取当前页面的宽高
let width = 0
let height = 0
uni.getSystemInfo({
success: function (res) {
width = res.windowWidth
height = res.windowHeight
console.log("宽度",res.windowWidth);
console.log("高度",res.windowHeight);
}
}
)
let that = this
//等待地图,在我的手机800ms大概可以正常的加载,如果太短可能对象还未生成
//that.$scope.$getAppWebview().children()[0] 这个拿不到对的
setTimeout(function(){
const wv = that.$scope.$getAppWebview().children()[0]
//这里让webview执行指定的js,传递参数 dataObject包含了我需要的经纬度
wv.evalJS(`getParams(${JSON.stringify(
dataObject
)})`)
console.log(height*0.6);
console.log(height*0.5);
console.log(width);
wv.setStyle({
height: height*0.3,
width: width*0.805,
left:width*0.1,
top:height*0.73,
// position:"relative"
})
}, 800)
}
我的组件中
<view class="content">
<web-view
class="webb"
@message="onMessage"
:update-title="false"
:webview-styles="webviewStyle"
:src="`/hybrid/html/map.html?latitude=${latitude}&longitude=${longitude}&height=${height+'vh'}&name=${name}`"></web-view>
</view>
在webview界面(我在这个页面引入了vue,可以不用)
<script>
var url = window.location
var wd = window
var vm = new Vue({
el: "#home",
data() {
return {
name: '某任务',
height: '100vh',
dataShow: {},
queryDic: {},
latitude: null,
longitude: null,
pointLayer: null,
map: {},
// 地图引擎
mapEngine: null,
zoom: 12,
// 轴承
bearing: 0,
// 屏幕坐标
containerPoint: {
x: null,
y: null
},
// 地图坐标
coordinatePoint: {
x: null,
y: null
}
};
},
methods: {
//移动
toOriginPlace() {
this.map.flyTo({
center: [this.latitude, this.longitude], // 中心点
zoom: 12, // 缩放比例
// pitch: 45 // 倾斜度
})
},
},
mounted() {
let that = this
const config = {
tileBZ: "http://www.zyzcgis.xyz/tile/wg/pc/baidu/"
}
wd.getParams = (data) => {
self.dataShow = data
that.longitude = data.longitude
that.latitude = data.latitude
const fuyuan = data.fuyuan
const centerCoordinate = [data.longitude,data.latitude ]
that.$nextTick(() => {
that.map = new maptalks.Map('map', {
center: ['117.690828','39.016343'],
zoom: 14,
minZoom: 1,
maxZoom: 19,
attribution: false,
// zoomControl: true, // add zoom control
scaleControl: true, // add scale control
baseLayer: new maptalks.TileLayer('base', {
'urlTemplate' : 'http://{ip地址写你的}:38666/gis/{z}/{x}/{y}.png',
'subdomains':[0, 1, 2, 3],
}),
});
that.$nextTick(() => {
if(!!fuyuan){
new maptalks.control.Toolbar({
'position': 'bottom-right',
'reverseMenu': false,
'items': [{
item: '复原',
click: function() {
that.toOriginPlace();
}
}]
})
.addTo(that.map);
}
this.map.flyTo({
center: centerCoordinate, // 中心点
zoom: 12, // 缩放比例
// pitch: 45 // 倾斜度
})
const centerPoint = centerCoordinate
const placeName = data.name
const point = new maptalks.Marker(
centerPoint, {}
);
var marker2 = new maptalks.Marker(
centerPoint, {
'symbol': [{
'markerFile': './static/dingwei01.png',
'markerWidth': 20,
'markerHeight': 24,
'markerDx': 0,
'markerDy': 0,
'markerOpacity': 1
},
{
'textFaceName': 'monospace',
'textFill': '#34495e',
// 'textHaloFill': '#fff',
'textName': placeName,
'textHaloRadius': 4,
'textSize': 18,
'textWeight': 'bold',
// 'textVerticalAlignment': 'top',
'textDy': 14
}
]
}
);
const layer = new maptalks.VectorLayer('vector')
layer.addGeometry(marker2)
that.map.addLayer(layer)
that.pointLayer = layer
})
})
}
},
created() {},
});
</script>
这样就可以正常的展示内容了,效果如下:
以上就是在uniapp集成maptalk展示地图的操作。
离线地图
代码的修改
关于map.html这个webview页面的内容,如果要离线,需要把所有的script引入的内容下载到本地离线。
<link rel="stylesheet" href="./css/maptalks.css">
<script src="./js/vue.js"></script>
<script src="./js/hybrid_html_uni.webview.1.5.5.js"></script>
<script src="./js/axios.min.js"></script>
<script src="./elementui/index.js"></script>
<script type="text/javascript" src="./js/maptalks.min.js"></script>
你可以在找到它们的h5引用,复制连接后手动添加到hybrid文件夹下进行引用。
瓦片下载
离线地图的展示,则需要下载瓦片,瓦片的下载工具我推荐github.com/atlasdatate…
这是一个多线程的瓦片下载工具,大概的使用方法如下
先去寻找geoJson来限制范围,可以从这个网站进行下载www.geojson.cn/
将待下载的指定的行政区划放在geojson之中,点击conf.toml修改配置
[app]
version = "v 0.1.0"
title = "MapCloud Tiler"
[output]
#可以填写 mbtiles/file 我没用过mbtiles
format ="file"
#输出文件,默认为当前的output文件夹
directory ="output"
[task]
#number of fetchers
#几个fetch一起下
workers = 3
#number of savers
#几个写入
savepipe = 1
#min request interval, a speed limit, unit millisecond
#最小请求间隔,限速 单位毫秒
timedelay = 50
[tm]
#下载的名称
name = "gaode satelite"
#设定地图的层级 最小是多少,最大是多少
min = 0
max = 18
#可以是 pbf/png/jpg
format = "png"
#可以是 xyz/tm
schema = "xyz"
# 你下载地图的位置,我这里用的是高德的
url = "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}"
#lrs can set diff boundaries for diff levels
[[lrs]]
#设定地图的层级 最小是多少,最大是多少,改的话这里和上面都改一下,我不知道这个和上面的具体怎么填写
min = 0
max = 18
# 指定的geojson路径,填你下的文件即可
geojson = "./geojson/tianjin.geojson"
之后运行tiler.exe下载即可,瓦片可能比较多,消耗时间较长,不清楚有没有断点续传的操作,可以分开下载,1-16层下一次,17层下一次,18层下一次,不同地区分开下最后在进行合并。
[[lrs]]好像可以使用多个,但作者的文档我并没有看的很明白,这样使用可以下载,额外的更便利的操作我就不知道了。
瓦片下载完成后使用nginx进行代理,这个教程较多,可以参考这个blog.csdn.net/weixin_4102… ,然后将webview页面的修改即可。
baseLayer: new maptalks.TileLayer('base', {
'urlTemplate' : 'http://{ip地址写你的}:38666/gis/{z}/{x}/{y}.png',
'subdomains':[0, 1, 2, 3],
}),