|
36 | 36 | }
|
37 | 37 | </style>
|
38 | 38 | <div id="head">
|
39 |
| - <h1>car-location</h1> |
40 | 39 | <form id="searchForm">
|
41 | 40 | <label for="apiKey">ApiKey:</label>
|
42 | 41 | <input id="apiKey" type="text" value="0XlwMJm8U42KEZ394N4p8hm2p=s=" />
|
|
72 | 71 | function getDoubleDigit(number){
|
73 | 72 | return number < 10 ? ('0' + number) : number;
|
74 | 73 | }
|
75 |
| - function calcVelocity(pointStart, pointEnd){ |
| 74 | + function calcVelocityAndDistance(pointStart, pointEnd){ |
76 | 75 | var timeCost = new Date(pointEnd.at) - new Date(pointStart.at);
|
77 | 76 | var distance = GPS.distance(pointStart.value.lat, pointStart.value.lon, pointEnd.value.lat, pointEnd.value.lon);
|
78 |
| - return distance / timeCost; |
| 77 | + return {distance: distance, velocity: distance / timeCost}; |
| 78 | + } |
| 79 | + function calcDistanceOfPoints(points){ |
| 80 | + if(points.length < 2){ |
| 81 | + return 0; |
| 82 | + } |
| 83 | + let pointStart = points[0], pointEnd = points[points.length - 1]; |
| 84 | + return GPS.distance(pointStart.lat, pointStart.lng, pointEnd.lat, pointEnd.lng); |
79 | 85 | }
|
80 | 86 | function getVelocityGroup(velocity){ //计算单位为米/微秒
|
81 | 87 | /*
|
|
102 | 108 | 30: '#f3ed49',
|
103 | 109 | 100: '#4fd27d',
|
104 | 110 | }
|
| 111 | + function splitDatapointsByTime(dataPoints){ |
| 112 | + let splitedPoints = []; |
| 113 | + let tempPoints = [dataPoints[0]]; |
| 114 | + for(let i = 1; i < dataPoints.length; i++){ |
| 115 | + if(new Date(dataPoints[i].at) - new Date(dataPoints[i - 1].at) > 600000){ //10分钟 |
| 116 | + splitedPoints.push(tempPoints); |
| 117 | + tempPoints = [dataPoints[i]]; |
| 118 | + }else{ |
| 119 | + tempPoints.push(dataPoints[i]); |
| 120 | + } |
| 121 | + } |
| 122 | + splitedPoints.push(tempPoints); //最后一组 |
| 123 | + return splitedPoints; |
| 124 | + } |
105 | 125 | function splitDatapointsByVelocity(dataPoints){
|
106 | 126 | let splitedPoints = [];
|
107 | 127 | splitedPoints.count = dataPoints.length;
|
108 | 128 | splitedPoints.startTime = dataPoints[0].at;
|
109 | 129 | splitedPoints.endTime = dataPoints[dataPoints.length - 1].at;
|
110 |
| - let currentVelocityGroup, |
111 |
| - previousVelocityGroup = getVelocityGroup(calcVelocity(dataPoints[0], dataPoints[1])), |
| 130 | + let currentVelocityGroup, |
| 131 | + currentPointsCost = calcVelocityAndDistance(dataPoints[0], dataPoints[1]); |
| 132 | + previousVelocityGroup = getVelocityGroup(currentPointsCost.velocity), |
| 133 | + reallyDistance = currentPointsCost.distance, |
| 134 | + airDistance = reallyDistance, |
| 135 | + currentStartPoint = dataPoints[0], |
112 | 136 | tempPoints = {
|
113 |
| - points: [getBMapPoint(dataPoints[0].value)], |
| 137 | + points: [getBMapPoint(dataPoints[0].value), getBMapPoint(dataPoints[1].value)], |
114 | 138 | velocityGroup: previousVelocityGroup
|
115 | 139 | };
|
116 | 140 | splitedPoints.push(tempPoints);
|
117 |
| - for(let i = 1; i < dataPoints.length - 1; i++){ |
118 |
| - currentVelocityGroup = getVelocityGroup(calcVelocity(dataPoints[i], dataPoints[i + 1])); |
| 141 | + //根据速度分组并只保留长直线的端点 |
| 142 | + for(let i = 2; i < dataPoints.length - 1; i++){ |
| 143 | + currentPointsCost = calcVelocityAndDistance(dataPoints[i - 1], dataPoints[i]); |
| 144 | + reallyDistance += currentPointsCost.distance; //实际距离 |
| 145 | + airDistance = GPS.distance(currentStartPoint.value.lat, currentStartPoint.value.lon, dataPoints[i].value.lat, dataPoints[i].value.lon); //航空距离 |
| 146 | + currentVelocityGroup = getVelocityGroup(currentPointsCost.velocity); |
119 | 147 | if(currentVelocityGroup == previousVelocityGroup){ //当前两个点的速度和前两个点的速度属于同一个组
|
| 148 | + if(reallyDistance - airDistance < 1){ |
| 149 | + tempPoints.points.length = tempPoints.points.length - 1; |
| 150 | + } |
120 | 151 | tempPoints.points.push(getBMapPoint(dataPoints[i].value));
|
121 | 152 | }else{
|
122 | 153 | tempPoints = {
|
123 | 154 | points: [getBMapPoint(dataPoints[i-1].value), getBMapPoint(dataPoints[i].value)],
|
124 | 155 | velocityGroup: currentVelocityGroup
|
125 | 156 | };
|
| 157 | + currentStartPoint = dataPoints[i - 1]; |
| 158 | + reallyDistance = currentPointsCost.distance; |
126 | 159 | splitedPoints.push(tempPoints);
|
127 | 160 | }
|
128 | 161 | previousVelocityGroup = currentVelocityGroup;
|
129 | 162 | }
|
130 |
| - return splitedPoints; |
| 163 | + //去掉毛刺点 TODO: 目前算法会把长直线与周边合并掉,因为长直线的点数量小于10 |
| 164 | + let concatedPoints = [splitedPoints[0]]; |
| 165 | + let j; |
| 166 | + for(j = 1; j < splitedPoints.length - 1; j++){ |
| 167 | + //console.log(splitedPoints[i].velocityGroup,concatedPoints[concatedPoints.length-1].velocityGroup,splitedPoints[i+1].velocityGroup); |
| 168 | + //console.log('端点距离:',calcDistanceOfPoints(splitedPoints[j].points)); |
| 169 | + if(splitedPoints[j].points.length < 10 && calcDistanceOfPoints(splitedPoints[j].points) < 50 && concatedPoints[concatedPoints.length-1].velocityGroup == splitedPoints[j+1].velocityGroup){ |
| 170 | + //console.log('等于:' ,concatedPoints[concatedPoints.length - 1].points,splitedPoints[i].points) |
| 171 | + concatedPoints[concatedPoints.length - 1].points = concatedPoints[concatedPoints.length - 1].points.concat(splitedPoints[j].points).concat(splitedPoints[j+1].points); |
| 172 | + ++j; |
| 173 | + //splitedPoints[i].points.length = 0; |
| 174 | + //splitedPoints[i] = null; |
| 175 | + }else{ |
| 176 | + concatedPoints.push(splitedPoints[j]); |
| 177 | + } |
| 178 | + } |
| 179 | + if(j < splitedPoints.length){ //倒数第二段不是毛刺的时候,j只能到length-1,这个时候需要把最后一项加进concatedPoints |
| 180 | + concatedPoints.push(splitedPoints[splitedPoints.length - 1]); |
| 181 | + } |
| 182 | + concatedPoints.startTime = splitedPoints.startTime; |
| 183 | + concatedPoints.endTime = splitedPoints.endTime; |
| 184 | + return concatedPoints; |
131 | 185 | }
|
| 186 | + function convertPoints(points){ |
| 187 | + var pointsGroupByTime = splitDatapointsByTime(points); |
| 188 | + pointsGroupByTime = pointsGroupByTime.map(pointsGroup => splitDatapointsByVelocity(pointsGroup)); |
| 189 | + pointsGroupByTime.count = points.length; |
| 190 | + return pointsGroupByTime; |
| 191 | + }; |
132 | 192 | function getBMapPoint(point){
|
133 | 193 | var bdGps = GPS.GPSToBaidu(point.lat, point.lon);
|
134 | 194 | return new BMap.Point(bdGps.lng, bdGps.lat);
|
|
164 | 224 | var _this = this;
|
165 | 225 | this._api.getDataPoints(deviceId, {datastream_id:'Gps', start: this.start, end: this.end, limit: $pointCount.value}).then(function(res){
|
166 | 226 | console.log('api调用完成,服务器返回data为:', res);
|
167 |
| - $log.innerHTML = '当前第1页,本次共渲染' + res.data.count + '个点'; |
168 | 227 | if(res.data.cursor){ //加入第二页的corsor
|
169 | 228 | _this.cursorListOfPageIndex[1] = res.data.cursor;
|
170 |
| - } |
171 |
| - var splitedPoints = splitDatapointsByVelocity(res.data.datastreams[0].datapoints); |
| 229 | + } |
| 230 | + var splitedPoints = convertPoints(res.data.datastreams[0].datapoints); |
| 231 | + $log.innerHTML = '当前第1页,本次共渲染' + splitedPoints.count + '个点'; |
172 | 232 | pageControl.baiduMap.resetMarker(splitedPoints);
|
173 | 233 | _this.pointsCache[1] = splitedPoints;
|
174 | 234 | });
|
|
190 | 250 | if(res.data.cursor){ //加入下一页的corsor
|
191 | 251 | _this.cursorListOfPageIndex[pageIndex + 1] = res.data.cursor;
|
192 | 252 | }
|
193 |
| - var splitedPoints = splitDatapointsByVelocity(res.data.datastreams[0].datapoints); |
| 253 | + //var pointsTimeGroup = splitDatapointsByTime(res.data.datastreams[0].datapoints); |
| 254 | + var splitedPoints = convertPoints(res.data.datastreams[0].datapoints); |
194 | 255 | pageControl.baiduMap.resetMarker(splitedPoints);
|
195 | 256 | _this.pointsCache[cursor] = splitedPoints;
|
196 | 257 | $log.innerHTML = '当前第' + (pageIndex + 1) + '页,本次共渲染' + splitedPoints.count + '个点';
|
|
277 | 338 | resetMarker: function(splitedPoints){
|
278 | 339 | this.map.clearOverlays();
|
279 | 340 | var _this = this;
|
280 |
| - splitedPoints.forEach(item => { |
| 341 | + var edgePoints = []; |
| 342 | + splitedPoints.forEach(pointsGroup => { |
| 343 | + edgePoints = edgePoints.concat(_this.drawGroup(pointsGroup)); |
| 344 | + }); |
| 345 | + this.map.setViewport(edgePoints); |
| 346 | + }, |
| 347 | + drawGroup: function(pointsGroup){ |
| 348 | + var _this = this; |
| 349 | + var count = 0; |
| 350 | + pointsGroup.forEach(item => { |
281 | 351 | _this.drawLine(item.points, VelocityGroupColor[item.velocityGroup]);
|
282 | 352 | });
|
283 | 353 | //加入marker
|
284 | 354 | var iconStart = new BMap.Icon('/resource/2019/markers_bg.png', new BMap.Size(25,40), {
|
285 | 355 | imageSize: new BMap.Size(50, 40),
|
286 | 356 | anchor: new BMap.Size(12, 40)
|
287 | 357 | });
|
288 |
| - var markerStart = new BMap.Marker(splitedPoints[0].points[0], {icon:iconStart}); |
| 358 | + var markerStart = new BMap.Marker(pointsGroup[0].points[0], {icon:iconStart}); |
289 | 359 | var iconEnd = new BMap.Icon('/resource/2019/markers_bg.png', new BMap.Size(25,40), {
|
290 | 360 | imageOffset: new BMap.Size(-25,0),
|
291 | 361 | imageSize: new BMap.Size(50, 40),
|
292 | 362 | anchor: new BMap.Size(12, 40)
|
293 | 363 | });
|
294 |
| - var endPoints = splitedPoints[splitedPoints.length - 1].points; |
| 364 | + var endPoints = pointsGroup[pointsGroup.length - 1].points; |
295 | 365 | var markerEnd = new BMap.Marker(endPoints[endPoints.length - 1], {icon:iconEnd});
|
296 |
| - markerStart.setLabel(new BMap.Label(splitedPoints.startTime, {offset: new BMap.Size(-20,-20)})); |
297 |
| - markerEnd.setLabel(new BMap.Label(splitedPoints.endTime, {offset: new BMap.Size(-20,-20)})); |
| 366 | + markerStart.setLabel(new BMap.Label(pointsGroup.startTime, {offset: new BMap.Size(-20,-20)})); |
| 367 | + markerEnd.setLabel(new BMap.Label(pointsGroup.endTime, {offset: new BMap.Size(-20,-20)})); |
298 | 368 | this.map.addOverlay(markerStart);
|
299 | 369 | this.map.addOverlay(markerEnd);
|
300 |
| - this.map.setViewport([splitedPoints[0].points[0], endPoints[endPoints.length - 1]]); |
| 370 | + return [pointsGroup[0].points[0], endPoints[endPoints.length - 1]]; |
301 | 371 | },
|
302 | 372 | drawLine: function(pointsArr, color){
|
303 | 373 | var sy = new BMap.Symbol(BMap_Symbol_SHAPE_BACKWARD_OPEN_ARROW, {
|
|
0 commit comments