Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for KML #2

Merged
merged 2 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
build/
node_modules/
pages/
scratch.html
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# BMLT Data Converter

* Converts BMLT meeting data from a JSON endpoint to CSV
* Converts BMLT meeting data from a JSON endpoint to CSV or KML
* Note that export of KML is only supported with GetSearchResults.
160 changes: 145 additions & 15 deletions assets/js/main.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
function fetchMeetings(query, callback) {
let isProcessingCSV = false;
let isProcessingKML = false;

const fetchMeetings = (query, callback, isCSV, isKML) => {
const script = document.createElement("script");
script.src = query + "&callback=" + callback.name;
script.src = `${query}&callback=${callback.name}`;
document.body.appendChild(script);
}
isProcessingCSV = isCSV;
isProcessingKML = isKML;
};

const handleMeetingsData = (meetings) => {
if (isProcessingCSV) {
const csvContent = `data:text/csv;charset=utf-8,${encodeURIComponent(
convertToCSV(meetings)
)}`;
const downloadLink = document.getElementById("downloadLink");
downloadLink.href = csvContent;
downloadLink.style.display = "block";
}

function handleMeetingsData(meetings) {
const csvContent =
"data:text/csv;charset=utf-8," + encodeURIComponent(convertToCSV(meetings));
const downloadLink = document.getElementById("downloadLink");
downloadLink.href = csvContent;
downloadLink.style.display = "block";
}
if (isProcessingKML) {
const kmlContent = `data:text/xml;charset=utf-8,${encodeURIComponent(
convertToKML(meetings)
)}`;
const kmlDownloadLink = document.getElementById("kmlDownloadLink");
kmlDownloadLink.href = kmlContent;
kmlDownloadLink.style.display = "block";
}
};

function convertToCSV(data) {
const convertToCSV = (data) => {
const csvRows = [];
const keys = Object.keys(data[0]);

Expand All @@ -35,14 +52,127 @@ function convertToCSV(data) {
});

return csvRows.join("\n");
}
};

const convertToKML = (data) => {
const kmlHeader = `
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
`;

const kmlFooter = `
</Document>
</kml>`;

const placemarks = data.map((meeting) => {
const name = meeting["meeting_name"].trim() || "NA Meeting";
const lng = parseFloat(meeting["longitude"]);
const lat = parseFloat(meeting["latitude"]);

function exportToCSV() {
if (lng || lat) {
const description = prepareSimpleLine(meeting);
const address = prepareSimpleLine(meeting, false);

return (
` <Placemark>\n` +
` <name>${name}</name>\n` +
(address ? ` <address>${address}</address>\n` : "") +
(description
? ` <description>${description}</description>\n`
: "") +
` <Point>\n` +
` <coordinates>${lng},${lat}</coordinates>\n` +
` </Point>\n` +
` </Placemark>\n`
);
}
});

return kmlHeader + placemarks.join("\n") + kmlFooter;
};

const exportData = () => {
const query = document.getElementById("query").value;
if (!query.includes("/client_interface/jsonp")) {
alert("Invalid BMLT query URL, must use jsonp endpoint.");
return;
}
// Only support GetSearchResults for KML
const isKML = query.includes("GetSearchResults");
fetchMeetings(query, handleMeetingsData, true, isKML);
if (isKML) {
fetchMeetings(query, handleMeetingsData, true, true);
}
};

const prepareSimpleLine = (meeting, withDate = true) => {
const getLocationInfo = () => {
const locationInfo = [];
const addInfo = (property) => {
if (property in meeting) {
const value = meeting[property].trim();
if (value) {
locationInfo.push(value);
}
}
};

addInfo("location_text");
addInfo("location_street");
addInfo("location_city_subsection");
addInfo("location_municipality");
addInfo("location_neighborhood");
addInfo("location_province");
addInfo("location_postal_code_1");
addInfo("location_nation");
addInfo("location_info");

return locationInfo.join(", ");
};

const getDateString = () => {
const weekday_strings = [
"All",
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const weekday = parseInt(meeting["weekday_tinyint"].trim());
const weekdayString = weekday_strings[weekday];

const startTime = `2000-01-01 ${meeting["start_time"]}`;
const time = new Date(startTime);

if (weekdayString && withDate) {
let dateString = weekdayString;

fetchMeetings(query, handleMeetingsData);
}
if (!isNaN(time)) {
dateString += `, ${time.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true,
})}`;
}

return dateString;
}

return "";
};

const locationInfo = getLocationInfo();
const dateString = getDateString();

if (withDate && dateString && locationInfo) {
return `${dateString}, ${locationInfo}`;
} else if (dateString) {
return dateString;
} else {
return locationInfo;
}
};
10 changes: 5 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<!DOCTYPE HTML>
<html>
<head>
<title>BMLT CSV Export</title>
<title>BMLT Data Converter</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body>
<h1>BMLT CSV Export</h1>
<h1>BMLT Data Converter</h1>
<div id="export-form">
<label for="query">BMLT URL Query:</label>
<input type="text" id="query" required>
<br>
<button onclick="exportToCSV()">Export CSV</button>
<button onclick="exportData()">Generate Export Data</button>
<a id="downloadLink" style="display: none;" download="BMLT_data.csv">Download CSV</a>
<a id="kmlDownloadLink" style="display: none;" download="BMLT_data.kml">Download KML</a>
</div>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
</html>
Loading