近期在專案中遇到這麼一個需求,需要在地圖上展示一組格網資料,格網大小為2m*2m
,地圖api
用的mapboxgl
。起初拿到這個需要感覺很easy,在地圖上新增一個fill
圖層就好啦。把格網面資料新增到地圖上之後,在大比例尺下顯示正常,但是當地圖層級小於15級時,渲染出的結果會消失。
簡單理一下原因,應該是在地圖縮小後,每個網格所佔的畫素太小,所以就消失了。
mapboxgl
在處理symbol
圖層的時候,會遇到點位自動避讓問題,導致部分點位不顯示。解決方法是把layout
中的icon-allow-overlap
設定為true
,這樣就相當於關閉了自動避讓功能,所有點圖示保持可見狀態。但是針對fill
圖層卻沒有這麼一個屬性。
但是這種情況又需要檢視資料,要如何實現呢?
首先分析下資料,我的原始資料是通過模型匯出的tiff
格式的柵格資料,然後在後臺根據tiff
格式資料中每個畫素所在行列號以及其灰度值生成帶屬性的格網資料,其中畫素的灰度值就是在渲染時需要分類展示的值。既然原始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
格式。
既然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
圖層結合展示,效果較好參考資料:
原文地址:http://gisarmory.xyz/blog/index.html?blog=mapboxgl-geotiff
歡迎關注《GIS兵器庫》
本文章採用 知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協定 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名《GIS兵器庫》(包含連結: http://gisarmory.xyz/blog/),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。