導言:優才網的春節相關的技術系列文章,今天繼續關注百度遷徙,我們是從前端的角度來分析的。昨天談完了數據和格式,今天來聊聊具體的 JS 實現。
昨天的文章里分析了百度遷徙的數據抓包和數據格式分析,了解了百度遷徙沒有使用 Flash 和 SVG 技術,而是使用的 echarts 庫,在Canvas上做的繪制,echarts 是百度前端團隊的開源項目(PS,百度前端團隊,有不少好的開源項目,如FIS、Ueditor、Tangram 都是百度前端開源的),據官方介紹,ECharts (Enterprise Charts 商業產品圖表庫),提供商業產品常用圖表,底層基于ZRender(一個全新的輕量級canvas類庫),創建了坐標系,圖例,提示,工具箱等基礎組件,并在此上構建出折線圖、柱狀圖、散點圖、K線圖、餅圖、雷達圖、地圖、和弦圖、力導向布局圖、儀表盤以及漏斗圖,同時支持任意維度的堆積和多圖表混合展現,也是目前所見的開源產品里圖形支持最全面的。
不過遷徙畢竟是地圖,所以在 echarts 上,有一層擴展,完成地圖到圖形操作和數據的映射,雖然 echarts 支持多種類型的圖形,但是由于只用到了地圖,所以在 Echarts的 chart 目錄下只用到了 map.js。如果想了解或者學習繪制其他類型的圖,可以進入 Github 下載源代碼。https://github.com/ecomfe/echarts
下面就來相對細致地分析一下,是如何將數據取回來,并展現到地圖上的。
我們從 mainIndex.js 入手來分析。正如昨天所說的機場和車站地理位置數據,在這個文件的第一行代碼就是各個省的各個地級城市的地理位置數據。這也是一份很價值的數據哦。
var CityGeoCoord = [
{ProvinceName: "北京", LatLng: [116.395645, 39.929986]},
{ProvinceName: "上海", LatLng: [121.487899, 31.249162]},
{ProvinceName: "天津", LatLng: [117.210813, 39.14393]},
{ProvinceName: "重慶", LatLng: [106.530635, 29.544606]},
{ProvinceName: "安徽", LatLng: [117.216005, 31.859252],
City: [{Name: "合肥", LatLng: [117.282699, 31.866942]},
{Name: "安慶", LatLng: [117.058739, 30.537898]},
{Name: "蚌埠", LatLng: [117.35708, 32.929499]},
{Name: "亳州", LatLng: [115.787928, 33.871211]},
{Name: "巢湖", LatLng: [117.88049, 31.608733]},
{Name: "池州", LatLng: [117.494477, 30.660019]},
{Name: "滁州", LatLng: [118.32457, 32.317351]},
{Name: "阜陽", LatLng: [115.820932, 32.901211]},
{Name: "淮北", LatLng: [116.791447, 33.960023]},
{Name: "淮南", LatLng: [117.018639, 32.642812]},
{Name: "黃山", LatLng: [118.29357, 29.734435]},
{Name: "六安", LatLng: [116.505253, 31.755558]},
{Name: "馬鞍山", LatLng: [118.515882, 31.688528]},
{Name: "宿州", LatLng: [116.988692, 33.636772]},
{Name: "銅陵", LatLng: [117.819429, 30.94093]},
{Name: "蕪湖", LatLng: [118.384108, 31.36602]},
{Name: "宣城", LatLng: [118.752096, 30.951642]}]},
接下來,是一些日期處理的工具函數,由于在遷徙的頁面上,使用了農歷和陽歷的對照,所以也有一個簡單的農歷計算工具函數。具體不詳述。
然后是在地圖上畫標記線、標記點,去除線和點的函數。而對于繪制圖的流程如下,以如下畫線為例:
mainIndex.js
function AddMarkLine(a, c, d) {
var b = $.extend(!0, {},
a.getOption().series[c].markLine);
b && (b.data = d, a.addMarkLine(c, b))
}
echarts.js(從Github庫中得到)
addMarkLine: function (seriesIdx, markData) {
return this._addMark(seriesIdx, markData, 'markLine');
},
_addMark: function (seriesIdx, markData, markType) {
var series = this._option.series;
var seriesItem;
if (series && (seriesItem = series[seriesIdx])) {
var seriesR = this._optionRestore.series;
var seriesRItem = seriesR[seriesIdx];
var markOpt = seriesItem[markType];
var markOptR = seriesRItem[markType];
markOpt = seriesItem[markType] = markOpt || { data: [] };
markOptR = seriesRItem[markType] = markOptR || { data: [] };
for (var key in markData) {
if (key === 'data') {
markOpt.data = markOpt.data.concat(markData.data);
markOptR.data = markOptR.data.concat(markData.data);
} else if (typeof markData[key] != 'object' || markOpt[key] == null) {
markOpt[key] = markOptR[key] = markData[key];
} else {
zrUtil.merge(markOpt[key], markData[key], true);
zrUtil.merge(markOptR[key], markData[key], true);
}
}
var chart = this.chart[seriesItem.type];
chart && chart.addMark(seriesIdx, markData, markType);
}
return this;
},
再接下來是DOM操作和事件綁定,還有其他的DOM工具函數。ChangeMenu 函數是一個切換菜單時調用的函數,在每一次菜單切換(也就是日期切換時)將各種數據重新初始化還原,包括界面上的輸入清空,數據類型重置等。傳入的參數是各種不同數據類型的類型編碼。
function changeMenu(a) {
MigrationResource.CurrentCondition.Province = "";
MigrationResource.CurrentCondition.City = "";
$("#input_cityName").attr("province", "");
$("#input_cityName").attr("city", "");
$("#input_cityName").val("");
$("#input_dateTime").val("");
MigrationResource.CurrentCondition.Flight = {};
$("#input_flight_start").val("");
$("#input_flight_end").val("");
MigrationResource.CurrentCondition.Type = Number(a);
MigrationResource.CurrentTime = (new Date).pattern("yyyy/MM/dd HH:mm");
updateSelectedTime();
updateDataSource();
MigrationResource.FileName = "";
MigrationResource.ChinaJson = {};
MigrationResource.CityJson = {};
MigrationResource.CurrentTrendData = {};
MigrationResource.Query(RedrawMap)
}
全局變量 MigrationResource 是一個非常重要的變量,里面包含了對地圖的初始化、以及數據源的設定和數據獲取。數據源的設定,是根據類型編號來的。比如11,12,13是航班數據。缺省的是人口遷徙數據,據主頁君測試,有些數據比如代號為202的數據還沒有。可能是將來要使用或者是廢棄掉的。
switch (MigrationResource.CurrentCondition.Type) {
case 11:
case 12:
case 13:
b = "data/flight";
break;
case 21:
b = "data/huoche";
break;
case 22:
b = "data/huoche";
break;
case 101:
b = "data/plane";
break;
case 102:
b = "data/train";
break;
case 103:
b = "data/bus";
break;
case 201:
b = "data/scenicspot";
break;
case 202:
b = "data/business";
break;
default:
b = "data/migration"
}
取數據的函數如下,是一個很清楚的使用 JSZipUtils 取數據的例子,并且是支持多文件的,取回來的數據是JSON格式,進行了解析,直接保存在MigrationResource數組中了。
function GetData(a, c, d, b, f, k) {
JSZipUtils.getBinaryContent(DomainName + a + "/" + c, function(a, c) {
a && "function" == typeof k && k();
try {
var e = new JSZip;
e.load(c);
for (var p in e.files)
for (var l = 0; l < b.length; l++) {
var m = b[l];
if (0 <= p.indexOf(m.FileName)) {
d[m.Attribute] = JSON.parse(e.file(p).asText());
break
}
}
"function" == typeof f && f()
} catch (n) {
return!1
}
})
}
接下來就是地圖的處理了,地圖先畫出基礎中國地圖,數據來自于 http://spotshot.baidu.com/getChinaLocDistribute.php 在經過 Map 封裝的 echarts 圖上繪制出中國地圖框架。
RedrawMap 是整個圖形繪制過程中的核心函數,根據當前要顯示的地圖的不同,進行不同的數據繪制。在這個過程中,進行了一些限定 ,比如限制地圖縮放等。我們也可以在Chrome 的開發者工具中,調用函數,EnableMapZoom() 來調試一下,讓當前地圖支持縮放。
function RedrawMap() {
StopInterval(initMapKey);
StopInterval(redrawMapKey);
StopInterval(ipNumKey);
$(".logo-box").show();
map.removeOverlay(heatmapOverlay);
map.removeControl(top_left_navigation);
isPc && ($("#timeline").show(),
$(".btn_open_list").click());
$(".other-box").removeClass("other-box-1");
switch (MigrationResource.CurrentCondition.Type) {
case -2:
RemoveBaseMap();
DisableMapZoom();
RefreshMap();
isPc ? AddBaseLine(AddBasePoint, !0) : (AddBasePoint(),
$("#mainMap").hide(),
$("#mobileDiv").show().children("div").attr("class", "index-page-1"));
break;
case -1:
AddHotLine();
break;
case 0:
AddHotPoint(0);
break;
case 1:
AddHotPoint(1);
break;
case 2:
RemoveBaseMap();
RefreshMap();
AddBasePoint();
AddCityHotLine(MigrationResource.CurrentCondition.Province, MigrationResource.CurrentCondition.City);
break;
case 3:
RemoveBaseMap();
RefreshMap();
AddBasePoint();
AddCityHotLine(MigrationResource.CurrentCondition.Province, MigrationResource.CurrentCondition.City);
break;
case 11:
RemoveBaseMap();
var a = phoneSizeZoom;
isPc ? (a = flightSizeZoom, EnableMapZoom(a)) : DisableMapZoom();
AddFlight();
break;
case 12:
AddFlight();
break;
case 13:
AddFlight();
break;
case 21:
RemoveBaseMap();
DisableMapZoom();
AddTrain();
break;
case 22:
RemoveBaseMap();
DisableMapZoom();
AddTrain();
break;
case 101:
RemoveBaseMap();
DisableMapZoom();
AddAirport();
break;
case 102:
isPc ? (RemoveBaseMap(),
DisableMapZoom(),
AddRailwayStation()) : ($("#mainMap").hide(),
$("#mobileDiv").show().children("div").attr("class", "index-page-2"));
break;
case 103:
RemoveBaseMap();
DisableMapZoom();
AddBusStation();
break;
case 201:
RemoveBaseMap();
DisableMapZoom();
AddScenicspot();
break;
case 202:
RemoveBaseMap(),
DisableMapZoom(),
AddBusiness()
}
}
當然,要繪制出各種各樣的圖,得有相應的函數,比如機場是AddAirport() ,都通過 RedrawMap 來進行了調用。在人口遷徙中,遷入調用的是AddHotPoint(0) 遷出調用的是AddHotPoint(1);
function AddHotPoint(a) {
RemoveHotPoint();
RemoveHotLine();
var c = [], d = [], b = {},
b = 0 == a ? MigrationResource.ChinaJson.topCityIn : MigrationResource.ChinaJson.topCityOut;
$(b).each(function(a, b) {
var g = {};
g.name = GetCityName(b.name);
g.CityLocation = b.name;
g.value = a + 1;
c.push(g);
d.push(g)
});
AddMarkPoint(myChart, 1, c);
AddCityShowName(d)
}
文件的后半部分,是有關右邊的列表的實現。其中比較比意思的地方是實現了對拼音搜索的支持。
var provincialCapital = {"安徽": "合肥", "福建": "福州", "甘肅": "蘭州", "廣東": "廣州", "廣西": "南寧", "貴州": "貴陽", "海南": "海口", "河北": "石家莊", "河南": "鄭州", "黑龍江": "哈爾濱", "湖北": "武漢", "湖南": "長沙", "吉林": "長春", "江蘇": "南京", "江西": "南昌", "遼寧": "沈陽", "內蒙古": "呼和浩特", "寧夏": "銀川", "青海": "西寧", "山東": "濟南", "山西": "太原", "陜西": "西安", "四川": "成都", "新疆": "烏魯木齊", "西藏": "拉薩", "云南": "昆明", "浙江": "杭州", "香港": "", "重慶": "", "北京": "", "天津": "", "上海": "", "臺灣": "臺北", "澳門": ""},
citys = ["香港 xianggang xg".split(" "),
"香港 香港 xianggang xg xianggang xg".split(" "),
"重慶 chongqing cq".split(" "),
"重慶 重慶 chongqing cq chongqing cq".split(" "),
"北京 beijing bj".split(" "),
"北京 北京 beijing bj beijing bj".split(" "),
"天津 tianjin tj".split(" "),
"天津 天津 tianjin tj tianjin tj".split(" "),
"上海 shanghai sh".split(" "),
"上海 上海 shanghai sh shanghai sh".split(" "),
"澳門 aomen am".split(" "),
這也是一份值得保存的數據和值得學習的做法。
地圖繪制就基本講完了,需要注意的一點,經緯度和屏幕像素等的轉換,最終是通過百度地圖類庫來實現的。具體的辦法是,在mainIndex 中調用 封裝好的 echarts 庫,而 echarts 庫,又調用 百度地圖API的庫,百度地圖 API 是通過這個 URL 取到的。
http://api.map.baidu.com/getscript?v=2.0&ak=ZUONbpqGBsYGXNIYHicvbAbM&services=&t=20150213143539
有關列表DOM操作不做過多介紹,我們下面來總結一下遷徙的實現。
百度遷徙,在2014年春節時推出,2015年春節,也被新聞媒體大量地引用,其在大數據產品化方面,有非常值得借鑒的意義,從技術上講,無論是數據繪制、數據從服務器端的獲取,還是本地的一些處理手法,都有值得我們學習的地方,優才網的公眾賬號,通過連續的兩篇文章,對其做一個簡單的分析,希望大家有用。
我們在春節期間推出的這些技術文章,得到了大家的歡迎。在后面,我們還將繼續為大家奉上原創的技術文章 。
如果覺得我們的文章不錯,歡迎關注優才網公眾賬號,以及查看原文,了解優才網的更多產品。
- PHP技術文章
- PHP中session和cookie的區別
- php設計模式(一):簡介及創建型模式
- php設計模式結構型模式
- Php設計模式(三):行為型模式
- 十款最出色的 PHP 安全開發庫中文詳細介紹
- 12個提問頻率最高的PHP面試題
- PHP 語言需要避免的 10 大誤區
- PHP 死鎖問題分析
- 致PHP路上的“年輕人”
- PHP網站常見安全漏洞,及相應防范措施總結
- 各開源框架使用與設計總結(一)
- 數據庫的本質、概念及其應用實踐(二)
- PHP導出MySQL數據到Excel文件(fputcsv)
- PHP中14種排序算法評測
- 深入理解PHP原理之--echo的實現
- PHP性能分析相關的函數
- PHP 性能分析10則
- 10 位頂級 PHP 大師的開發原則
- 30條爆笑的程序員梗 PHP是最好的語言
- PHP底層的運行機制與原理
- PHP 性能分析與實驗——性能的宏觀分析
- PHP7 性能翻倍關鍵大揭露
- 鳥哥:寫在PHP7發布之際一些話
- PHP與MySQL通訊那點事
- Php session內部執行流程的再次剖析
- 關于 PHP 中的 Class 的幾點個人看法
- PHP Socket 編程過程詳解
- PHP過往及現在及變革
- PHP吉祥物大象的由來
- PHP生成靜態頁面的方法
- 吊炸天的 PHP 7 ,你值得擁有!
- PHP開發中文件操作疑難問答
- MongoDB PHP Driver的連接處理解析
- PHP 雜談《重構-改善既有代碼的設計》之二 對象
- 在php中判斷一個請求是ajax請求還是普通請求的方法
- 使用HAProxy、PHP、Redis和MySQL支撐10億請求每周架構細節
- HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、Web Services 是什么?
- 重構-改善既有代碼的設計
- PHP場景中getshell防御思路分享
- 移動互聯時代,你看看除了PHP你還會些什么
- 安卓系統上搭建本地php服務器環境
- PHP中常見的緩存技術!
- PHP里10個鮮為人知但卻非常有用的函數
- 成為一名PHP專家其實并不難
- PHP 命令行?是的,您可以!
- PHP開發提高效率技巧
- PHP八大安全函數解析
- PHP實現四種基本排序算法
- PHP開發中的中文編碼問題
- php.get.post
- php發送get、post請求的6種方法簡明總結
- 中高級PHP開發者應該掌握哪些技術?
- 前端開發
- web前端知識體系大全
- 前端工程與性能優化(下)
- 前端工程與性能優化(上)
- 2016 年技術發展方向
- Web應用檢查清單
- 如何成為一名優秀的web前端工程師
- 前端組件化開發實踐
- 移動端H5頁面高清多屏適配方案
- 2015前端框架何去何從
- 從前端看“百度遷徙”的技術實現(一)
- 從前端看“百度遷徙”的技術實現(二)
- 前端路上的旅行
- 大公司里怎樣開發和部署前端代碼?
- 5個經典的前端面試問題
- 前端工程師新手必讀
- 手機淘寶前端的圖片相關工作流程梳理
- 一個自動化的前端項目實現(附源碼)
- 前端代碼異常日志收集與監控
- 15年雙11手淘前端技術總結 - H5性能最佳實踐
- 深入理解javascript原型和閉包系列
- 一切都是對象
- 函數和對象的關系
- prototype原型
- 隱式原型
- instanceof
- 繼承
- 原型的靈活性
- 簡述【執行上下文】上
- 簡述【執行上下文】下
- this
- 執行上下文棧
- 簡介【作用域】
- 【作用域】和【上下文環境】
- 從【自由變量】到【作用域鏈】
- 閉包
- 完結
- 補充:上下文環境和作用域的關系
- Linux私房菜