关于javascript: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文件解析

既然mapboxglimage图层不反对tiff格局,那是不是能够把tiff数据导出成png呢,于是应用arcmap关上了tiff数据,导出数据格式也反对png,然而在保留时又报错了。

通过剖析,发现是tiff数据波段数量的起因,我的这份数据波段数为1,从网上下载了一份测试数据,波段数为3,能够胜利导出。

在查找相干解决方案的时候,看到这么个工具,geotiff.js,能够通过js解析tiff数据并渲染,leaflet有个扩大就是用的这个工具,https://github.com/stuartmatt…。查看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/g…
  2. https://github.com/stuartmatt…
  3. https://www.cnblogs.com/arxiv…

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

欢送关注《GIS兵器库》

本文章采纳 常识共享署名-非商业性应用-雷同形式共享 4.0 国内许可协定 进行许可。欢送转载、应用、从新公布,但务必保留文章署名《GIS兵器库》(蕴含链接:  http://gisarmory.xyz/blog/),不得用于商业目标,基于本文批改后的作品务必以雷同的许可公布。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理