主頁 > 軟體設計 > 高德智慧交通地圖空間可視化SDK設計與實作

高德智慧交通地圖空間可視化SDK設計與實作

2021-02-03 10:42:32 軟體設計

一、背景

地圖空間可視化作為高德智慧交通前端業務中最重要的功能之一,承擔著城市交通大腦、全境智能大屏等業務中大量的地圖渲染需求,作為向用戶展示交通資料的視窗,我們需要展現省、市、區、商圈、自定義區域多種場景,包括所有交通事件、擁堵指數、轄區等多種維度的資料,呈現著資料量大、元素種類多、邏輯展現重等特點,

JSAPI作為高德地圖前端戰線的引擎,涵蓋著渲染地圖、展示覆寫物等底層能力,但對于行業應用領域的開發來說,存在著開發難度大、適配成本高、純原生JS實作與主流框架結合不緊密,無行業圖層能力的問題,

基于以上原因,我們設計了具有適用于垂直行業的、可復用、可擴展、二次開發簡單等特點的地圖SDK,已經成為智慧交通地圖空間可視化能力的首選方案,

二、方案設計

整體框架設計方案

高德智慧交通團隊經過大量專案實踐和思考,以交通行業為切入點,面向整個前端行業地圖設計了一套地圖空間可視化開發的SDK,整體功能架構設計如下圖所示:

(1) MapContainer是整個SDK的基座,用于承載地圖引擎,裝載在其上渲染的覆寫物圖層,加載所需要的框架模塊,在整個架構中起到中流砥柱的作用,

(2) 配置控制器負責傳入用戶配置,包括地圖應用key配置、加載可選功能配置、樣式配置等,在用戶變更這些配置后,它會把更新后的配置資訊傳遞到流程中的其他模塊中,

(3) 接受資料的作業由SourceLoader完成,設計了一套SDK內部使用的標準化的資料格式,Loader負責將用戶傳入的不同型別的資料(已經支持GeoJSON、WKT、資料串列等形式)轉化成專用標準格式資料,分發到地圖容器及各圖層中,

(4) 為了支持不同的主流應用框架,將框架適配層單獨拆分,由它將主要模塊封裝成Vue、React等框架兼容的組件形式,實作多框架擴展,

(5) 地圖API呼叫有著嚴格的順序限制,而封裝框架對于圖層各個生命周期的觸發是異步的,亂序的,存在無法保證流程一致性的問題,為了應對這種情況我們在SDK中引入了事件佇列機制,

狀態驅動方案的實作

1.生命周期設計

地圖JS API的呼叫邏輯與原生Javascript一樣,是命令式呼叫設計,像下面這樣:

// 創建地圖
const map = new AMap.Map(options);


// 添加覆寫物
const marker = new AMap.Marker(markerOptions);
map.add(marker);


// 修改覆寫物屬性
marker.setContext(newContext);


// 移除覆寫物
map.remove(marker);
map.destroy();

這樣的API呼叫方式,與上層專案的開發框架,如Vue、React等不匹配,如果在一個狀態驅動的框架下充斥著大量命令式驅動的代碼,會大幅度降低這個專案的可維護性、可擴展性,

為了更好地支撐開發的需要,所有業務圖層抽象出了一套完整的生命周期流程,不同的圖層,渲染邏輯的步驟不完全相同,各圖層的額外能力,如支持互動事件的能力、影片能力也不盡相同,但都可以囊括在這一套生命周期結構內,

SDK圖層組件生命周期定義如下:

(1)地圖注冊

在地圖底座加載完畢后,會通知各個圖層的RegisterMap流程,這是圖層組件生命周期的第一步,圖層中包含的所有元素都在這之后才會開始渲染,

(2)中間層加載

部分型別的元素需要分組批量加載,因此在渲染這些元素之前,需要先將對應的組圖層加載出來,因此,我們設計了組圖層相關的生命周期,相關邏輯只需要在beforeAppendGroup,appendGroup,afterAppendGroup這些流程中實作即可,

(3)元素加載

beforeAppendComponent,appendComponent,afterAppendComponent,這些是元素圖層中最重要的流程,用于實作圖層元素加載的主邏輯,

其中,對于一些元素需要有前置檢查,有資料校驗,可以把相應的檢查邏輯放入beforeAppend中;有的元素需要注冊互動事件,或者需要有添加影片scheme能力,這部分的實作邏輯可以放到afterAppend流程中,

與之對應的,還有元素的銷毀流程,beforeRemoveComponent,removeComponent,afterRemoveComponent,如果元素系結了互動事件,將會在beforeRemove的時候解綁;如果元素注冊了影片或者周期呼叫,也會在beforeRemove的時候銷毀周期timer,

(4)元素更新

shoudlUpdate,diff,updateComponent,用于實作組件資料動態更新后圖層元素的diff、更新程序,

其中為了防止源資料中只有一小部分修改導致整個圖層全部重繪的情況,我們在其中加入了diff的演算法,通過各圖層的校驗資料key的方法,篩選出變更前后一致的資料項,只重繪不同的資料,大大提升了渲染流程的效率,

2.插件的實作

不同圖層之間存在共同處理流程和共同的屬性,對此,我們設計了各種可復用的內置插件,供各圖層根據自身特性組合使用,

例如,有實作定時重繪效果的scheme插件,實作影片效果的animate插件,實作注冊互動事件的event插件等,這些插件的設計,必須遵守組件生命周期的規范,插件功能的實作邏輯,也全部以注冊上述的生命周期函式的方式完成,

這些生命周期需要與主流框架的生命周期設計適配,以目前我們專案中正在使用的Vue框架舉例,Vue也有其自己的組件生命周期,它的設計基本能夠與我們的周期函式相匹配,因此,針對Vue的適配程序其實并不怎么難:

Vue自身有一套不同層級的組件之間的加載控制流程,父子層級、兄弟層級之間的組件有著嚴格的觸發順序,例如,父組件的beforeCreate總是在子組件beforeCreate之前觸發,而父組件的mounted又總是在子組件mounted之后才會回應,這與我們的多層級圖層之間想要的觸發順序相符,因此,SDK圖層的各生命周期總能在Vue中找到與之對應的觸發時間點,

經過封裝后,用SDK實作的地圖模塊在專案中生成的組件樹結構如下:


3.異步流程的一致性設計

我們使用的底層地圖引擎,對于流程邏輯的順序有著嚴格的要求:

(1)地圖底座的創建須在所有其他流程之前,

(2)Loca、L7底座的初始化須在地圖底座創建完成之后,

(3)地圖元素需要在地圖底座加載完成后才能夠開始加載,銷毀也需要在地圖底座銷毀之前完成,

(4)需要確保狀態與結果的一致性,如果在短時間內觸發了大量的更新資料的操作,即使底層引擎處理需要很長的時間,也要保證最終的展示結果與更新的順序完全一致,

不幸的是,雖然主流的框架有完善的生命周期管理機制,能夠確保各個流程的執行順序不出差錯,但這些流程之間都是異步的、并發的,而繪圖引擎在處理這些渲染指令時,會由于處理時長的不確定性,導致各指令回傳的順序有所變化,這可能會導致下面的情況出現:

  • 地圖容器的加載時間過長,導致加載后續元素時,地圖仍沒有渲染完成而出錯;

  • 在短時間內對同一份資料進行變更,如果引擎處理第一次變更花的時間比后一次更長,就會導致第一次更新的結果渲染出來時,會把更早完成的第二次渲染結果覆寫掉,

為了避免上述情況,我們在SDK中實作了事件佇列控制器,處理順序問題:

(1)所有圖層組件中需要呼叫底座引擎的事件,例如append component,remove component等,不會直接呼叫底座的相關介面,而是在佇列控制器中push一個對應型別的事件,

(2)佇列控制器中的所有事件型別,全部封裝成同步方法實作,由控制器收集所有涂層的呼叫訊息,單執行緒逐一消費,

(3)在控制器中寫入特殊的控制邏輯,地圖基座的加載需要在其他圖層加載之前,則把基座加載的事件的回應優先級設定為最高,

(4)引入篩選機制,針對佇列中存在同一圖層的互逆操作,如短時間內加載一份資料,之后又remove掉,由于這一對操作不會對當前的結果有任何影響,因此這一對操作將會被過濾邏輯洗掉,達到優化渲染性能的效果,

4.地圖控制指令的優化

地圖底座支持用戶通過呼叫相關方法控制地圖展示的視野,SDK在這種設計上加以優化,通過在地圖底座組件上配置相應的屬性狀態,來實作定位到選定元素、定位到整個轄區范圍、定位到特定地點及縮放級別等多種視野型別,

同時,地圖的其他控制方法,例如設定周邊避讓區域、設定游標形狀、設定自定義地圖樣式等方法,也全部改為傳遞props屬性的方式實作,

三、其他優化

地圖實體快取

就我們使用的底層地圖引擎來說,創建、銷毀一個地圖底座需要消耗大量的性能,而有時候這樣的操作是可以避免的,有時候我們只是切換了一個頁面路由,圖面的上展示物并不需要有什么變化,但仍然會觸發地圖底座的銷毀與重新生成,這個流程是多余的,

為了優化這個問題,我們設計了可以容納2個底座實體的快取容器,每次在執行銷毀地圖的命令時,我們并不會真正的銷毀它,而是把它隱藏掉并存入快取中,下次需要創建實體時,直接在快取中找到符合要求的實體拿來用,

多實體環境隔離

隨著下游業務專案的功能迭代,產品提出了在同一個頁面內展示多個SDK底座實體的要求,對此,我們對SDK進行了一系列的優化:

  • 改造訊息佇列控制器,原來的單執行緒模式已經不再適用,現在已可以支持實體隔離,不同實體之間獨享事件佇列和流程控制邏輯,

  • 優化圖層與底座的從屬判定機制,在多個底座之間存在父子關系的情況下,能夠讓圖層在最合適的底座上展現,

GL渲染Context沒有正確GC回收導致的崩潰問題

在為L7撰寫加載器時,遇到了記憶體泄露的問題:如果在專案中使用了L7相關圖層,銷毀時L7使用的WebGLRenderingContext資源不會正確釋放,反復創建銷毀幾次后,瀏覽器會因為內部的renderingContext資源不足而渲染崩潰,

分析L7原始碼后發現,L7為了實作與地圖同步resize,在地圖容器DOM上注冊了一個resize事件,并把這個事件的處理函式系結在了這個容器DOM的一個叫__resize__trigger__的屬性上,

如果開發者在專案中使用Vue作為前端框架,Vue的模板更新機制會引起DOM的重繪,在一次資料變更之后,它會把原來的容器DOM銷毀,替換為一個新的,

但由于注冊的事件函式中含有DOM物件參考的緣故,雖然舊的DOM物件已經從DOM tree上移除,但并不會被GC回收,而是仍然被__resize__trigger__這個函式參考著,同時由于新生成的DOM不具有該屬性,導致在L7引擎銷毀的時候,由于L7找不到這個函式,resize事件解綁也會失敗,在開發者觸發多次切換引擎操作之后,有大量的未被實際參考的容器DOM無法被回收,而這些DOM中又都包含著webGL Canvas物件,導致瀏覽器的GLRendering資源不足的問題出現,

解決方法:我們無法修改L7的原始碼,因此也無法更改它注冊、解綁事件的邏輯,但我們可以通過在每次Vue重繪之前,對即將被移除的canvas的width和height設定為0,以此來直接釋放renderingContext資源,實測有效,

最佳解決方案:目前我們已經有自行實作的3D圖形類,且也擴展了對Loca等其他可視化庫的支持,可以擺脫對單一庫的依賴,實作相同的能力,

四、多維資料比對

經過高德智慧交通大量的專案實踐和資料比對,充分證明了地圖空間可視化SDK開發的必要性,業務價值和技術價值都經歷了專案的考驗,以高德交通大腦和全境智能大屏的資料比對可以得到使用SDK之前和之后的資料比較:

專案落地效果:

使用SDK后的專案開發代碼:

<template>
  <!-- 地圖底座 -->
  <CommonMap
    :center="center"
    :zoom="zoom"
    :city="fitViewCity"
    view-mode="3D"
    :map-style="mapStyle"
  >
    <!-- 場景1 -->
    <TrafficScene>
      <!-- 地圖元素層 -->
      <TrafficPointLayer :list="trafficPointList" />
      <!-- 帶有事件監聽的地圖元素層 -->
      <TrafficRoadMarkerLayer
        :list="trafficRoadList"
        @click="handleTrafficRoadMarkerClick"
      />
    </TrafficScene>
    <!-- 場景2 -->
    <PublishScene>
      <PublishMarkerLayer
        :list="publishList"
        @mouseover="handlePublishMouseOver"
        @mouseout="handlePublishMouseOut"
        @click="handlePublishClick"
      />
    </PublishScene>
    <!-- 可視化場景 -->
    <VisualizationScene use="amap-loca">
      <!-- 可視化資料層 -->
      <TrafficRoadLineLayer :list="trafficRoadList" />
    </VisualizationScene>
  </CommonMap>
</template>

五、展望

經過高德智慧交通大量專案的實踐,SDK的建設已經趨于成熟,其開發簡單、穩定性高、性能好的特點可以很好地降低開發者使用高德開放平臺JSAPI來開發地圖空間可視化專案的成本,我們未來會以開發者官網的形式對外輸出,更好地服務于開發者,

招聘

阿里巴巴高德地圖技術中心長期招聘Java、Golang、Python、Android、iOS 前端資深工程師和技術專家,職位地點:北京,歡迎投遞簡歷到gdtech@alibaba-inc.com,郵件主題為:姓名-應聘團隊-應聘方向,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/255890.html

標籤:其他

上一篇:2021年的今天,如何成為一名專業的前端工程師?

下一篇:漫畫 | CPU戰爭40年,真正的王者終于現身!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more