refactor chart shortcode to use static js instead

This commit is contained in:
Sam 2025-01-10 12:20:38 +00:00
parent eb6f97f54a
commit 9c12ccadc5
7 changed files with 234 additions and 280 deletions

View File

@ -18,6 +18,8 @@ The chart always reflects the countries selected in the table.
{{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="bitcoin-business-growth-chart bitcoin-business-growth-table" >}} {{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="bitcoin-business-growth-chart bitcoin-business-growth-table" >}}
{{< table id="bitcoin-business-growth-table" endpoint="bitcoin_business_growth_percent_diff" 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" targets="bitcoin-business-growth-chart" defaultFirstSelected="true" >}} {{< table id="bitcoin-business-growth-table" endpoint="bitcoin_business_growth_percent_diff" 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" targets="bitcoin-business-growth-chart" defaultFirstSelected="true" >}}
{{< chart id="bitcoin-business-growth-table" src="/js/bitcoin-business-growth-chart.js" >}}
{{< chart chartMethod="tableRowSelectChart" id="bitcoin-business-growth-chart" endpoint="bitcoin_business_growth_timeseries" chartType="line" xAxisField="date" yAxisField="cumulative_value" scaleChart=true xAxisType="category" >}} {{< chart chartMethod="tableRowSelectChart" id="bitcoin-business-growth-chart" endpoint="bitcoin_business_growth_timeseries" chartType="line" xAxisField="date" yAxisField="cumulative_value" scaleChart=true xAxisType="category" >}}
#### Attribution and License #### Attribution and License

View File

@ -13,4 +13,4 @@ The following chart shows daily miner revenue in USD for the period selected in
{{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="miner-rewards-chart" >}} {{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="miner-rewards-chart" >}}
{{< chart chartMethod="simpleChart" id="miner-rewards-chart" endpoint="miner_rewards" chartType="line" xAxisField="date" yAxisField="total_reward_usd" scaleChart=true xAxisType="category" >}} {{< chart id="miner-rewards" src="/js/miner-rewards.js" >}}

View File

@ -97,18 +97,19 @@
}); });
} }
chartData = [];
function simpleChart( function simpleChart(
id, id,
endpoint, endpoint,
chartType, chartType,
xAxisField, xAxisField,
yAxisField, yAxisField,
series,
sortField = null, sortField = null,
scaleChart = false, scaleChart = false,
xAxisType = "time", xAxisType = "time",
formatValueDecimalPlaces = null, formatValueDecimalPlaces = null,
) { ) {
console.log(series);
async function fetchDataForChart(query) { async function fetchDataForChart(query) {
try { try {
const apiEndpoint = `${apiURL}/${endpoint}?${query}`; const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
@ -145,12 +146,7 @@
scale: scaleChart, scale: scaleChart,
type: "value", type: "value",
}, },
series: [ series: JSON.parse(`{${series}}`),
{
data: chartData.map((item) => item.total_reward_usd),
type: "line",
},
],
}; };
myChart.setOption(option, true); myChart.setOption(option, true);

View File

@ -1,20 +1,7 @@
{{ partial "chart.html" }} <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.js"></script>
<section class = 'chart-container'> <section class = 'chart-container'>
<script>let id = '{{ .Get "id" }}'</script>
<div class = "chart" id='{{ .Get "id" }}'> <div class = "chart" id='{{ .Get "id" }}'>
<script> <script src={{ .Get "src" }}></script>
document.addEventListener("DOMContentLoaded", function () {
{{ .Get "chartMethod" | safeJS }}(
id={{ .Get "id" }},
endpoint={{ .Get "endpoint" }},
chartType={{ .Get "chartType" }},
xAxisField={{ .Get "xAxisField" }},
yAxisField={{ .Get "yAxisField" }},
sortField={{ .Get "sortField" }},
scaleChart={{ .Get "scaleChart" }},
xAxisType={{ .Get "xAxisType" }})
});
</script>
</div> </div>
</section> </section>

View File

@ -2,7 +2,7 @@
.chart-container { .chart-container {
display: flex; display: flex;
/* height: 600px; */ /* height: 600px; */
aspect-ratio: 1 / 1; aspect-ratio: 2 / 1;
} }
.chart { .chart {
@ -10,3 +10,12 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
@media (max-width: 600px) {
.chart-container {
display: flex;
/* height: 600px; */
aspect-ratio: 1 / 1;
}
}

View File

@ -1,25 +1,30 @@
let chartData = []; var chartDom = document.getElementById(id);
let myChart; var myChart = echarts.init(chartDom);
chartData = [];
let periodIndex = 3; function tableRowSelectChart(
endpoint,
const periods = ["1 day", "7 day", "28 day", "365 day"]; xAxisField,
yAxisField,
async function fetchDataForChart(str, period) { chartType,
xAxisType,
scaleChart = false,
formatValueDecimalPlaces = null,
) {
async function fetchDataForChart(query, valueId) {
try { try {
const apiEndpoint = `${apiURL}/bitcoin_business_growth_by_country?cumulative_period_type=${period}&countries=${str}`; const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
console.log("Fetching from " + apiEndpoint);
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const fetchedData = await response.json(); const fetchedData = await response.json();
console.log(fetchedData);
const newData = fetchedData.reduce((acc, item) => { const newData = fetchedData.reduce((acc, item) => {
const objectId = item.country_name; const objectId = item[valueId];
if (!acc[objectId]) { if (!acc[objectId]) {
acc[objectId] = []; acc[objectId] = [];
} }
acc[objectId].push([item.date, item.cumulative_current_value]); acc[objectId].push([item[xAxisField], item[yAxisField]]);
return acc; return acc;
}, {}); }, {});
chartData = { ...chartData, ...newData }; chartData = { ...chartData, ...newData };
@ -27,83 +32,71 @@ async function fetchDataForChart(str, period) {
} catch (error) { } catch (error) {
console.error("Fetching data failed:", error); console.error("Fetching data failed:", error);
} }
} }
function updateChart() { function updateChart() {
let chartDataMap = new Map(); let chartDataMap = new Map();
for (let objectId in chartData) { for (let objectId in chartData) {
chartDataMap.set(objectId, chartData[objectId]); chartDataMap.set(objectId, chartData[objectId]);
} }
option = {
backgroundColor: backgroundColor, var option = {
grid: grid, tooltip: {
tooltip: tooltip, ...tooltip,
toolbox: toolboxParams, valueFormatter(value, index) {
return formatValueDecimalPlaces == null
? value
: nFormatter(value, formatValueDecimalPlaces);
},
},
xAxis: { xAxis: {
axisTick: axisTick, type: xAxisType,
axisLabel: axisLabel,
axisLine: axisLine,
type: "category",
}, },
yAxis: { yAxis: {
axisTick: axisTick, scale: scaleChart,
scale: true, type: "value",
splitLine: {
show: false,
}, },
axisLabel: {
fontSize: 12 * fontScale,
color: textColor,
formatter(value, index) {
return nFormatter(value, 2);
},
},
axisLine: axisLine,
},
series: Array.from(chartDataMap.entries()).map(([name, data]) => ({ series: Array.from(chartDataMap.entries()).map(([name, data]) => ({
name, name,
type: "line", type: chartType,
data, data,
showSymbol: false, showSymbol: false,
})), })),
}; };
myChart.setOption(option, true); myChart.setOption(option, true);
}
function handleCheckboxChange(event) {
if (event.target.type === "checkbox") {
const boxChecked = event.target.checked;
const boxId = event.target.id;
let selectedPeriod = getPeriodFromDropdown();
// Remove unchecked boxes
if (boxChecked === false) {
delete chartData[boxId];
updateChart();
// Add checked boxes
} else {
fetchDataForChart(boxId, selectedPeriod);
} }
}
}
document.addEventListener("DOMContentLoaded", function () { // listen for filter events for this target
periodDropdown(periods, periodIndex); document.addEventListener("filterChange", function (event) {
document.addEventListener("reloadTable", () => { tableId = document.getElementById(id).id;
myChart = echarts.init(document.getElementById("chart")); console.log(event.detail);
jsonTableCheckedBoxes = document.querySelectorAll( eventDetail = event.detail;
'#jsonTableContainer input[type="checkbox"]:checked', if (eventDetail.filterActions.includes("refresh")) {
);
const checkedBoxes = Array.from(jsonTableCheckedBoxes).map(
(checkbox) => checkbox.id,
);
const str = checkedBoxes.join(",");
let selectedPeriod = getPeriodFromDropdown();
chartData = []; chartData = [];
fetchDataForChart(str, selectedPeriod); updateChart();
} else {
if (eventDetail.filterTargets.includes(tableId)) {
if (eventDetail.filterActions.includes("selected")) {
valueId = eventDetail.filterId;
let selectedRow = {
[valueId]: eventDetail.filterValue,
};
query = queryConstructor(selectedRow);
jsonTable = document.getElementById("jsonTableContainer"); fetchDataForChart(query, valueId);
jsonTable.removeEventListener("change", handleCheckboxChange); console.log(valueId)
jsonTable.addEventListener("change", handleCheckboxChange); } else {
delete chartData[eventDetail.filterValue];
updateChart();
}
}
}
}); });
}); }
tableRowSelectChart(
endpoint = "bitcoin_business_growth_timeseries",
xAxisField = "date",
yAxisField = "cumulative_value",
chartType = "line",
xAxisType = "category",
);

View File

@ -1,69 +1,39 @@
let dataArr = []; var chartDom = document.getElementById(id);
const myChart = echarts.init(document.getElementById("chart")); var myChart = echarts.init(chartDom);
const filename = "final__miner_rewards.json"; chartData = [];
const periods = [ function simpleChart(
"all time", endpoint,
"last 7 days", formatValueDecimalPlaces = null,
"last 28 days", ) {
"last 365 days", async function fetchDataForChart(query) {
"last 2 years",
];
async function fetchDataForChart(selectedValue) {
try { try {
const apiEndpoint = `${apiURL}/get_json/${filename}?period=${selectedValue}`; const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
const response = await fetch(apiEndpoint); const response = await fetch(apiEndpoint);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const dataArr = await response.json(); chartData = await response.json();
initEchart(dataArr); updateChart();
console.log(chartData);
} catch (error) { } catch (error) {
console.error("Fetching data failed:", error); console.error("Fetching data failed:", error);
} }
} }
function initEchart(dataArr) { function updateChart() {
console.log(dataArr); var option = {
const option = {
backgroundColor: backgroundColor,
tooltip: { tooltip: {
...tooltip, ...tooltip,
formatter: function (params) {
let colors = ["#ee6666", "#000000", "#b0da9d", "#8699d5"];
let colorSpan = (color) =>
'<span style="display:inline-block;margin-right:1px;border-radius:5px;width:9px;height:9px;background-color:' +
color +
'"></span>';
let tooltip = "<p>" + params[0].axisValue + "</p>";
params.reverse().forEach((item, index) => {
let color = colors[index % colors.length];
let labels =
"<p>" +
colorSpan(color) +
" " +
item.seriesName +
": " +
nFormatter(item.data, 3);
("</p>");
tooltip += labels;
});
return tooltip;
},
valueFormatter(value, index) { valueFormatter(value, index) {
return nFormatter(value, 3); return formatValueDecimalPlaces == null
? value
: nFormatter(value, formatValueDecimalPlaces);
}, },
}, },
toolbox: toolboxParams,
xAxis: { xAxis: {
data: dataArr.map((row) => row.date), type: "category",
axisTick: axisTick, data: chartData.map((item) => item.date),
axisLabel: axisLabel,
axisLine: axisLine,
}, },
grid: grid,
dataZoom: dataZoom(0),
yAxis: [ yAxis: [
{ {
type: "value", type: "value",
@ -117,7 +87,7 @@ function initEchart(dataArr) {
lineStyle: { lineStyle: {
width: 0, width: 0,
}, },
data: dataArr.map((row) => row.subsidy_usd), data: chartData.map((row) => row.subsidy_usd),
}, },
{ {
type: "line", type: "line",
@ -128,7 +98,7 @@ function initEchart(dataArr) {
lineStyle: { lineStyle: {
width: 0, width: 0,
}, },
data: dataArr.map((row) => row.totalfee_usd), data: chartData.map((row) => row.totalfee_usd),
}, },
{ {
type: "line", type: "line",
@ -138,7 +108,7 @@ function initEchart(dataArr) {
width: 1, width: 1,
color: textColor, color: textColor,
}, },
data: dataArr.map((row) => row.total_reward_usd), data: chartData.map((row) => row.total_reward_usd),
}, },
{ {
type: "line", type: "line",
@ -148,22 +118,19 @@ function initEchart(dataArr) {
lineStyle: { lineStyle: {
width: 3, width: 3,
}, },
data: dataArr.map((row) => row.block_subsidy), data: chartData.map((row) => row.block_subsidy),
}, },
], ],
}; };
myChart.setOption(option); myChart.setOption(option, true);
} }
document.addEventListener("DOMContentLoaded", function () { query = queryConstructor();
let periodIndex = 2; fetchDataForChart(query);
periodDropdown(periods, periodIndex); document.addEventListener("filterChange", function (event) {
fetchDataForChart(periods[periodIndex]); query = queryConstructor();
const selectElement = document.getElementById("select-period-dropdown"); fetchDataForChart(query);
selectElement.addEventListener("change", function (event) {
const selectedValue = event.target.value;
fetchDataForChart(selectedValue);
}); });
}); }
simpleChart((endpoint = "miner_rewards"));