一、項目優化 1.去掉列印console 需求:在開發環境中,保留列印console;在生產上線環境,自動去掉列印console 使用步驟: 第一步:在項目根目錄下,創建如下圖兩個配置文件 在.env.development中(開發環境變數) NODE_ENV=development 在.env.p ...
緣起
近期在項目中遇到這麼一個需求,需要在地圖上展示一組格網數據,格網大小為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/),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。