10萬人的大場館如何“畫座位”?
阿里妹導讀:疫情之下,宅在家里就是對自己的保護。我們相信大家能夠共度難關,早日迎來與親友們現(xiàn)場看電影、看球賽的那天。今天,我們就來講講10萬人的大場館如何“畫座位”?懷念過去的歡聚,期待下一次的再見。
說到“畫座位”,最常見的場景莫過于影院的在線選座購票。這個場景下的需求,對開發(fā)者來說并不難,但你知道10萬座位的大場館該如何畫嗎?座位不固定,場景復雜等一系列挑戰(zhàn)該如何應對?接下來,阿里文娛技術專家莫那和阿里文娛高級工程師土嚎,為你揭秘。
一、背景
1、網(wǎng)絡售票,需要畫座:購票所見即所得
大麥主要業(yè)務是票務,包括演唱會、體育賽事、音樂節(jié)等,品類繁多。賣票就要畫場館、畫座位,大家都在網(wǎng)上買過電影票,這不難理解。雖然可以拿電影售票做類比,但底層難度差異很大。沒有10W座的電影院,卻有10W座的演唱會,而且演出/體育類場館變化多,挑戰(zhàn)相當大。 2、大麥繪座演進:從示意圖到實際場景圖
大麥以前的繪座系統(tǒng),是安裝版的程序,畫座位只能一個看臺一個看臺地畫,看臺之間完全無關聯(lián),畫出來幾乎每個看臺都長一個模樣,座位只有相對位置的示意圖,沒有角度、距離,更談不上精確定位。
?
?? 
圖1:老版繪座頁面(已淘汰) 大麥網(wǎng)從2017年,開始設計新版繪座系統(tǒng)。這里沒有修補,沒有重構,新版繪座完全重來,連技術棧也由.NET換成了Java,由C/S換成了B/S。
新繪座以SVG矢量圖為核心,通過Canvas進行繪制,在演進的過程中攻克了大量的性能卡點和技術難點,最終打造成型,堪以重任。
?
?? 
?
?? 
圖2:新繪座頁面
二、新繪座:Flash走了,Canvas來了
1、Flash已死,來到路口,別無選擇
新繪座已誕生2年多,現(xiàn)在回首,這條路似乎早已注定。
老版繪座和選座是基于Flash的,悲劇的是,Adobe宣稱Flash 2020年后,將不再維護,相關技術會在2020年底全部退役,大麥的繪座和選座系統(tǒng),都被迫轉型。
Flash只是原因之一,看過競爭對手的產(chǎn)品,會發(fā)現(xiàn)SVG是條不錯的道路,即使沒有Flash這一出,大麥網(wǎng)也會朝這個方向邁進。
2、技術選型
1)任何過度使用DOM的應用,都不會快。
經(jīng)過技術調(diào)研,發(fā)現(xiàn)國外一些場館座位繪制,選用的是SVG方案,每個座位都是一個獨立的SVG元素。但如果直接把SVG搬到瀏覽器,無法支持幾萬座位的場館,因為瀏覽器無法支持過多的DOM數(shù)量,并且,一旦DOM數(shù)量太多,操作一定是低效的,“任何過度使用DOM的應用,都不會太快”。
于是,技術同學想到了Canvas,Canvas是瀏覽器上的一個畫布,無論上面繪制多少元素,對于瀏覽器而言,都只是一個DOM元素。
對于不了解Canvas的同學,我們可以簡單做個說明,Canvas在瀏覽器上,就是下面一個標簽:
<canvasid="myCanvas" width="200" height="100"style="border:1px solid #000000;">
</canvas>
在Canvas上繪圖,就是使用JS獲取Canvas對象,使用封裝好的方法進行繪制。Canvas畫布上的圖形變化,完全通過擦除+重繪的方式展現(xiàn)。
那么新繪座的目標就變得很明確了,我們就是要在Canvas上繪制出想要的場館座位圖,然后以SVG的格式把圖形保存起來,用以選座、售票。 2)Canvas也不是銀彈:單個Canvas的大小是有限制的,超限之后也會卡頓。
選型初期,技術同學使用Canvas+SVG做了個Demo,模擬了10W座位的渲染,并實現(xiàn)了拖拽、縮放。但真正作為畫座組件開發(fā)的時候,發(fā)現(xiàn)座位達到2W就出現(xiàn)了卡頓,因為Canvas的寬高達到一定的數(shù)值,就會出現(xiàn)卡頓。于是,沿著化整為零的思路,技術同學將整個畫布,分成了多份Canvas,形成了一個Canvas矩陣,通過對每個Canvas的操作,完美解決了單個Canvas過大引起卡頓的問題。
關于Canvas繪圖組件,大家可以在網(wǎng)上搜到很多資料,這里不再贅述。
3、新版繪座上線初期:青蘋果
剛上線的新版繪座,就像個青澀的蘋果,雖然漂亮,卻沒那么好吃。
最突出的問題有2個:第1個是變形難用,由于算法比較初級,座位矩陣變形很難滿足用戶需求;第2個是接口速度慢,打開一個1W座的場館,好幾分鐘,超過5W,直接崩潰,根本無法支持。
為什么理想很豐滿,結果卻差強人意呢?根源在于第一版只重功能,忽略了算法效率。與服務端的接口調(diào)用,都是整個場館級別的,幾萬座位數(shù)據(jù),加上關聯(lián)的看臺、票、以及狀態(tài)等,一個碩大的數(shù)據(jù)包在前后端丟來丟去,系統(tǒng)不堪重負,用戶受盡折磨。 4、艱苦改進之旅
新繪座上線后,立刻啟動了改進優(yōu)化工程,主要攻克的難關有三點:1. 頁面響應時間;2. 座位自由組合變形;3. 打印順序計算。
1)交互+接口優(yōu)化,進入秒開時代
首先要解決接口慢的問題,解決效率低的一大法寶:化整為零。
從一次load一個場館的數(shù)據(jù),改成一次load幾個看臺的數(shù)據(jù)。服務端數(shù)據(jù)隨著前端視口(頁面可視范圍)的變化,逐漸加載,類似地圖常用的“拉框查詢”。前端交互也從全加載,改為按視口取數(shù)據(jù)。僅此一項優(yōu)化,幾萬座大場館的系統(tǒng)響應速度,立刻由幾分鐘,降到了1~2s,小場館更是瞬時打開,系統(tǒng)好用了不少。
這里面最重要的一個技術點,就是視口計算,原理如下:
前端首先獲取到屏幕視口在Canvas畫布上的坐標,然后和看臺的外接矩形進行碰撞檢測,兩個矩形一旦相交,就說明該看臺已暴露在視口之內(nèi),于是就加載該看臺的數(shù)據(jù)。
從接口優(yōu)化開始,新繪座逐漸走向成熟。
?
?? 
圖3:按視口加載原理圖
2)合并座位矩陣,自由變形
座位自由變形包括傾斜、錯位、排距、座距、旋轉、弧度等多種操作。除了弧度變形,其它基本上是一些數(shù)學上的坐標計算,我們不贅述,這里重點說一下弧度變形。
新弧度變形,運用貝塞爾二階曲線原理,根據(jù)用戶的數(shù)據(jù)輸入,計算出相應的貝塞爾曲線,再把每排座位,均勻排列到曲線上。下面是貝塞爾二階公式:
?
?? 
圖4:貝塞爾曲線示意圖
?
?? 
注釋:P0、P2為一排座位的左右端點(一排的第一個座位和最后一個座位)。
看似套公式就可以搞定,非常簡單的樣子。但是這里有一個難點:從圖中可以看出,t為比例值,處在線段P0P2不同的比例,所在的弧度位置也是不一樣的。
如果所有的座位都在P0P2線段上,很好算,但是如果座位之前就是一條弧線呢?
中間所有的座位都不在P0P2線段上,要怎么算出中間座位的每個比例?
我們通過弧線上的每個座位,做一條P0P2線段的垂線,垂線與線段P0P2的交點,就是這些座位所在這一排的原始位置,計算出這些原始位置的坐標,根據(jù)這些原始位置,就可以算出中間所有座位的比例了。
這樣,弧度變形問題就通過貝塞爾二階曲線完美解決。
?
?? 
圖5:弧形座位矩陣貝塞爾曲線變形原理圖
?
?? 
圖6:弧度變形實際操作
?
?? 
圖7:座位自由組合,隨意變形
3) 打印順序計算
“打印順序”是個什么鬼?
這得從大麥的業(yè)務特點說起,主辦有時候會批量出票并將票配發(fā)給相關人群,有時整個看臺一起打印。在配票的時候,需要按照座位的物理位置關系排序,避免座位沒挨著、“2個情侶”被“拆散”的情況發(fā)生。舉個例子:下圖中,主辦期望打印票的順序是“5-3-1-2-4-6”,而不是“1-2-3-4-5-6”,這樣他們就可以按打印順序配票,而不用擔心兩張票不挨著。那么,在繪座過程中,我們就要計算出座位的順序,看似簡單,實現(xiàn)起來有難度很大,原因只有一個,場館形狀各異,座位排列多樣。
?
?? 
圖:8:北京奧體中心的某個看臺
如果說,上圖還能按照座位Y坐標對比進行排序,那么下面的幾個情形,就不那么好處理了:
?
?? 
圖9:各種特殊的座位排列場景
打印問題,我們通過場景匯總,對場館進行分區(qū),最終找到了排序的規(guī)律,得以解決。打印問題技術方案原理:
第1步:將場館分成8個象限,象限內(nèi)的座位,已標識出該如何排序(標識出了應該對比X坐標還是Y坐標來進行排序);
第2步:每一組座位矩陣,取出首排,求首尾座位連線的斜率,然后根據(jù)斜率將座位矩陣劃分到對應象限;
第3步:按照對應象限的排序標識,對比座位的X坐標(或Y坐標),進行座位排序。
?
?? 
圖10:座位排序原理圖
4)小彩蛋之“沙發(fā)、角度”
效率、變形和打印3個主要問題根解之后,隨之出現(xiàn)了大量的產(chǎn)品優(yōu)化需求,開始著眼于細微之處,小沙發(fā)和座位角度就是2個典型的功能。這兩個功能雖然難度不大,但卻在體驗上有了一大步的提升。
?
?? 
圖11:圓點、沙發(fā)效果對比
5)小彩蛋之“撤回”
經(jīng)過不斷優(yōu)化和添磚加瓦,大麥的繪座系統(tǒng),越來越像一款專業(yè)的繪圖工具。好的繪圖工具一定需要“前進&撤回”功能。
新繪座系統(tǒng)的撤回功能實現(xiàn)原理:設計一個“歷史數(shù)據(jù)”數(shù)組,數(shù)組里的每個元素,記錄一個操作步驟對應的被編輯座位數(shù)據(jù)以及座位位置信息,回退時,找到對應操作步驟的數(shù)組元素,重繪座位位置,這樣就回退了整個操作。因為無論座位相對位置如何變形,本質(zhì)上,其實都是坐標數(shù)據(jù)的改變,通過記錄和重繪歷史坐標信息,就達到了撤回操作的目的。 三、 在正確的路上繼續(xù)前行
到目前為止,新繪座系統(tǒng)已能夠承接國內(nèi)外任何大型場館的繪座工程,各種細節(jié)的優(yōu)化也日臻完善,效率大幅提升。但產(chǎn)品和技術同學的努力,并沒有終止,而是在正確的道路上,繼續(xù)前行。
以下簡單列舉幾個很實用的功能,供大家參考:
1)區(qū)域編輯:自由繪制矩形、圓形、多邊形等各種形狀,并自由變形;
2)一鍵自動變形:全選看臺內(nèi)的座位,點擊“一鍵變形按鈕”,座位瞬間適應看臺形狀,自動排列。
?
?? 
圖12:一鍵變形效果圖
3)座位復制、鏡像:區(qū)用戶可以自由復制選中座位,并且支持鏡像、翻轉等多種復制模式,排號、座位號根據(jù)設置自動處理;
4)一鍵朝向舞臺:用戶選中一個看臺的數(shù)據(jù),點擊“一鍵朝向舞臺”,系統(tǒng)會自動計算舞臺方向和座位角度,瞬間將整個看臺座位“擺正”。



















