這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 介紹 有朋友反饋說最近分享的內容不太好理解,那麼今天來分享個早前開發的圖層製作過程,基於GIS數據代碼生成流動的車行線,上手很簡單。下麵我將在實現思路、具體開發、數據來源這幾方面逐步講解,希望讀者能從中獲取對數據可視化開發的興趣。文中使用 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
介紹
有朋友反饋說最近分享的內容不太好理解,那麼今天來分享個早前開發的圖層製作過程,基於GIS數據代碼生成流動的車行線,上手很簡單。下麵我將在實現思路、具體開發、數據來源這幾方面逐步講解,希望讀者能從中獲取對數據可視化開發的興趣。文中使用到高德地圖JSAPI、three.js和一些GIS數據處理工具。
實現思路
1.這是我們通常能夠獲取到的數據,從geoJSON數據通常沒有真正的曲線,得到通常是基於關鍵節點生成的線段幾何體,只要線越密集,看上去就越平滑,所消耗的資源也就越多。
2.在空間幾何中,線本身是沒有寬度這個概念的,我們能看到不同粗細程度到線,其本質其實是一連串拼合的三角面帶,這些面始終朝著相機,這樣的話才保證我們在不同角度看到的始終是“均勻圓潤”的線。
3.給這些幾何賦予純色材質,整條線看著像一個整體。
4.根據具體場景給幾何體賦予貼圖,我們知道如果用相機長曝光模式去拍攝夜晚車輛移動,能夠看到一條從亮到暗的軌跡,因為給線圖層也賦予這樣一層貼圖。
5.通過調整貼圖的X軸偏移讓線條動起來。
6.增加後期輝光效果,給圖層賦予光的質感。
實現步驟
1.編寫構造函數,聲明基礎的參數。這裡Layer為基類,封裝了在高德地圖上創建glCustomLayer圖,管理圖層,逐幀函數等基礎操作。
class FlowlineLayer extends Layer { // 圖層數據 _data = [] // 線材質 _material = null /** * @param {Object} config * @param {geoJSON} config.data 路徑數據 * @param {Number} [config.lineWidth=20.0] 路徑線條寬度 * @param {Number} [config.altitude=0.0] 整體海拔高度 * @param {Array} [config.zooms=[5,14]] 顯示區間 * @param {Boolean} [config.animate=true] 是否顯示動畫 * @param {Number} [config.speed=1.0] 流動速度繫數 * @param {String} [config.uvMapURL='./static/texture/road_bg1.png'] 線條紋理URL */ constructor (config) { const conf = { data: null, speed: 1, animate: true, lineWidth: 20.0, altitude: 0.0, uvMapURL: './static/texture/road_bg1.png', ...config } super(conf) this.initData(conf.data) } }
2.將Polyline的geoJSON數據並轉為空間坐標
initData (data) { const arr = data?.features.map(item => { return item?.geometry?.coordinates[0] }) // 經緯度轉為空間坐標 const res = this.customCoords.lngLatsToCoords(arr) this._data = res }3.根據數據創建幾何體,並設置材質。事實上我們得到的是一條沒有寬度的線的數據,而最終的展示的是平行於地面的一條平面帶,這裡我們使用插件meshline,它提供的MeshLineGeometry能夠自動幫我們生成所需的幾何體。
import { MeshLineGeometry, MeshLineMaterial } from '../plugins/meshline.js' //... initLines () { const { scene } = this //材質紋理 const texture = new THREE.TextureLoader().load(this.mergeSourceURL(this._conf.uvMapURL)) texture.wrapS = THREE.RepeatWrapping texture.wrapT = THREE.RepeatWrapping const material = new MeshLineMaterial({ lineWidth: this._conf.lineWidth, sizeAttenuation: 1, useMap: 1, opacity: 1, map: texture, transparent: true, depthTest: true }) this._material = material //生成網格體 const multiLine = [...this._data] multiLine.forEach(lineData => { const points = [] lineData.forEach(([x, y]) => { points.push(new THREE.Vector3(x, y, this._conf.altitude)) }) const line = new MeshLineGeometry() line.setPoints(points) const mesh = new THREE.Mesh(line, material) scene.add(mesh) }) }
4.在requestAnimationFrame逐幀修改紋理的x偏移量,形成動畫效果
// 更新紋理偏移量 update () { if (!this._isAnimate) { return } if (this._material?.uniforms?.offset) { this._material.uniforms.offset.value.x -= 0.01 * this._conf.speed } }
5.添加後期效果,這塊不作展開,有興趣可以看 這裡
const layer = new FlowlineLayer({ id: 'trafficLayer', //... }) layer.on('complete',(layer)=>{ new EffectLayer({ layer, style:{ strength: 1.0, //發光強度 radius: 0.5 //泛光半徑 } }) })
路徑數據從哪來
1.通過地圖引擎的路徑導航功能獲取路徑,如下圖所示,通過指定起點、終點、經過點可以從API中獲取規劃好的路徑數據,適合在地圖上能查得到的部分道路
2.自行繪製,如果需要展示的路徑還處於規劃中,或者屬於園區內部道路數據,在官方地圖上無法獲取,則需要人工使用工具做繪製,這裡推薦使用QGIS繪製矢量圖層。
3.如果是涉及範圍或數據量較大的路徑,則需要通過某些途徑導出了,通過OSM可以無套路導出所需的各種點線面數據,缺點就是有些數據實在太老舊了。在國內我們使用水經註之類的GIS數據下載器獲取最新最全的數據,當然,優質的數據都是收費的。