缘起

近期在项目中遇到这么一个需求,需要在地图上展示一组格网数据,格网大小为2m*2m,地图api用的mapboxgl。起初拿到这个需要感觉很easy,在地图上添加一个fill图层就好啦。把格网面数据添加到地图上之后,在大比例尺下显示正常,但是当地图层级小于15级时,渲染出的结果会消失。

简单理一下原因,应该是在地图缩小后,每个网格所占的像素太小,所以就消失了。

mapboxgl在处理symbol图层的时候,会遇到点位自动避让问题,导致部分点位不显示。解决方法是把layout中的icon-allow-overlap设置为true,这样就相当于关闭了自动避让功能,所有点图标保持可见状态。但是针对fill图层却没有这么一个属性。

但是这种情况又需要查看数据,要如何实现呢?

首先分析下数据,我的原始数据是通过模型导出的tiff格式的栅格数据,然后在后台根据tiff格式数据中每个像素所在行列号以及其灰度值生成带属性的格网数据,其中像素的灰度值就是在渲染时需要分类展示的值。既然原始tiff数据的灰度值就是所用的属性值,那是不是直接添加到地图就好了。接下来的解决方案就是看是否能直接用mapboxgl直接加载tiff数据,并渲染出自己想要的效果。

mapboxgl加载tiff

查看mapboxgl文档,可以看到mapboxgl支持image图层,只需传入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]
]});

可是,当我把地址换成tiff数据时却报错了。下面为报错内容:

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

可以简单理解为不支持tiff格式。

tiff文件解析

既然mapboxglimage图层不支持tiff格式,那是不是可以把tiff数据导出成png呢,于是使用arcmap打开了tiff数据,导出数据格式也支持png,但是在保存时又报错了。

经过分析,发现是tiff数据波段数量的原因,我的这份数据波段数为1,从网上下载了一份测试数据,波段数为3,可以成功导出。

在查找相关解决方案的时候,看到这么个工具,geotiff.js,可以通过js解析tiff数据并渲染,leaflet有个扩展就是用的这个工具,https://github.com/stuartmatthews/leaflet-geotiff。查看geotiff.js相关文档,发现其实用起来还是挺方便的,通过简单的代码实现的我的需求。

先使用geotiff.js解析tiff数据,再配合使用canvas绘制图片导出base64格式数据,然后就可以使用添加到mapboxgl图层了。

核心代码如下:

async function getData() {
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
}
});
}

本以为到这里问题已经解决,但是在查看地图时,发现图片图层数据叠加到底图有不小的偏移。

经过一番对比分析,发现原来是tiff数据的坐标系与地图坐标系不一致的导致的。我拿到的tiff数据坐标系为西安80的投影坐标系,在展示时配置的为wgs84地理坐标系,所以会有偏差。既然是坐标系问题,那就通过工具对tiff文件做下投影转换。这里用的是arcmap,打开ArcToolbox–>Data Management Tools–>Projections and Transformations–>Raster–>Project Raster

转换之后会发现,数据的行列值也会发生变化,也就是tiff图片的大小和形状都有所变化。

转换前:

转换后:

使用转换后的数据再次解析,然后叠加到地图,位置完全匹配。

最终展示方案

通过尝试发现,单独的图片展示时,由于图片分辨率固定,当地图等级放大到一定程度图片会被放大很多导致图片模糊不清,展示效果不理想;单独的格网面展示时,当地图等级缩小到一定程度,面图层则会消失,也就是文章开头提到的问题。

综上,根据自己的格网数据大小,判断在哪个等级格网面数据会消失,小于这个等级使用图片展示,大于这个等级用格网面展示,就可以完美的展示出想要的效果。

处理前效果:

处理后效果:

以上为有tiff栅格数据情况的解决方案,针对于只有格网面数据,而没有tiff栅格数据的情况要怎么解决呢?

如果在这组格网数据中,每个网格的属性中有他所在原始tiff数据的像素位置,以及原始tiff数据像素大小,就可以写一个类似上文中的getBase64Image方法,遍历每个网格,在网格对应的像素位置上绘制颜色,然后再通过canvas导出图片添加到地图。

总结

  1. mapboxglimage图层无法直接添加tiff栅格数据
  2. mapboxgl添加fill图层时,地图层级缩小到一定程度,面数据所占像素值过小无法显示
  3. tiff数据可以使用geotiff.js+canvas解析,得到base64的图片,添加到mapboxglimage图层
  4. 在解析tiff数据时,需注意它的坐标系、波段个数等信息
  5. 在做展示时可以image图层和fill图层结合展示,效果较好

参考资料:

  1. https://geotiffjs.github.io/geotiff.js/
  2. https://github.com/stuartmatthews/leaflet-geotiff
  3. https://www.cnblogs.com/arxive/p/6746570.html

原文地址:http://gisarmory.xyz/blog/index.html?blog=mapboxgl-geotiff

欢迎关注《GIS兵器库

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名《GIS兵器库》(包含链接:  http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

mapboxgl加载tiff的更多相关文章

  1. Flex 加载tiff

    gis系统常常要加载tiff,因为好多土地证书,各种文件都是扫描件,如果你是用as来写的前台,怎么加载呢,顺便说下用插件AlternaTIFF也是可以得不过浏览器加载这么多插件是不太好的. 首先TIF ...

  2. Flex 加载 wmf,svg

    最近做gis系统发现要在flex加载wmf图片.我记得flash的loader只能是png,gis,jpg.wmf格式居然是window出的,flash居然不支持我也是醉了,没办法,只能后台转格式,首 ...

  3. geotrellis使用(二十三)动态加载时间序列数据

    目录 前言 实现方法 总结 一.前言        今天要介绍的绝对是华丽的干货.比如我们从互联网上下载到了一系列(每天或者月平均等)的MODIS数据,我们怎么能够对比同一区域不同时间的数据情况,采用 ...

  4. ios UIWebView 在开发中加载文件

    UIWebView 在实际应用中加载文件的时候,有两种情况, 1. 实行在线预览 , 2. 下载到本地,再查看 如果是第一种情况: NSURL *url = [NSURL URLWithString: ...

  5. C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。

    其实我一直都是喜欢自己去做图像格式的解码的(目前我自己解码的图像格式大概有15种),但是写本文主要原因是基于CSDN的这个帖子的: http://bbs.csdn.net/topics/3905104 ...

  6. 快速加载DXF、DWG格式文件控件ABViewer

    ABViewer是一种高品质,低成本,高效率的多功能设计及工程文档管理应用程序. ABViewer为您提供专业的cad文件浏览和编辑工具. 支持多种格式,如:DWG格式, DXF, DWF, Hewl ...

  7. ArcGIS Engine中数据的加载 (转)

    1.加载Shapefile数据 1 IWorkspaceFactory pWorkspaceFactory; 2 IFeatureWorkspace pFeatureWorkspace; 3 IFea ...

  8. Arc Engine下数据的加载处理

    1.加载Shapefile数据 IWorkspaceFactory pWorkspaceFactory; IFeatureWorkspace pFeatureWorkspace; IFeatureLa ...

  9. ArcGIS Engine中加载数据

    ArcGIS Engine中加载数据 http://blog.csdn.net/gisstar/article/details/4206822   分类: AE开发积累2009-05-21 16:49 ...

随机推荐

  1. Webpack学习系列 - Webpack5 怎么集成Babel ?

    程序员优雅哥简介:十年程序员,呆过央企外企私企,做过前端后端架构.分享vue.Java等前后端技术和架构. 本文摘要:主要通过实操讲解运用Webpack 5 如何集成 Babel Babel 对于前端 ...

  2. Java开发学习(二十二)----Spring事务属性、事务传播行为

    一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...

  3. 【原创】Auto.js get和post 案例

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! Auto.js get和post 案例 ...

  4. ApacheCon 首次亚洲大会 —— Incubator 专场介绍

    Apache 孵化器即为想要进入 Apache 软件基金会(ASF)的项目提供相关帮助和服务.它帮助进入的项目(称为"podling")采用 Apache 的治理风格,并引导使用 ...

  5. 【常见】CSS3进度条Loading动画

    现在,GIF 格式的进度条已经越来越少,CSS 进度条如雨后春笋般涌现.CSS3的崛起,更使得动态效果得以轻松实现,未来,必定是CSS3的天下,所以今天我就来分享一下几个常见的CSS3进度条Loadi ...

  6. kubernetes之Endpoint引入外部资源实践;

    1. 什么是Endpoint? 我们创建Service的时候会自动给我们创建一个同名的Endpoint资源,每一个同名的 Servie都有一个Endpoints资源,因为Service自己并不直接匹配 ...

  7. Dart 异步编程(二):async/await

    对每一个异步任务返回的 Future 对象都使用链式操作-- then ,超过三个以上时,导致"倒三角"现象,降低代码的可阅读性. getHobbies() { post('htt ...

  8. 介绍下Java内存区域(运行时数据区)

    介绍下Java内存区域(运行时数据区) Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域.JDK 1.8 和之前的版本略有不同. 下图是 JDK 1.8 对JV ...

  9. Excelize 发布 2.3.0 版本, Go 语言 Excel 文档基础库

    Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准.可以使用它来读取.写入由 Microsoft Exc ...

  10. cad开发动态块对应的界面

    为了使设计人员更加容易的操作动态块, 应经可能对动态块的制作制定相关的规范, 如动态块的属性 => 类的属性 动态块操作名称(作为变量名,后台数据库的字段) 动态块操作描述  (作为注释,后台数 ...