cesium 切換瓦片地圖的加載方式
如果你熟悉 cesium,那么你或多或少應(yīng)該用過或者了解如何用 cesium 加載瓦片地圖。
熟悉加載瓦片地圖這本身不是一個太難的工作,一般來說,只要你照著官方的沙盒中的示例,一般都能輕松掌握。
但是問題是,只要你細(xì)心研究過,你就會發(fā)現(xiàn),cesium 加載瓦片地圖,居然是用 ajax 請求的方式來加載貼圖的。

這種加載方式的優(yōu)劣我們姑且不論,cesium 選擇這種方式必然會有其意義所在。
但是問題是,為什么翻遍 api 和源碼,都沒有找到一個方式,可以更換貼圖的加載方式呢?
我們知道,對于現(xiàn)代的瀏覽器來說,一般都會對傳統(tǒng)的加載圖片做一些優(yōu)化。
比如會進(jìn)行緩存,同樣的圖片,不會重復(fù)向服務(wù)器請求等等。
這兩種加載圖片的方式,用在瀏覽器上,到底哪一種比較比較好,還有待商榷。
截止到目前為止,我還并未找到對兩種加載方式的優(yōu)劣進(jìn)行比較的分析資料。
如果有童鞋曾經(jīng)看過相關(guān)比較好的資料,還希望能積極分享出來。
如果要采用 JavaScript 的方式來加載圖片,該怎么做呢?
一般我們會采用下面的方式:
const img = new Image()
img.src = imgUrl
img.crossOrigin = 'Anonymous'
// 圖片加載成功
img.onload = () => {
console.log(imgUrl + " 圖片加載成功!")
}
// 圖片加載失敗
img.onerror = () => {
console.error('圖片:【' + imgUrl + '】加載失敗!')
}
現(xiàn)在問題是,我們怎么將上面這套機(jī)制,應(yīng)用在 cesium 里面呢?
也就是說,我們需要做一些修改源碼的操作。
但是修改源碼最關(guān)鍵的一個要素是,我們只是朝源碼上加功能,而不能對現(xiàn)有的功能造成哪怕一絲絲的影響。
否則,在我們沒有全盤掌握某段代碼的作用的時候,隨意的修改,會造成難以預(yù)料的后果。
對于 JavaScript 來說,有些時候,做到這一點(diǎn),還蠻容易的。
如果源碼是采用面向?qū)ο蟮姆绞綄懙模敲次覀儗υ玩溕夏硞€方法重載下,就能達(dá)到我們想要的效果。
接下倆,我們需要做的就是,找到合適的重載的地方。
那么該如何找呢?
別著急,接下來,我會手把手的教你,該如何找到合適的重載的地方。
首先,我們需要用到我們的好伙伴——chrome devtool。

當(dāng)然如果你用火狐瀏覽器的開發(fā)者工具,也能達(dá)到同樣的效果,這里就不一一舉例了,直接以 chrome 為例進(jìn)行說明。
我們找到 Network 這一列,刷新下頁面,能看到我們頁面發(fā)的所有的請求。
而 XHR 這一欄里面,就是我們前端頁面所有的 ajax 請求的集合欄了。
隨便點(diǎn)開一個加載瓦片圖的鏈接,你便會詳細(xì)的了解到每個請求的調(diào)用棧。
如何找到合適的地方,進(jìn)行重載呢?
這里貌似沒有什么好方法,只有從上到下,依次將源碼點(diǎn)開研究一番。
最后你會發(fā)現(xiàn),在這個地方進(jìn)行重載,可以達(dá)到比較滿意的效果。

之所以這么說,原因有幾點(diǎn),這個 loadImage 方法是個靜態(tài)的方法,需要 imageryProvider 的實(shí)例以及圖片的 url 地址,其返回的結(jié)果是個一 Promise,而 Promise 最終返回的值為圖片元素。
既然這個地方用的是 fetchImage 方法,也就是通過 ajax 的方式來獲取圖片的,那么我們直接給這個地方改成傳統(tǒng)的拿圖方式就好了。
import {
ImageryProvider
} from 'Cesium'
// 將原來的 loadImage 方法重命名
ImageryProvider.loadImage2 = ImageryProvider.loadImage
// 將 loadImage 重載
ImageryProvider.loadImage = function(imageryProvider, url) {
// 在某些情況下,走我們原來的邏輯
if(url === some case){
return ImageryProvider.loadImage2.call(this, imageryProvider, url)
}
// 其余情況,采用傳統(tǒng)的加載圖片的方式
return new Promise((resolve, reject) => {
const imgUrl = url.url
const img = new Image()
img.src = imgUrl
img.crossOrigin = 'Anonymous'
// 圖片加載成功了,進(jìn)行 reslove
img.onload = () => {
resolve(img)
}
// 圖片未加載成功
img.onerror = (err) => {
console.error('圖片:【' + imgUrl + '】加載失??!')
reject(err)
}
})
}
如果后面需要進(jìn)一步優(yōu)化的話,為了防止圖片出錯,加載失敗,可以用一個通用的圖片去代替出錯的圖片,以達(dá)到讓程序能夠正常的運(yùn)行的目的。
比如這樣做:
// 圖片未加載成功
img.onerror = (err) => {
console.error('圖片:【' + imgUrl + '】加載失敗!')
resolve(ErrorImage)
}
或者這樣做:
// 圖片未加載成功
img.onerror = (err) => {
console.error('圖片:【' + imgUrl + '】加載失敗!')
img.url = errorImageUrl
}
總之,在平時寫代碼的過程中,總會有很多小細(xì)節(jié),很值得我們?nèi)?yōu)化,如果優(yōu)化的好,也可以極大的提升用戶的使用體驗(yàn)。