【2019數模國賽C題】js+BaiduMap API實現上海浦東機場出租車行車路徑可視化

作為數學苦手,每次參加數模(雖然加上這次也就兩次)都是抱著劃水抱大腿的打算參加的……C題要求的是搜集某城市航班和該城市機場出租相關信息敞葛,航班信息倒簡單腺占,爬一下攜程、飛常準之類的網站就行了妙黍。機場出租信息真是要了老命……按思路有兩種,一種是查機場出租車秩序站的相關接口楣导,在某乎上有看到有匿名網友爬到了鄭州新鄭機場出租車秩序站的一個網頁废境,但找來找去沒找著;第二種則是統(tǒng)計篩選某城市所有出租車的GPS路徑筒繁,本來覺得這數據處理也太麻煩了噩凹,也找不到數據。在幾乎打算直接編造數據的時候毡咏,在某乎上找到了一份2007年上海出租車的GPS數據驮宴,處理了一下也還好。做了個簡單的可視化呕缭,雖然對論文估計沒啥用堵泽,但還是挺有意思的修己,這里記錄一下簡單的js和相關接口的運用,萌新如我也可以輕松學會迎罗。

數據格式

一段示例數據:

2108,2007-02-20 00:01:06,121.438500,31.249000,  0, 45,0
2108,2007-02-20 00:02:07,121.438500,31.249000,  0, 45,0
2108,2007-02-20 00:03:08,121.438500,31.249000,  0, 45,0
2108,2007-02-20 00:04:09,121.438500,31.249000,  0, 45,0
編號 時間 經度 緯度 速度 偏移角度 載客狀態(tài)
2108 2007-02-20 00:01:06 121.438500 31.249000 0 45 0

實現過程

整個數據有4000多份睬愤,每一份都是一輛出租車一天約每隔一分鐘產生的位置信息。因為其中不乏沒有出動的纹安、只在市區(qū)載客的出租車尤辱,我們需要篩選出經過上海浦東機場的數據,從百度地圖上找出上海浦東機場的位置為[121.81509,31.157478]厢岂,為了方便簡單的定義經過該坐標半徑3000m即視作經過浦東機場光督。

# -*- coding:utf-8 -*-
import os
from math import radians, cos, sin, asin, sqrt
import shutil

#計算兩點間距離-m
def geodistance(lng1,lat1,lng2,lat2):
    lng1, lat1, lng2, lat2 = map(radians, [lng1, lat1, lng2, lat2])
    dlon=lng2-lng1
    dlat=lat2-lat1
    a=sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    dis=2*asin(sqrt(a))*6371*1000
    return dis

def all_path(dirname):

    result = []#所有的文件

    for maindir, subdir, file_name_list in os.walk(dirname):

        for filename in file_name_list:
            apath = os.path.join(maindir, filename)#合并成一個完整路徑
            result.append(apath)

    return result


if __name__ == '__main__':
    dis = [121.81509,31.157478]
    path = r'E:\雜圖作品\20190912數學建模\數據(打開前請看備注)'
    to_path = r'E:\雜圖作品\20190912數學建模\經過浦東機場的數據'
    txts = all_path(path)
    count = 0;
    for i in txts:
        f = open(i)
        for s in f.readlines():
            a = s.split(',')
            if(geodistance(float(a[2]),float(a[3]),dis[0],dis[1])<3000):
                print("%s經過了浦東機場"%i)
                shutil.copy(i, to_path)
                count+=1
                break
    print("共%d輛出租車經過浦東機場"%count)

經過篩選,有263條數據經過了浦東機場塔粒,還是比較可觀的结借。

隨后就開始前端展示的搭建,我的需求是網頁里可以打開相對應的文本卒茬,隨后繪制出一天中所有的路徑船老,其中載客狀態(tài)由不同顏色的線條表示。同時有一個可拖動的進度條圃酵,可以控制一天內的大致時間來觀察其路徑的具體方向努隙。

首先是一個打開文件的按鈕,為其綁定事件。

 <input id='file' type="file" onchange="upload(this)" />
function upload(input) {
    //支持chrome IE10
    if (window.FileReader) {
        var file = input.files[0];
        console.log(file)
        filename = file.name.split(".")[0];
        var reader = new FileReader();
        reader.onload = function() {
            var arr = this.result.split("\n");
            arrData = arr;
            console.log(arr);
            map.clearOverlays(); 
            drawLines(arr);
        }
//      reader.readAsText(file,"UTF-8");
        reader.readAsText(file,"gb2312");
        
    }
    //支持IE 7 8 9 10
    else if (typeof window.ActiveXObject != 'undefined'){
        var xmlDoc;
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = false;
        xmlDoc.load(input.value);
        alert(xmlDoc.xml);
    }
    //支持FF
    else if (document.implementation && document.implementation.createDocument) {
        var xmlDoc;
        xmlDoc = document.implementation.createDocument("", "", null);
        xmlDoc.async = false;
        xmlDoc.load(input.value);
        alert(xmlDoc.xml);
    } else {
        alert('error');
    }

因為我使用的是chrome瀏覽器辜昵,所以只在其中一個分支里進行了邏輯處理,其他的兼容性分支也是類似的咽斧。

 reader.onload = function() {
            var arr = this.result.split("\n");
            arrData = arr;
            console.log(arr);
            map.clearOverlays(); 
            drawLines(arr);
        }

即載入文件后堪置,就對百度地圖的組件進行重繪,具體百度地圖API的接入可參考代碼或者百度的文檔张惹。

function drawLines(arr,p){
        p = p || 1.0;
        var t = arr[0].split(",");
        var lastLong = t[2];
        var lastLat = t[3];
        var isFull = 0;
        var lastFull = 0;
        var temp = [];
        for(var i = 0 ; i < arr.length*p - 1; i=i+1){
            var a = arr[i].split(",");
            if(a[2]<120||a[2]>122||a[3]<30||a[3]>33)
                continue;
            
            if(a[6]!=lastFull || i == arr.length - 2){
                var c = "green";
                if (lastFull==1){
                    c = "red";
                }
                var polyline = new BMap.Polyline(temp, {strokeColor:c,
                                          strokeWeight:3, 
                                          strokeOpacity:1});
                map.addOverlay(polyline);
                temp = [];
                temp.push(new BMap.Point(lastLong,lastLat))
            }
            temp.push(new BMap.Point(a[2],a[3]));
            lastLong  = a[2];
            lastLat = a[3];
            lastFull = a[6];
        }
   }

邏輯也比較簡單舀锨,對每行文本進行經緯度提取然后再通過BMap.Polyline()進行繪圖,該API需要傳入一個經緯度的數組和線條的樣式宛逗。只不過需要注意的是坎匿,由于我想要路徑顏色根據載客狀態(tài)不同而不同,所以需要多段繪制雷激。一開始圖方便每兩個點就進行一次繪圖替蔬,但1700多個經緯度點就要繪圖1700多次,導致網頁非呈合荆卡頓承桥。后來優(yōu)化了一下,修改成每一段載客/空載進行一次繪圖根悼。
拖動條的樣式和代碼來自網絡凶异,具體也只是修改相應的回調函數蜀撑,可參考代碼。

完整代碼

注:感謝網絡上分享各組件代碼的網友剩彬,同時因為是建模過程中寫的酷麦,寫的很忙亂,很多地方寫的非常不美觀喉恋,僅供學習參考沃饶。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
    body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;font-family:"微軟雅黑";}
    </style>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的百度APIak碼"></script>
    <title>車輛運行軌跡測試</title>
<script src="http://c.#/core.php"></script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

<style>
            *{
                margin: 0;
                padding: 0;
            }
            .scroll{
                width: 400px;
                height: 8px;
                background-color: #ccc;
                margin: 10px;
                position: relative;
            }
            .bar{
                width: 10px;
                height: 22px;
                background-color: #369;
                position: absolute;
                top: -7px;
                left: 0;
                cursor: pointer;
            }
            .mask{
                width: 0;
                height: 100%;
                background-color: #336699;
                /*position: absolute;
                top: 0;
                left: 0;*/
            }
        </style>

</head>
<body>
    <input id='file' type="file" onchange="upload(this)" />
    <div class="scroll" id="scrollBar">
            <div class="bar"></div>
            <div class="mask"></div>
    </div>
    <div class="demo" id="demo"></div>
    <div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
    // 獲取元素
    var scrollBar = document.getElementById("scrollBar");
    var bar = scrollBar.children[0];
    var mask = scrollBar.children[1];
    var demo = document.getElementById("demo");
    // 拖動原理
    bar.onmousedown = function(event){
        var event = event || window.event;
        var leftVal = event.clientX - this.offsetLeft;
        // 拖動放到down的里面
        var that = this;
        var p = 0.0;
        document.onmousemove = function(event){
            var event = event || window.event;
            that.style.left = event.clientX - leftVal + "px";
            // 限制條件
            var val = parseInt(that.style.left);
            if(val < 0){
                that.style.left = 0;
            }else if(val > 390){
                that.style.left = "390px";
            }
            // 移動的距離為遮罩的寬度
            mask.style.width = that.style.left;
            // 顯示百分比
            p = parseInt(that.style.left) / 390;
            var hour = parseInt(p*24);
            var min = 24*60*p - hour*60;
            demo.innerHTML = "移動了:"+ parseInt(parseInt(that.style.left) / 390 * 100) + "%" +"約"+hour+":"+min;
            
            
            // 清除拖動 --- 防止鼠標已經彈起時還在拖動
            window.getSelection ? window.getSelection().removeAllRanges():document.selection.empty();
            map.clearOverlays();
            drawLines(arrData,p);
        }
        // 鼠標抬起停止拖動
        document.onmouseup = function(){
            document.onmousemove = null;
            //清空畫布
            map.clearOverlays(); 
            console.log("p:"+p)
            //根據比例繪圖
            drawLines(arrData,p);
        }
    }

    var arrData  = [];
    var linesPoints = null;
    // 百度地圖API功能
    var map = new BMap.Map("allmap");    // 創(chuàng)建Map實例
    map.centerAndZoom(new BMap.Point(121.487500,31.374500), 15);  // 初始化地圖,設置中心點坐標和地圖級別
    map.addControl(new BMap.MapTypeControl());   //添加地圖類型控件
    map.setCurrentCity("上海");          // 設置地圖顯示的城市 此項是必須設置的
    map.enableScrollWheelZoom(true);     //開啟鼠標滾輪縮放

   
   
   function drawGreenLine(startLong,startLat,endLong,endLat){
       var polyline = new BMap.Polyline([
                                          new BMap.Point(startLong,startLat),//起始點的經緯度
                                          new BMap.Point(endLong,endLat)//終止點的經緯度
                                          ], {strokeColor:"green",//設置顏色 
                                          strokeWeight:3, //寬度
                                          strokeOpacity:1});//透明度
       map.addOverlay(polyline);
   }
   
   function drawRedLine(){
       startLongR = endLongR;
       startLatR = endLatR;
       var polyline1 = new BMap.Polyline([
                                          new BMap.Point(startLongR,startLatR),//起始點的經緯度
                                          new BMap.Point(endLongR,endLatR)//終止點的經緯度
                                          ], {strokeColor:"red",//設置顏色 
                                          strokeWeight:3, //寬度
                                          strokeOpacity:1});//透明度
       map.addOverlay(polyline1);
   }
 

   
   function drawLines(arr,p){
        p = p || 1.0;
        var t = arr[0].split(",");
        var lastLong = t[2];
        var lastLat = t[3];
        var isFull = 0;
        var lastFull = 0;
        var temp = [];
        for(var i = 0 ; i < arr.length*p - 1; i=i+1){
            var a = arr[i].split(",");
            if(a[2]<120||a[2]>122||a[3]<30||a[3]>33)
                continue;
            
            if(a[6]!=lastFull || i == arr.length - 2){
                var c = "green";
                if (lastFull==1){
                    c = "red";
                }
                var polyline = new BMap.Polyline(temp, {strokeColor:c,
                                          strokeWeight:3, 
                                          strokeOpacity:1});
                map.addOverlay(polyline);
                temp = [];
                temp.push(new BMap.Point(lastLong,lastLat))
            }
            temp.push(new BMap.Point(a[2],a[3]));
            lastLong  = a[2];
            lastLat = a[3];
            lastFull = a[6];
        }
                                      
   }
   function upload(input) {
    //支持chrome IE10
    if (window.FileReader) {
        var file = input.files[0];
        console.log(file)
        filename = file.name.split(".")[0];
        var reader = new FileReader();
        reader.onload = function() {
            var arr = this.result.split("\n");
            arrData = arr;
            console.log(arr);
            map.clearOverlays(); 
            drawLines(arr);
        }
//      reader.readAsText(file,"UTF-8");
        reader.readAsText(file,"gb2312");
        
    }
    //支持IE 7 8 9 10
    else if (typeof window.ActiveXObject != 'undefined'){
        var xmlDoc;
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = false;
        xmlDoc.load(input.value);
        alert(xmlDoc.xml);
    }
    //支持FF
    else if (document.implementation && document.implementation.createDocument) {
        var xmlDoc;
        xmlDoc = document.implementation.createDocument("", "", null);
        xmlDoc.async = false;
        xmlDoc.load(input.value);
        alert(xmlDoc.xml);
    } else {
        alert('error');
    }
}
</script>

效果演示

1

2

如圖便為一個在機場排隊等待載客的典型選擇,其在6時左右載客到達機場瀑晒,并等待排隊約三小時后載客再度離開機場绍坝。


3
4

如圖為載客至機場后放棄排隊直接返回的典型選擇,司機在9時50分左右載客至機場后立刻空載返回苔悦,并于10時40分左右在市區(qū)周圍再次攬客載至其他地點轩褐。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市玖详,隨后出現的幾起案子把介,更是在濱河造成了極大的恐慌,老刑警劉巖蟋座,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拗踢,死亡現場離奇詭異,居然都是意外死亡向臀,警方通過查閱死者的電腦和手機巢墅,發(fā)現死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券膀,“玉大人君纫,你說我怎么就攤上這事∏郾颍” “怎么了蓄髓?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舒帮。 經常有香客問我会喝,道長,這世上最難降的妖魔是什么玩郊? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任肢执,我火速辦了婚禮,結果婚禮上瓦宜,老公的妹妹穿的比我還像新娘蔚万。我一直安慰自己,他們只是感情好临庇,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布反璃。 她就那樣靜靜地躺著昵慌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淮蜈。 梳的紋絲不亂的頭發(fā)上斋攀,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音梧田,去河邊找鬼淳蔼。 笑死,一個胖子當著我的面吹牛裁眯,可吹牛的內容都是我干的鹉梨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼穿稳,長吁一口氣:“原來是場噩夢啊……” “哼存皂!你這毒婦竟也來了?” 一聲冷哼從身側響起逢艘,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤旦袋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后它改,有當地人在樹林里發(fā)現了一具尸體疤孕,經...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年央拖,在試婚紗的時候發(fā)現自己被綠了祭阀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡鲜戒,死狀恐怖柬讨,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情袍啡,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布却桶,位于F島的核電站境输,受9級特大地震影響,放射性物質發(fā)生泄漏颖系。R本人自食惡果不足惜嗅剖,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘁扼。 院中可真熱鬧信粮,春花似錦、人聲如沸趁啸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至旅掂,卻和暖如春赏胚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背商虐。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工觉阅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秘车。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓典勇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叮趴。 傳聞我的和親對象是個殘疾皇子割笙,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容

  • 我的弟弟妹妹呀,是我從小欺負大的疫向,他們是那么的愛我咳蔚,而我也如此愛他們。 你說你會愛我么搔驼? 我知道我們不會再見谈火,所以...
    夢游世界閱讀 217評論 0 0
  • HTTP簡介 HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用...
    微笑的AK47閱讀 1,157評論 0 1
  • 打開華為運動健身軟件糯耍,今天是我啟用華為這部手機健身運動三周年,1095天沒給自己放一天假囊嘉,從大年初一至除夕温技,保持每...
    山東田夫閱讀 1,406評論 31 48