123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- const options = {
- legend: {
- position: "nw",
- show: true,
- noColumns: 2,
- },
- zoom: {
- interactive: true
- },
- pan: {
- interactive: true,
- cursor: "move",
- frameRate: 60
- },
- series: {
- lines: {
- show: true,
- lineWidth: 2
- }
- },
- xaxis: {
- tickDecimals: 2,
- tickSize: 0.01
- },
- yaxis: {
- tickDecimals: 2,
- tickSize: 0.01
- }
- }
- window.onload = function() {
- const fileSelector = document.getElementById('file-selector')
- fileSelector.addEventListener('change', (event) => {
- const fileList = event.target.files;
- console.log(fileList);
- importFiles(fileList)
- })
- const dropArea = document.getElementsByClassName('content')[0];
- dropArea.addEventListener('dragover', (event) => {
- event.stopPropagation();
- event.preventDefault();
- // Style the drag-and-drop as a "copy file" operation.
- event.dataTransfer.dropEffect = 'copy';
- });
- dropArea.addEventListener('drop', (event) => {
- event.stopPropagation();
- event.preventDefault();
- const fileList = event.dataTransfer.files;
- console.log(fileList);
- importFiles(fileList)
- });
- }
- function importFiles(fileList) {
- d = []
- plot = $.plot("#placeholder", d, options);
- for (const file of fileList) {
- if(file.name?.toLowerCase().endsWith(".txt"))
- readTxtFile(file)
- else if (file.name?.toLowerCase().endsWith(".nmea"))
- parseNmeaFile(file)
- }
- }
- function readTxtFile(file) {
- const reader = new FileReader()
- reader.addEventListener('load', (event) => {
- const lines = event.target.result.split('\n')
- let result = []
- for(const line of lines) {
- const fields = line.split(',')
- if(fields.length != 8)
- continue
-
- result.push({
- timestamp: fields[0],
- lat: parseFloat(fields[1]),
- lng: parseFloat(fields[2]),
- alt: parseFloat(fields[3]),
- hdop: parseInt(fields[4]),
- speed: parseInt(fields[5])
- })
- }
- process(file.name, result)
- });
- reader.readAsText(file)
- }
- function parseNmeaFile(file) {
- const reader = new FileReader()
- reader.addEventListener('load', (event) => {
- const lines = event.target.result.split('\n')
- let result = []
- let ggaObj, oldTime;
-
- for(const line of lines) {
- const obj = GPS.Parse(line);
- if (obj.type == "RMC") {
- if(ggaObj.time != oldTime) {
- oldTime = ggaObj.time
- result.push({
- timestamp: ggaObj.time,
- lat: ggaObj.lat,
- lng: ggaObj.lon,
- alt: ggaObj.alt,
- hdop: ggaObj.hdop,
- speed: obj.speed
- })
- }
- ggaObj = null
- } else if(ggaObj) {
- if(ggaObj.time != oldTime) {
- oldTime = ggaObj.time
- result.push({
- timestamp: ggaObj.time,
- lat: ggaObj.lat,
- lng: ggaObj.lon,
- alt: ggaObj.alt,
- hdop: ggaObj.hdop,
- speed: null
- })
- }
- ggaObj = null
- }
- if(obj.type == "GGA") {
- ggaObj = obj;
- }
- }
- process(file.name, result)
- });
- reader.readAsText(file)
- }
- function process(name, markers) {
- d.push({
- label: `${name} ${markers.length}`,
- data: markers.map(m => [m.lat, m.lng])
- })
- markers = RamerDouglasPeucker2d(markers, 0.00001) //.0001 = 7m
- d.push({
- label: `RamerDouglasPeucker2d ${markers.length}`,
- data: markers.map(m => [m.lat, m.lng])
- })
- plot.setData(d);
- plot.setupGrid(); //only necessary if your new data will change the axes or grid
- plot.draw();
- }
- function perpendicularDistance2d(ptX, ptY, l1x, l1y, l2x, l2y) {
- if (l2x == l1x)
- {
- //vertical lines - treat this case specially to avoid dividing
- //by zero
- return Math.abs(ptX - l2x);
- }
- else
- {
- const slope = ((l2y-l1y) / (l2x-l1x));
- const passThroughY = (0-l1x)*slope + l1y;
- return (Math.abs((slope * ptX) - ptY + passThroughY)) /
- (Math.sqrt(slope*slope + 1));
- }
- }
- function RamerDouglasPeucker2d(pointList, epsilon) {
- if (pointList.length < 2)
- {
- return pointList;
- }
- // Find the point with the maximum distance
- let dmax = 0;
- let index = 0;
- let totalPoints = pointList.length;
- for (let i = 1; i < (totalPoints - 1); i++)
- {
- let d = perpendicularDistance2d(
- pointList[i].lat, pointList[i].lng,
- pointList[0].lat, pointList[0].lng,
- pointList[totalPoints-1].lat,
- pointList[totalPoints-1].lng);
- if (d > dmax)
- {
- index = i;
- dmax = d;
- }
- }
-
- // If max distance is greater than epsilon, recursively simplify
- if (dmax >= epsilon)
- {
- // Recursive call on each 'half' of the polyline
- const recResults1 = RamerDouglasPeucker2d(pointList.slice(0, index + 1), epsilon);
- const recResults2 = RamerDouglasPeucker2d(pointList.slice(index), epsilon);
- // Build the result list
- return recResults1.slice(0, recResults1.length - 1).concat(recResults2);
- }
- else
- {
- return [pointList[0], pointList[totalPoints-1]];
- }
- }
|