function createTable( endpoint, tableId, headers, maxHeight, sortable, valueId, selectableRows, filterTargets, defaultFirstSelected, ) { async function fetchDataForTable(query) { try { const apiEndpoint = `${apiURL}/${endpoint}?${query}`; const response = await fetch(apiEndpoint); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const fetchedData = await response.json(); data = fetchedData; generateTable(data); } catch (error) { console.error("Fetching data failed:", error); } } function generateTable(data) { const jsonTableContainer = document.getElementById(`${tableId}-container`); jsonTableContainer.className = "jsonTableContainer"; jsonTableContainer.innerHTML = ""; jsonTableContainer.style.maxHeight = maxHeight; tableHeaderNames = Object.values(headers); tableHeaderKeys = Object.keys(headers); const table = document.createElement("table"); table.id = tableId; const thead = document.createElement("thead"); const tbody = document.createElement("tbody"); const headerRow = document.createElement("tr"); tableHeaderNames.forEach((header) => { const th = document.createElement("th"); th.textContent = header; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); for (const key in data) { const row = document.createElement("tr"); row.value = data[key][valueId]; tableHeaderKeys.forEach((columnName) => { const td = document.createElement("td"); const div = document.createElement("div"); div.id = "scrollable"; div.textContent = data[key][columnName]; td.appendChild(div); row.appendChild(td); tbody.appendChild(row); }); } table.appendChild(thead); table.appendChild(tbody); jsonTableContainer.appendChild(table); if (sortable == true) { table.className = "sortable"; sorttable.makeSortable(document.getElementById(tableId)); } if (selectableRows === "multi" || selectableRows === "single") { const rows = table.getElementsByTagName("tr"); for (let i = 1; i < rows.length; i++) { rows[i].addEventListener("click", function() { if (selectableRows === "multi") { this.classList.toggle("selected"); if (this.classList.contains("selected")) { const event = new CustomEvent("filterChange", { detail: { filterId: valueId, filterValue: this.value, filterActions: ["selected"], filterTargets: filterTargets, }, }); document.dispatchEvent(event); } else { const event = new CustomEvent("filterChange", { detail: { filterId: valueId, filterValue: this.value, filterActions: ["deselected"], filterTargets: filterTargets, }, }); document.dispatchEvent(event); } } else if (selectableRows === "single") { const event = new CustomEvent("filterChange", { detail: { filterId: valueId, filterValue: this.value, filterActions: ["selected"], filterTargets: filterTargets, }, }); document.dispatchEvent(event); if (this.classList.contains("selected")) { this.classList.remove("selected"); } else { for (let j = 1; j < rows.length; j++) { rows[j].classList.remove("selected"); } this.classList.add("selected"); } } }); if (defaultFirstSelected == true) { if (i == 1) { rows[i].classList.add("selected"); const event = new CustomEvent("filterChange", { detail: { filterId: valueId, filterValue: rows[i].value, filterActions: ["selected"], filterTargets: filterTargets, }, }); document.dispatchEvent(event); } } } } } document.addEventListener("filterChange", function(event) { tableId = document.getElementById(tableId).id; if (event.detail.filterTargets.includes(tableId)) { query = queryConstructor(); fetchDataForTable(query); } }); let query = queryConstructor(); fetchDataForTable(query); } function createChart( chart, chatId, endpoint, xAxisField, yAxisField, chartType, xAxisType, scaleChart = false, formatValueDecimalPlaces = null, ) { async function fetchDataForChart(query, valueId) { try { const apiEndpoint = `${apiURL}/${endpoint}?${query}`; const response = await fetch(apiEndpoint); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const fetchedData = await response.json(); const newData = fetchedData.reduce((acc, item) => { const objectId = item[valueId]; if (!acc[objectId]) { acc[objectId] = []; } acc[objectId].push([item[xAxisField], item[yAxisField]]); return acc; }, {}); chartData = { ...chartData, ...newData }; updateChart(); } catch (error) { console.error("Fetching data failed:", error); } } function updateChart() { let chartDataMap = new Map(); for (let objectId in chartData) { chartDataMap.set(objectId, chartData[objectId]); } var option = { tooltip: { ...tooltip, valueFormatter(value, index) { return formatValueDecimalPlaces == null ? value : nFormatter(value, formatValueDecimalPlaces); }, }, xAxis: { type: xAxisType, }, yAxis: { scale: scaleChart, type: "value", }, series: Array.from(chartDataMap.entries()).map(([name, data]) => ({ name, type: chartType, data, showSymbol: false, })), }; chart.setOption(option, true); } // listen for filter events for this target document.addEventListener("filterChange", function(event) { eventDetail = event.detail; if (eventDetail.filterActions.includes("refresh")) { chartData = []; updateChart(); } else { if (eventDetail.filterTargets.includes(chatId)) { if (eventDetail.filterActions.includes("selected")) { valueId = eventDetail.filterId; let selectedRow = { [valueId]: eventDetail.filterValue, }; query = queryConstructor(selectedRow); fetchDataForChart(query, valueId); } else { delete chartData[eventDetail.filterValue]; updateChart(); } } } }); } document.addEventListener("DOMContentLoaded", function() { chartData = []; let chartDom = document.getElementById("bitcoin-business-growth-chart"); let myChart = echarts.init(chartDom); const filterPeriods = {"7 day": 7, "28 day": 28, "365 day": 365, "2 years": 730, "5 years": 1826, "10 years": 3652, "all time": 10000}; dropDownFilter("days_ago_dropdown_filter", "days_ago", ["bitcoin-business-growth-chart", "bitcoin-business-growth-table"], filterPeriods, "365 day") createTable( endpoint = "bitcoin_business_growth_percent_diff", tableId = "bitcoin-business-growth-table", headers = { 'country_name': 'Country', 'date_range': 'Date Range', 'first_value': 'Previous #', 'last_value': 'Current #', 'difference': 'Diff', 'percent_difference': '% Diff' }, maxHeight = "400px", sortable = true, valueId = "country_name", selectableRows = "multi", filterTargets = "bitcoin-business-growth-chart", defaultFirstSelected = true ) createChart( chart = myChart, chartId = "bitcoin-business-growth-chart", endpoint = "bitcoin_business_growth_timeseries", xAxisField = "date", yAxisField = "cumulative_value", chartType = "line", xAxisType = "category", ); });