公司有個需求須要實時繪製掃地機的清潔路徑,可是上報的點幾千個後,svg繪製就會很卡,決定使用抽稀算法減小些定位點,優化性能。算法
util.js數組
// 計算兩點間距離 export const calculationDistance = (point1, point2) => { const x1 = point1.x; const y1 = point1.y; const x2 = point2.x; const y2 = point2.y; const xy = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); return xy; }; // 計算點pX到點pA和pB所肯定的直線的距離 export const distToSegment = (start, end, center) => { const a = Math.abs(calculationDistance(start, end)); const b = Math.abs(calculationDistance(start, center)); const c = Math.abs(calculationDistance(end, center)); const p = (a + b + c) / 2.0; const s = Math.sqrt(Math.abs(p * (p - a) * (p - b) * (p - c))); return s * 2.0 / a; }; // 遞歸方式壓縮軌跡 export const compressLine = (coordinate, result, start, end, dMax) => { if (start < end) { let maxDist = 0; let currentIndex = 0; const startPoint = coordinate[start]; const endPoint = coordinate[end]; for (let i = start + 1; i < end; i++) { const currentDist = distToSegment(startPoint, endPoint, coordinate[i]); if (currentDist > maxDist) { maxDist = currentDist; currentIndex = i; } } if (maxDist >= dMax) { // 將當前點加入到過濾數組中 // console.warn(maxDist); result.push(coordinate[currentIndex]); // 將原來的線段以當前點爲中心拆成兩段,分別進行遞歸處理 compressLine(coordinate, result, start, currentIndex, dMax); compressLine(coordinate, result, currentIndex, end, dMax); } } return result; }; export const douglasPeucker = (coordinate, dMax = 10) => { if (!coordinate || !(coordinate.length > 2)) { return null; } coordinate.forEach((item, index) => { item.id = index; }); const result = compressLine(coordinate, [], 0, coordinate.length - 1, dMax); result.push(coordinate[0]); result.push(coordinate[coordinate.length - 1]); const resultLatLng = result.sort((a, b) => { if (a.id < b.id) { return -1; } else if (a.id > b.id) return 1; return 0; }); resultLatLng.forEach((item) => { item.id = undefined; }); return resultLatLng; };
datas= douglasPeucker(newData,10);
優化前svg
優化後性能