vue echarts實現航班選座案例分析

背景

最近在echarts官方看到瞭一個航班選座的示例,感覺很好,可以擴大,縮小,鼠標放置到座位上可以顯示座位號,允許默認選中座位。於是在5.1假期抽瞭一點點時間,來寫一篇文章,深入研究分析一下這個示例,解析一下這個示例的完整代碼。首先讓我們來看下示例的效果圖。

實現思路

代碼是使用echarts來實現的,主要用到的是svg和自定義地圖的相關知識。
示例的完整代碼

在做選座的功能,我們使用div佈局加背景圖的技術手段也能簡單實現,但不支持縮放,在位置比較多,想要看詳細的情況下,就需要用到svg,這個可以擴大縮小後不會失真的矢量圖形。搭配echarts渲染能力和可擴展性,做出來的功能可以達到很好的用戶體驗。
這個示例的主要特性大致有以下幾點

  • 座位默認三種狀態,未選的(白色),自己選的(綠色的),已被別人選的(紅色)
  • 可以擴大,縮小,圖片不失真,清晰
  • 鼠標放到座位上可以顯示座位號
  • 可移植性,換個svg文件,就能改成影院選座,或會議室排座
  • 簡單,快捷,代碼隻有不到100行

代碼分析

獲取svg

在示例代碼中,首先是要獲取一個svg文件。

$.get(ROOT_PATH + '/data/asset/geo/flight-seats.svg', function (svg) {
  // ....
})

使用jquery獲取一個svg文件,svg的完整路徑是 https://cdn.jsdelivr.net/gh/apache/echarts-website@asf-site/examples/data/asset/geo/flight-seats.svg
點擊可以訪問。但顯示的是這樣的。

隻顯示個飛機頭,這是因為svg太大的原因。要想看完整的,需要使用專門的svg查看軟件。
使用jquery獲取的svg,是svg文件的編碼。我們可以調試,打印一下svg的內容看一下。

這裡可以看到是svg的具體內容。

註冊自定義地圖

echarts是可以搭配地圖來實現自定義的位置坐標佈局渲染的。但不僅僅局限於百度,高德地圖。他還支持將一個符合地圖數據的svg註冊為一個地圖。
下面來看一下echarts的這個註冊自定義地圖的api。

registerMap

完整的解釋點擊此處查看

文檔的大致意思就是 你可以配置一個geoJson的東西,然後echarts可以解析內部的坐標,然後渲染,支持查找。
echarts中geo的相關文檔。
https://echarts.apache.org/zh/option.html#geo
該組件可以配置一些name,顏色,索引,能否被選中,交互後的顏色,hover效果。

這裡稍微擴展一下GeoJSON這個東西,我也是第一次接觸。它是一種用於編碼各種地理數據結構的格式。
一種編程式的地圖,用一些特殊的屬性來表達地圖上的線,面,點,顏色。區域。
以GeoJSON支持以下幾何類型:Point,LineString, Polygon,MultiPoint,MultiLineString,和MultiPolygon。具有其他屬性的幾何對象是Feature對象。要素集包含在FeatureCollection對象中。
這裡說的不對的,歡迎大佬拍磚,傳道解惑。
相關文檔
這裡如果要展開講的話,以我現在的知識點,肯定講的不夠透徹,如果有感興趣的同學,可以在評論區留言,下篇文章可以給大傢帶來有關geojson更詳細的解析。

回歸主線,那麼registerMap這個方法其實就是將svg轉化為一個標準的地圖坐標系。隻不過轉化後地圖的定位不是根據經緯度,而是因為name。

 echarts.registerMap('flight-seats', { svg: svg });

好瞭上面這句代碼的含義就講解到這裡。其實想想,每一個api的後面都牽扯到一大堆的知識。隻要你細心,具有探索精神,那就一定會學的比別人多,學的好。知識是連貫的,不是單獨存在的。舉一反三,融會貫通方得學道。

geo組件的配置

echarts中有很多很多的組件如brush(區域選擇組件),parallel(平行坐標系),timeline,calendar(日歷坐標系),其中一個就是geo,地理坐標系組件。
地理坐標系組件用於地圖的繪制,支持地理坐標系上繪制散點圖,線集。
有關geo組件的所有的配置項都可以在此處查詢到詳細的解析。
此案例使用的就是該組件,那麼下面來看下示例是如何配置的。

geo: {
    map: 'flight-seats',
    roam: true,
    selectedMode: 'multiple',
    layoutCenter: ['50%', '50%'],
    layoutSize: '95%',
    tooltip: {
        show: true
    },
    itemStyle: {
        color: '#fff'
    },
    emphasis: {
        itemStyle: {
            color: null,
            borderColor: 'green',
            borderWidth: 2
        },
        label: {
            show: false
        }
    },
    select: {
        itemStyle: {
            color: 'green'
        },
        label: {
            show: false,
            textBorderColor: '#fff',
            textBorderWidth: 2
        }
    },
    regions: makeTakenRegions(takenSeatNames)
}

以上是示例中有關geo組件的配置,下面讓我們仔細分析一下每一個配置項。

map

首先map指向的是我們剛剛註冊的一個自定義地圖'flight-seats'

map: 'flight-seats',

roam

roam關鍵字是用於配置是否開啟鼠標縮放和平移漫遊。默認不開啟。如果隻想要開啟縮放或者平移,可以設置成 ‘scale’ 或者 ‘move’。設置成 true 為都開啟

selectedMode

如字面意思selectedMode 字段是用於配置選中模式,表示是否支持多個選中,默認關閉,支持佈爾值和字符串,字符串取值可選’single’表示單選,或者’multiple’表示多選。

layoutCenter, layoutSize

用於調整echarts的實例在dom容器中的初始位置。

tooltip

是否開啟tooltip效果,開啟後,鼠標放到座位上會有文本提示當前座位。

itemStyle

座位的默認樣式,配置顏色,字體

emphasis

高亮狀態下的多邊形和標簽樣式。

select

選中狀態下的多邊形和標簽樣式。

regions

在地圖中對特定的區域配置樣式。這裡傳入的是一個數組,被格式化後的已被選的座位信息,
默認已經被選
每一項的數據格式是這樣的

{
    name: '26E',
    silent: true,
    itemStyle: {
        color: '#bf0e08'
    },
    emphasis: {
        itemStyle: {
            borderColor: '#aaa',
            borderWidth: 1
        }
    },
    select: {
        itemStyle: {
            color: '#bf0e08'
        }
    }
}

其中有一個屬性叫做 silent 它的作用是圖形是否不響應和觸發鼠標事件,默認為 false,即響應和觸發鼠標事件。

到這裡該示例的echarts配置其實已經講解完瞭。這裡的坐標系不是用經緯度,而是用每個座位的name來查找的。所以在svg中是可以找到對應的name的。name的值必須保證唯一。

該示例中除瞭核心的配置外,還有二個輔助函數。一起來看一下。

makeTakenRegions函數

這個函數就是將已經定義好的已選座位數據,轉化成格式化的座位樣式數據。
下面是定義的默認已被選中的座位。

var takenSeatNames = ['26E', '26D', '26C', '25D', '23C', '21A', '20F'];

geoselectchanged

在這個示例的最後,有一個監聽函數

myChart.on('geoselectchanged', function (params) {
    var selectedNames = params.allSelected[0].name.slice();
    // Remove taken seats.
    for (var i = selectedNames.length - 1; i >= 0; i--) {
        if (takenSeatNames.indexOf(selectedNames[i]) >= 0) {
            selectedNames.splice(i, 1);
        }
    }
    console.log('selected', selectedNames);
});

這幾行代碼是幹嘛的那?
我們在點擊座位的時候,是有一個點擊事件,這裡就是用於處理點擊後的交互的,然後獲取當前用戶選中的座位。
geoselectchanged 世界是 geo 中地圖區域切換選中狀態的事件。
用戶點擊選中會觸發該事件。 相關文檔

我們可以調試一下該函數看下,params的內容具體是什麼

這裡是用於處理點擊已經被人選中的座位,不進行選中,這段函數的使用場景是用於獲取當前用戶選中的座位列表,比如用戶選完座外要將座位信息發送給後臺保存。
主要功能就是判斷選的座位是不是已經被別人選中瞭,如果已被選中就剔除。

舉一反三

分析完代碼後,瞭解瞭每一個配置項的含義,那麼我們趁熱打鐵做一個類似的聯系題,以達到舉一反三,融會貫通的目的。
需求,定義一個svg文件,有6個方塊,使用它做一個選座位的功能。
定義mysvg文件

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="600px" height="600px" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <g name="a1">
        <rect x="20" y="20" rx="20" ry="20" width="100" fill="#cccccc" stroke="#000000" height="100" />
    </g>
    <g name="a2">
        <rect x="20" y="120" rx="20" ry="20" width="100" fill="#cccccc" stroke="#000000" height="100" />
    </g>
    <g name="a3">
        <rect x="20" y="220" rx="20" ry="20" width="100" fill="#cccccc" stroke="#000000" height="100" />
    </g>
    <g name="a4">
        <rect x="20" y="320" rx="20" ry="20" width="100" fill="#cccccc" stroke="#000000" height="100" />
    </g>
</svg>

html代碼

<div id="main" style="height:600px;width:600px"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<script>
    var chartDom = document.getElementById('main');
    var myChart = echarts.init(chartDom);
    var option;
    $.get('/mysvg.svg', function (svg) {
        echarts.registerMap('flight-seats', { svg: svg });
        var takenSeatNames = ['a1'];
        option = {
            tooltip: {
            },
            geo: {
                map: 'flight-seats',
                roam: true,
                selectedMode: 'multiple',
                layoutCenter: ['50%', '50%'],
                layoutSize: '95%',
                tooltip: {
                    show: true
                },
                itemStyle: {
                    color: '#fff'
                },
                emphasis: {
                    itemStyle: {
                        color: null,
                        borderColor: 'green',
                        borderWidth: 2
                    },
                    label: {
                        show: false
                    }
                },
                select: {
                    itemStyle: {
                        color: 'green'
                    },
                    label: {
                        show: false,
                        textBorderColor: '#fff',
                        textBorderWidth: 2
                    }
                },
                regions: makeTakenRegions(takenSeatNames)
            }
        };
        function makeTakenRegions(takenSeatNames) {
            var regions = [];
            for (var i = 0; i < takenSeatNames.length; i++) {
                regions.push({
                    name: takenSeatNames[i],
                    silent: true,
                    itemStyle: {
                        color: '#bf0e08'
                    },
                    emphasis: {
                        itemStyle: {
                            borderColor: '#aaa',
                            borderWidth: 1
                        }
                    },
                    select: {
                        itemStyle: {
                            color: '#bf0e08'
                        }
                    }
                });
            }
            return regions;
        }
        myChart.setOption(option);
        // Get selected seats.
        myChart.on('geoselectchanged', function (params) {
            var selectedNames = params.allSelected[0].name.slice();
            // Remove taken seats.
            for (var i = selectedNames.length - 1; i >= 0; i--) {
                if (takenSeatNames.indexOf(selectedNames[i]) >= 0) {
                    selectedNames.splice(i, 1);
                }
            }
            console.log('selected', selectedNames);
        });
    })
</script>

效果圖

1212.gif

註意點

  • svg文件必須的每一個座位,可點擊區域必須要用g標簽包裹,且name屬性需
  • 定義到g標簽上定義geojson時,svg不能指向一個文本 結語

如果掌握瞭echarts的geo自定義地圖,那麼你能做出非常多的示例
比如這樣的

這樣的

還有這樣的

隻需要一個svg文件,再加幾個name,你就可以做成自己想要的地圖系圖表。
最後送大傢一句話:
不積跬步,無以至千裡;不積小流,無以成江海

到此這篇關於vue echarts實現航班選座案例分析的文章就介紹到這瞭,更多相關vue echarts航班選座案例內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: