做者:韓永豪 前端開發部 前端開發工程師javascript
以前發佈的文章《一個炫酷大屏展現頁的打造過程》反響很是熱烈,在感謝你們支持的同時,我挑了四個問題,在這裏解答一下:前端
Q1: 有用到第三方庫麼?java
A1:頁面邏輯都是原生寫的,簡單封裝了一些對節點的操做。git
Q2:地圖是怎麼畫出來的?github
A2:地圖是由設計師提供的圖片,而地圖上閃動的光點和冒出的氣泡是DOM節點,樣式和動畫都是經過CSS實現的。ajax
Q3:怎麼適配不一樣的分辨率?算法
A3:適配不一樣屏幕儘可能仍是用百分比,至於字體大小或者某些固定大小的元素,這裏用到了rem適配,根據屏幕分辨率計算根節點的字體大小,從而調節總體尺寸。npm
Q4: 能提供DEMO嗎?json
A4: 這個問題是你們最感興趣,也是最多人提出的。因爲項目自己涉及到公司機密,所以不方便提供完整的源碼,可是通過一番整理,已經把主要的功能獨立成一個開源項目。本文的主要內容就是介紹這個開源項目,即 「Scatter Map Toolkit」(散點圖工具包)。瀏覽器
先回顧一下大屏展現頁的地圖展現模塊,其主要功能就是把數據轉化爲光點顯示在地圖對應的省份區域內:
要實現這個效果,首先碰到的問題就是:地圖上的省份是不規則圖形,很難界定一個省份的區域,因此本開源項目的第一個功能就是以圖形化的界面輔助開發者劃定每一個不規則的區域,而且輸出爲JSON數據。而第二個功能就是根據這份數據把光點定位到具體的區域。
按照微積分的原理,要計算一個不規則圖形的面積,能夠將其切割成若干個矩形,矩形越小,數量越多,覆蓋面積越廣,矩形面積之和就越接近這個不規則圖形的面積,這個工具就是利用這個原理劃定區域。
要使用這個工具,先從Github克隆本項目到本地,在命令行切換到項目路徑,運行:
$ npm install
$ npm start
複製代碼
而後用瀏覽器訪問「 http://localhost:8000/ 」便可進入界面,後續操做步驟以下:
最終效果以下:
生成的JSON文件以下:
{
"image": "https://qiniu-pic.ibeiliao.com/o_1c93ofmqlug61uid15qe174d5ke7.png",
"data": {
"廣東": {
"isShow": true,
"areas": [
{
"x1": "58.778625954198475%",
"x2": "64.02035623409668%",
"y1": "71.23695976154993%",
"y2": "78.09239940387481%"
},
{
"x1": "64.02035623409668%",
"x2": "70.38167938931298%",
"y1": "73.91952309985098%",
"y2": "78.09239940387481%"
},
...
]
}
},
"setting": {
"resize": true,
"width": 1310,
"height": 895
}
}
複製代碼
生成這份區域數據以後要如何使用呢?首先,一個光點必然是顯示在某個省的區域內的,因此要從數據中找到該省份的配置:
// 全部的區域數據都存在這個json文件內
ajax('options.json').then((options) => {
// 廣東省的矩形區域集合
options.data['廣東'].areas;
});
複製代碼
其次,在矩形區域集合內隨機選擇一個區域,並在該區域內隨機選擇一個點:
// 在區域中隨機選取一個座標點
function radom(area) {
let x1 = parseFloat(area.x1);
let x2 = parseFloat(area.x2);
let y1 = parseFloat(area.y1);
let y2 = parseFloat(area.y2);
return {
x: x1 + ((x2 - x1) * Math.random()) + '%',
y: y1 + ((y2 - y1) * Math.random()) + '%'
};
}
// 從集合中隨機獲取一個矩形區域
function getArea(areas) {
return areas[Math.floor(Math.random() * areas.length)];
}
// 全部的區域數據都存在這個json文件內
ajax('options.json').then((options) => {
// 隨機獲取一個矩形區域
let area = getArea(options.data['廣東'].areas);
// 隨機獲取一個座標點
random(area);
});
複製代碼
然而,這種作法會出現一個問題:面積大的矩形裏面的點被選中的機率和麪積小的矩形被選中的機率不一致。假設一個省份包含兩個矩形區域:
具體的體現就是面積小的矩形裏面的點會更密集。爲了解決這個問題,咱們對隨機選取矩形的算法進行了改良,面積越大被選中的機率就越大。思路很簡單,把全部矩形的面積轉化成一條線段(200個點+50個點=250個點的線段),在這條線上面隨機獲取一個點,這個點所在的線段對應的矩形就是隨機獲取到的矩形,由於矩形A在線段上佔比更大,因此獲取到點的機率也更大:
實現代碼以下:
/** 根據每一個矩形的權重,隨機獲取一個矩形區域
* @param {Array} areas 矩形集合
* @param {Number} areas[i].sumArea 改矩形的面積
* @param {Number} sumArea 全部矩形的總面積
*/
function getArea(areas, sumArea) {
let currentSumArea = 0; // 當前累計總面積
let result = null; // 查找結果
this.areas.some((area) => {
// 查找這個數落在哪條線段上
if (
random >= currentSumArea &&
random <= currentSumArea + area.sumArea
) {
result = area;
return true;
}
currentSumArea += area.sumArea;
});
return result;
}
複製代碼
這樣改良後,兩個矩形裏面的點被選中的機率都是同樣的:
這裏的功能已經封裝爲項目中「 /dist/scatter-map.min.js 」的randomFromGroup方法
最後迴歸到一開始說的地圖展現模塊,如今只須要先用區域劃定工具生成區域數據,而後引入庫,再調用它的方法,就能夠獲取隨機座標點。
<scrpit type="text/javascript" src="dist/scatter-map.min.js"></script>
<scrpit type="text/javascript">
ajax('options.json').then((options) => {
// 工具實例化
let scatterMap = new ScatterMap(options);
// 隨機獲取廣東省的一個座標點,格式以下:
// { x: '50%', y: '50%' }
scatterMap.randomFromGroup('廣東');
});
</script>
複製代碼
而後,只須要根據這個座標點設置光點的位置,加上樣式和動畫便可完成上述效果。
雖然項目的總體功能都已經完成,可是因爲時間限制,區域劃定工具還存在一些兼容性問題,目前建議經過谷歌瀏覽器打開使用,後續會完善兼容代碼。
當前版本的工具包不含光點繪製功能,例子中的光點繪製是經過DOM節點實現的,若是數量過多,有可能會形成頁面卡頓,瀏覽器佔用內存過大。所以,接下來會考慮把使用SVG或Canvas實現光點繪製。
當前版本的區域劃定功能還不夠方便,須要繁瑣的手動操做,後續但願能夠作到Photoshop魔法棒的效果,能夠根據色差判斷不規則區域的覆蓋範圍,這樣繪製的效率將會大大提升。
最後再貼一下地址,但願你們多多支持:github.com/beiliao-mob…