mapboxgl加载tiff
缘起
近期在项目中遇到这么一个需求,需要在地图上展示一组格网数据,格网大小为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文件解析
既然mapboxgl
的image
图层不支持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
导出图片添加到地图。
总结
mapboxgl
的image
图层无法直接添加tiff栅格数据mapboxgl
添加fill
图层时,地图层级缩小到一定程度,面数据所占像素值过小无法显示tiff
数据可以使用geotiff.js+canvas
解析,得到base64
的图片,添加到mapboxgl
的image
图层- 在解析
tiff
数据时,需注意它的坐标系、波段个数等信息 - 在做展示时可以
image
图层和fill
图层结合展示,效果较好
参考资料:
- https://geotiffjs.github.io/geotiff.js/
- https://github.com/stuartmatthews/leaflet-geotiff
- 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的更多相关文章
- Flex 加载tiff
gis系统常常要加载tiff,因为好多土地证书,各种文件都是扫描件,如果你是用as来写的前台,怎么加载呢,顺便说下用插件AlternaTIFF也是可以得不过浏览器加载这么多插件是不太好的. 首先TIF ...
- Flex 加载 wmf,svg
最近做gis系统发现要在flex加载wmf图片.我记得flash的loader只能是png,gis,jpg.wmf格式居然是window出的,flash居然不支持我也是醉了,没办法,只能后台转格式,首 ...
- geotrellis使用(二十三)动态加载时间序列数据
目录 前言 实现方法 总结 一.前言 今天要介绍的绝对是华丽的干货.比如我们从互联网上下载到了一系列(每天或者月平均等)的MODIS数据,我们怎么能够对比同一区域不同时间的数据情况,采用 ...
- ios UIWebView 在开发中加载文件
UIWebView 在实际应用中加载文件的时候,有两种情况, 1. 实行在线预览 , 2. 下载到本地,再查看 如果是第一种情况: NSURL *url = [NSURL URLWithString: ...
- C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。
其实我一直都是喜欢自己去做图像格式的解码的(目前我自己解码的图像格式大概有15种),但是写本文主要原因是基于CSDN的这个帖子的: http://bbs.csdn.net/topics/3905104 ...
- 快速加载DXF、DWG格式文件控件ABViewer
ABViewer是一种高品质,低成本,高效率的多功能设计及工程文档管理应用程序. ABViewer为您提供专业的cad文件浏览和编辑工具. 支持多种格式,如:DWG格式, DXF, DWF, Hewl ...
- ArcGIS Engine中数据的加载 (转)
1.加载Shapefile数据 1 IWorkspaceFactory pWorkspaceFactory; 2 IFeatureWorkspace pFeatureWorkspace; 3 IFea ...
- Arc Engine下数据的加载处理
1.加载Shapefile数据 IWorkspaceFactory pWorkspaceFactory; IFeatureWorkspace pFeatureWorkspace; IFeatureLa ...
- ArcGIS Engine中加载数据
ArcGIS Engine中加载数据 http://blog.csdn.net/gisstar/article/details/4206822 分类: AE开发积累2009-05-21 16:49 ...
随机推荐
- 1_day01_java入门
java入门 学习目标: 1.熟悉计算机编程语言 2.熟练掌握java特点 3.熟练配置java开发环境 4.熟练编写入门程序 5.熟练编写注释信息 一.计算机语言 1.1 什么是编程语言 计算机语言 ...
- JavaWeb--Servlet详解
前言 Java Web 其实就是一个技术的总和,把Web看成一个容器而已主要使用JavaEE技术来实现.在加上各种中间件. 整个javaWeb阶段的内容通过实际的案例贯穿学习, 所涉及到的技术知识点会 ...
- Quicker程序实用及获取
-- 仅代表个人见解 --官方网站:https://getquicker.net/主界面截图 桌面图标截图 3分钟快速体验Quicker https://getquicker.net/KC/ ...
- Modbus转Profinet网关案例 | 三菱FR-A700系列变频器配置方法
本案例是利用小疆智控Modbus转Profinet网关GW-PN5001把三菱FR-A700变频器接入到西门子1200PLC.实现Profinet转Modbus的通讯协议的互转. 用到设备有:三菱FR ...
- 线程本地存储 ThreadLocal
线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...
- Luogu3802 小魔女帕琪 (排列组合)
注意除数为0情况 #include <iostream> #include <cstdio> #include <cstring> #include <alg ...
- uni-app 从0 到 1 制作一个项目,收藏等于学会
uni-app 是使用 vue.js 开发的所有前端应用框架,开发者编写的一套代码,可以发布到 ios.android.web ,以及各种小程序平台. 一.创建uni-app 1.hBuilderX ...
- 操作系统学习笔记4 | CPU管理 && 多进程图像
操作系统的核心功能就是管理计算机硬件,而CPU就是计算机中最核心的硬件.而通过学习笔记3的简史回顾,操作系统通过多进程图像实现对CPU的管理.所以多进程图像是操作系统的核心图像. 参考资料: 课程:哈 ...
- wbr 文本换行规则标签
<wbr/>标签规定在文本中的何处适合添加换行符.如果文本太长,浏览器可能会在错误的位置换行,那么可以使用<wbr/>标签来添加单词换行时机. Talk is cheap. S ...
- ceph 010 clustermap ceph调优
cluster map [ceph: root@clienta /]# ceph mon dump epoch 4 fsid 2ae6d05a-229a-11ec-925e-52540000fa0c ...