vue 中使用 cesium
我是在 vue 項目里面使用的 cesium,但是呢,有點問題,就是有些語法在js轉vue的時候有些許的限制,比如說js中相對路徑引入文件是一切OK的,vue 也能解決,但是呢,在引入的文件中又引用了其他的文件,vue 處理起來就不是特別的好用,所以說,我是直接在 vue 文件里面使用 iframe 標簽引入的 html 文件來實現接入的,而vue和iframe之間的通信采用的 postMessage 方式實現,下面就稍微介紹一下。
vue項目引入cesium
這個相對來說簡單,我也在之前的博客有介紹過,主要是下載cesiumjs包,然后這個包下載比較分時費力,所以說我整理了一下百度雲盤存了起來。
百度雲盤:鏈接:https://pan.baidu.com/s/1lf75yPi8XPPo5Y9YTvrVig
提取碼:0c7s
如果有需要的可以在這里下載。
下載下來之后選擇一個自己需要的版本,然后放進 public
文件夾下就可以。
編寫 cesium 代碼
開始已經說了,我是寫了一個html
文件,所有有關3D的東西全部在這個html文件里面實現的,所以說,最后需要我們將寫的代碼文件通過iframe
標簽引入到vue項目當中去,其中有幾個注意的點,我來稍微強調一下。
首先第一個,這個html文件就是一個普通的html文件,按照官網的官方文檔寫響應的代碼就可以了,但是呢,關鍵是怎么使用iframe標簽嵌入進我們的vue項目,首先強調,我是用的是cli3創建的項目,其他方式創建可靠性不確定,且下面的代碼都是在我發文之前編寫demo測試通過的,截止到發文為止完全可靠!
編寫iframe標簽
這個就很簡單了,無非就是在需要引入3D的地方不寫詳細的代碼了, 然后就是單純的寫一個iframe標簽,把編寫具體3D代碼的html文件引入進來就可以了。
下面是主要代碼:
<iframe ref="iframeModel" src="/static/cesium.html" width="100%" height="100%" style="background-color: #070707;" frameborder="0">
</iframe>
ok,就是上面這一行代碼就完事了,然后src寫的就是我們具體詳細代碼的html文件,引入進來就行了。
注意!!! cli3 創建的vue項目,這個引入的本地 html 文件一定、是一定要放在 public/static
文件夾下面,放在其他的地方不可以!!!而且,使用iframe標簽引入的時候,直接 /static/文件名.html
就可以,不這樣整,可能引入會報錯,也就是顯示不出來!切記切記!
然后就是編寫HTML文件了,這個沒啥可以說的,正常編寫就可以,沒啥注意的。
在這個 html 文件中引入cesiumjs 包,文件路徑寫自己的哈,別直接粘,我們不一定一樣。
<link rel="stylesheet" href="../Cesium/Widgets/widgets.css">
<script type="text/javascript" src="../Cesium/Cesium.js"></script>
然后就是很常規的操作,簡單寫一下關鍵代碼哈,不全,根據實際需要得改一下哈。
// 初始化3D地圖
viewer = new Cesium.Viewer('map', {
baseLayerPicker: false, // 影像切換
animation: false, //是否顯示動畫控件
timeline: false, //是否顯示時間線控件
infoBox: false, //是否顯示點擊要素之后顯示的信息
geocoder: false, //是否顯示地名查找控件
navigationHelpButton: false, //是否顯示幫助信息控件
terrainProvider: new Cesium.CesiumTerrainProvider({ // 加載地形信息
url: 'https://www.supermapol.com/realspace/services/3D-stk_terrain/rest/realspace/datas/info/data/path',
requestVertexNormals: true
}),
})
自定義地圖實例
// 添加mapbox自定義地圖實例
var layer = new Cesium.MapboxStyleImageryProvider({
url: 'https://api.mapbox.com/styles/v1',
username: 'username',
styleId: '這里是我的styleId',
accessToken: '這個是我的accessToken',
scaleFactor: true
});
viewer.imageryLayers.addImageryProvider(layer);
這個地方我稍微多說兩句哈,我們在做具體項目的時候吧,肯定不可能直接把默認的地圖樣式給渲染出來,因為設計不會這么簡單就放過我們開發,對吧?所以說可能需要深色模式,或者是個性化的地圖底層,這個就很難整,不好搞,百度地圖和高德地圖甚至是天地圖,他們都可以設計個性化地圖,但是這些個性化地圖都只能在高德或者百度的產品里面使用,在cesium中用不了,所以說,這個時候有一個相當牛逼的網站,可以提供在cesium中使用的個性化地圖,這個網站就是偉大的 —— mapbox。在這里面可以創建、設計、發布自己的個性化地圖給cesium使用,超級牛掰,就是國外的打開可能有點慢,進去注冊,然后怎么用,自己研究一下就可以了!
可以設置地圖的顏色,文字等很多東西。創建好自己的個性化地圖,就可以設置成公開的,然后就可以根據一些參數調用到這種設計好的個性化地圖,很淫性!自己慢慢研究,上面代碼就是我引入的例子,但是關鍵地方我隱掉了,換成你的就OK了!
然后是加載模型,找模型太費勁了,開發一星期,有半星期都在找模型上,那么沒錯,貼心的我也給各位准備了幾個測試的軍艦3D模型,均是gltf格式的,不需要轉化,貼心吧?
百度雲盤 鏈接:https://pan.baidu.com/s/1T1fYUBk-9J6VKmWA7r3Wag
提取碼:63y7
不想要軍艦?在推薦一個網址!操碎了心,稀碎啊!
sketchfab 進這個網站,模型收費很正常哈,不要抱怨,但是這里面也有很多免費的,可能不是很好,但是測試完全夠用,注冊賬號,撒歡去吧!
// 添加3D模型
var scene = viewer.scene
var hpr = new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(45), // 設置這個屬性即可(順時針旋轉的角度值)
Cesium.Math.toRadians(0),
Cesium.Math.toRadians(0)
); // 設置方向角
var origin = Cesium.Cartesian3.fromDegrees(117.70901, 38.781056, 0.0); // 設置位置
var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
origin,
hpr
);
var model = scene.primitives.add(new Cesium.Model.fromGltf({
url: './models/rrv_rapid_response_vessel/scene.gltf', //gltf文件的URL
// url: './models/ces1/scene.gltf', //gltf文件的URL
modelMatrix: modelMatrix,
color: new Cesium.Color(0, 0.9, 0.8, 0.5), // 設置模型的顏色以及透明度
scale: 1000.0 //放大倍數
}))
設置相機飛入角度
// 設置相機飛入視角
viewer.camera.flyTo({
destination: new Cesium.Cartesian3.fromDegrees(117.80901, 38.481056, 15000.0), //相機飛入點
orientation: {
heading: 0,
pitch: -0.5,
roll: 0.0
}
})
設置相機視角,和上邊不要共用哈,不然沖突。
// 設置相機角度
// heading - 代表鏡頭左右方向, 正值為右, 負值為左, 360度和0度是一樣的
// pitch - 代表鏡頭上下方向, 正值為上, 負值為下.
// roll - 代表鏡頭左右傾斜.正值, 向右傾斜, 負值向左傾斜
viewer.scene.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(117.80901, 38.481056, 15000.0),
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-25),
roll: Cesium.Math.toRadians(0)
}
});
完事!齊活!
當然了,我這是自己寫的測試Demo,有點簡陋有點丑,但是,只要你地圖設置的好,模型找的漂亮,你就真她娘的是個天才~
vue postMessage 通信給 iframe
這個其實不是很難哈,直接百度就到手了,首先iframe向我最開始一樣寫,主要是有一個 ref
。
然后呢,直接上代碼:
vue頁面
監聽接受
mounted() {
window.addEventListener('message', function (event) {
//此處執行事件
console.log('監聽到iframe數據--------> ', event.data)
})
},
發送
this.$nextTick(() => {
this.$refs.iframeModel.contentWindow.postMessage({
type: 'full'
}, '*')
})
iframe 頁面
window.addEventListener('message', function (e) {
const da = e.data;
console.log("接收到的數據---->> ", da )
});
齊活了!