关于javascript:mapboxgl加载tiff

2次阅读

共计 4102 个字符,预计需要花费 11 分钟才能阅读完成。

缘起

近期在我的项目中遇到这么一个需要,须要在地图上展现一组格网数据,格网大小为 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/),不得用于商业目标,基于本文批改后的作品务必以雷同的许可公布。

正文完
 0