mapboxgl通过添加tiff图层,解决小网格的fill图层在地图缩小时图层不显示问题
近期在项目中遇到这么一个需求,需要在地图上展示一组格网数据,格网大小为,地图用的。起初拿到这个需要感觉很easy,在地图上添加一个图层就好啦。把格网面数据添加到地图上之后,在大比例尺下显示正常,但是当地图层级小于15级时,渲染出的结果会消失。
简单理一下原因,应该是在地图缩小后,每个网格所占的像素太小,所以就消失了。
在处理图层的时候,会遇到点位自动避让问题,导致部分点位不显示。解决方法是把中的设置为,这样就相当于关闭了自动避让功能,所有点图标保持可见状态。但是针对图层却没有这么一个属性。
但是这种情况又需要查看数据,要如何实现呢?
首先分析下数据,我的原始数据是通过模型导出的格式的栅格数据,然后在后台根据格式数据中每个像素所在行列号以及其灰度值生成带属性的格网数据,其中像素的灰度值就是在渲染时需要分类展示的值。既然原始数据的灰度值就是所用的属性值,那是不是直接添加到地图就好了。接下来的解决方案就是看是否能直接用直接加载数据,并渲染出自己想要的效果。
查看文档,可以看到支持图层,只需传入url和coordinates
map.addSource(‘some id’, {
type: ‘image’,
url: ‘https://www.mapbox.com/images/foo.png’,
coordinates: [
[-76.54, 39.18],
[-76.52, 39.18],
[-76.52, 39.17],
[-76.54, 39.17]
]});
可是,当我把地址换成数据时却报错了。下面为报错内容:
Could not load image because of The source image could not be decoded.. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported
可以简单理解为不支持格式。
既然的图层不支持格式,那是不是可以把数据导出成呢,于是使用打开了数据,导出数据格式也支持,但是在保存时又报错了。
经过分析,发现是数据波段数量的原因,我的这份数据波段数为1,从网上下载了一份测试数据,波段数为3,可以成功导出。
在查找相关解决方案的时候,看到这么个工具,geotiff.js,可以通过解析数据并渲染,有个扩展就是用的这个工具,https://github.com/stuartmatthews/leaflet-geotiff。查看相关文档,发现其实用起来还是挺方便的,通过简单的代码实现的我的需求。
先使用解析数据,再配合使用绘制图片导出格式数据,然后就可以使用添加到图层了。
核心代码如下:
GeoTIFF.fromUrl(url).then(tiff=> {
console.log(tiff)
getImage(tiff)
});
}
async function getImage(tiff) {
const image=await tiff.getImage();
let bbox=await image.getBoundingBox();
let data=await image.readRasters({
samples: rgbBands // 波段数量,一个波段:[0],三个波段:[2,1,0]
});
let base64Image=getBase64Image(data)
addToMapboxgl(base64Image)
}
function getBase64Image(data) {
let thumbnailPixelHeight=data.height
let thumbnailPixelWidth=data.width
let canvas=document.createElement(‘canvas’)
canvas.width=thumbnailPixelWidth
canvas.height=thumbnailPixelHeight
let ctx=canvas.getContext(“2d”)
let totalPixelCount=0
for (let y=0; y < thumbnailPixelHeight; y++) {
for (let x=0; x < thumbnailPixelWidth; x++) {
let colour=’rgb(0, 0, 0, 0)’ // let the default be no data (transparent)
// 根据灰度值所在范围渲染颜色
if (data[0][totalPixelCount] > 0) {
if (data[0][totalPixelCount] > 50 && data[0][totalPixelCount] <=55) {
colour=`rgb(15, 255, 0, 1)`
} else if (data[0][totalPixelCount] > 55 && data[0][totalPixelCount] <=60) {
colour=`rgb(155, 255, 0, 1)`
} else if (data[0][totalPixelCount] > 60 && data[0][totalPixelCount] <=65) {
colour=`rgb(255, 255, 0, 1)`
} else {
colour=`rgb(255, 255, 0, 1)`
}
}
ctx.fillStyle=colour
ctx.fillRect(x, y, 1, 1)
totalPixelCount++
}
}
let canvasImage=canvas.toDataURL(“image/png”)
return canvasImage
}
// 将图片添加到地图
function addToMapboxgl(image) {
map.addSource(‘tiff-source’, {
“type”: “image”,
“url”: image,
“coordinates”: [
[114.425597191307, 38.1091563484708],
[114.538187627939, 38.1091563484708],
[114.538187627939, 37.9627378349512],
[114.425597191307, 37.9627378349512]
]
});
map.addLayer({
id: ‘tiff-layer’,
‘type’: ‘raster’,
‘source’: ‘tiff-source’,
‘paint’: {
‘raster-fade-duration’: 0
}
});
}
本以为到这里问题已经解决,但是在查看地图时,发现图片图层数据叠加到底图有不小的偏移。
经过一番对比分析,发现原来是数据的坐标系与地图坐标系不一致的导致的。我拿到的数据坐标系为西安80的投影坐标系,在展示时配置的为地理坐标系,所以会有偏差。既然是坐标系问题,那就通过工具对文件做下投影转换。这里用的是,打开ArcToolbox–>Data Management Tools–>Projections and Transformations–>Raster–>Project Raster
转换之后会发现,数据的行列值也会发生变化,也就是图片的大小和形状都有所变化。
转换前:
转换后:
使用转换后的数据再次解析,然后叠加到地图,位置完全匹配。
通过尝试发现,单独的图片展示时,由于图片分辨率固定,当地图等级放大到一定程度图片会被放大很多导致图片模糊不清,展示效果不理想;单独的格网面展示时,当地图等级缩小到一定程度,面图层则会消失,也就是文章开头提到的问题。
综上,根据自己的格网数据大小,判断在哪个等级格网面数据会消失,小于这个等级使用图片展示,大于这个等级用格网面展示,就可以完美的展示出想要的效果。
处理前效果:
处理后效果:
以上为有栅格数据情况的解决方案,针对于只有格网面数据,而没有栅格数据的情况要怎么解决呢?
如果在这组格网数据中,每个网格的属性中有他所在原始数据的像素位置,以及原始数据像素大小,就可以写一个类似上文中的getBase64Image方法,遍历每个网格,在网格对应的像素位置上绘制颜色,然后再通过导出图片添加到地图。
的图层无法直接添加tiff栅格数据添加图层时,地图层级缩小到一定程度,面数据所占像素值过小无法显示数据可以使用解析,得到的图片,添加到的图层在解析数据时,需注意它的坐标系、波段个数等信息在做展示时可以图层和图层结合展示,效果较好
https://geotiffjs.github.io/geotiff.js/https://github.com/stuartmatthews/leaflet-geotiffhttps://www.cnblogs.com/arxive/p/6746570.html
到此这篇关于mapboxgl加载tiff的文章就介绍到这了,更多相关mapboxgl加载tiff内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!