generated from nathanwoodburn/python-webserver-template
feat: Add new api routes and updated chart
All checks were successful
Build Docker / BuildImage (push) Successful in 34s
All checks were successful
Build Docker / BuildImage (push) Successful in 34s
This commit is contained in:
@@ -47,68 +47,178 @@
|
||||
</header>
|
||||
<section style="margin-top: 50px;margin-bottom: 50px;max-width: 100vw;overflow: hidden;">
|
||||
<div class="text-center">
|
||||
<h1>Current Vault Contents</h1>
|
||||
<h1 data-bs-toggle="tooltip" data-bss-tooltip="" id="chart-header" title="Toggle per token view" style="border-bottom: 5px dashed var(--bs-body-color);width: fit-content;margin: auto;margin-bottom: 20px;">Current Vault Contents</h1>
|
||||
<div class="text-center" id="data-table"></div>
|
||||
<div id="pie-chart" style="margin: auto;"><script type="text/javascript">
|
||||
|
||||
window.onload = function () {
|
||||
google.charts.load('current', {
|
||||
packages: ['corechart']
|
||||
});
|
||||
google.charts.load('current', { packages: ['corechart'] });
|
||||
|
||||
// Set a callback to run when the API is loaded.
|
||||
google.charts.setOnLoadCallback(drawChart);
|
||||
|
||||
function drawChart() {
|
||||
// Create data array from Flask data passed into the template
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Token');
|
||||
data.addColumn('number', 'Value');
|
||||
data.addColumn({ type: 'string', role: 'tooltip', 'p': { 'html': true } });
|
||||
|
||||
data.addRows([
|
||||
{% for token, value, name in pie_chart %}
|
||||
['{{ token }}', {{ value }}, '{{name}}'],
|
||||
{% endfor %}
|
||||
]);
|
||||
|
||||
// Set chart options
|
||||
var options = {
|
||||
pieSliceText: 'label',
|
||||
legend: {
|
||||
position: 'right',
|
||||
textStyle: {
|
||||
color: 'white'
|
||||
}
|
||||
},
|
||||
backgroundColor: '#212529',
|
||||
};
|
||||
var chart = new google.visualization.PieChart(document.getElementById('pie-chart'));
|
||||
function resizeChart() {
|
||||
// Dynamically adjust the chart size to the container
|
||||
var width = window.innerWidth * 0.8;
|
||||
var height = window.innerHeight * 0.5;
|
||||
|
||||
// If the width is less than 600 px use full width
|
||||
if (width < 700) {
|
||||
chart.draw(data, options);
|
||||
}
|
||||
else {
|
||||
chart.draw(data, {
|
||||
...options,
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resizeChart();
|
||||
|
||||
window.addEventListener('resize', resizeChart);
|
||||
|
||||
|
||||
}
|
||||
let isPerTokenView = false; // Track the current view state
|
||||
let chart; // Declare the chart instance globally to reuse it
|
||||
let options = {
|
||||
pieSliceText: 'label',
|
||||
tooltip: { isHtml: false },
|
||||
legend: {
|
||||
position: 'right',
|
||||
textStyle: { color: 'white' }
|
||||
},
|
||||
backgroundColor: '#212529',
|
||||
};
|
||||
</script></div><a class="btn btn-secondary" role="button" href="https://www.coingecko.com/en/portfolios/public/vault" target="_blank">View on Coingecko</a>
|
||||
|
||||
async function fetchData(apiUrl) {
|
||||
try {
|
||||
const response = await fetch(apiUrl);
|
||||
if (!response.ok) throw new Error('Failed to fetch data from API');
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function transformDataForChart(data) {
|
||||
const chartData = [];
|
||||
for (const token in data) {
|
||||
if (token !== 'total') {
|
||||
chartData.push([
|
||||
token, // Label for the chart
|
||||
data[token].value, // Value for the chart
|
||||
data[token].tooltip, // Tooltip for the chart
|
||||
]);
|
||||
}
|
||||
}
|
||||
return chartData;
|
||||
}
|
||||
|
||||
async function drawChart() {
|
||||
const apiUrl = '/api/v1/vault';
|
||||
const data = await fetchData(apiUrl);
|
||||
|
||||
if (!data) return; // Exit if data fetch fails
|
||||
|
||||
const chartDataTable = new google.visualization.DataTable();
|
||||
chartDataTable.addColumn('string', 'Token');
|
||||
chartDataTable.addColumn('number', 'Value');
|
||||
chartDataTable.addColumn({ type: 'string', role: 'tooltip', 'p': { 'html': false } });
|
||||
chartDataTable.addRows(transformDataForChart(data));
|
||||
|
||||
chart = new google.visualization.PieChart(document.getElementById('pie-chart'));
|
||||
resizeAndDraw(chart, chartDataTable, options);
|
||||
updateText(true);
|
||||
populateTable(data);
|
||||
}
|
||||
|
||||
function updateText(isVault) {
|
||||
let headerText = document.getElementById('chart-header');
|
||||
if (isVault) {
|
||||
headerText.innerText = 'Current Vault Contents';
|
||||
} else {
|
||||
headerText.innerText = 'Current Per Token Holding';
|
||||
}
|
||||
}
|
||||
|
||||
function populateTable(data) {
|
||||
const tableContainer = document.getElementById('data-table');
|
||||
tableContainer.innerHTML = ''; // Clear previous table data
|
||||
|
||||
// Create table elements
|
||||
const table = document.createElement('table');
|
||||
table.style.margin = 'auto';
|
||||
table.style.borderCollapse = 'collapse';
|
||||
|
||||
const thead = document.createElement('thead');
|
||||
const tbody = document.createElement('tbody');
|
||||
|
||||
// Create table header
|
||||
const headerRow = document.createElement('tr');
|
||||
['Name', 'Amount', 'Value'].forEach(headerText => {
|
||||
const th = document.createElement('th');
|
||||
th.textContent = headerText;
|
||||
th.style.border = '1px solid #ccc';
|
||||
th.style.padding = '8px 20px';
|
||||
th.style.backgroundColor = '#333';
|
||||
th.style.color = 'white';
|
||||
headerRow.appendChild(th);
|
||||
});
|
||||
thead.appendChild(headerRow);
|
||||
|
||||
// Create table rows
|
||||
for (const token in data) {
|
||||
if (token !== 'total') {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
const nameCell = document.createElement('td');
|
||||
nameCell.textContent = data[token].name;
|
||||
nameCell.style.border = '1px solid #ccc';
|
||||
nameCell.style.padding = '8px 20px';
|
||||
|
||||
const amountCell = document.createElement('td');
|
||||
amountCell.textContent = `${data[token].amount} ${token}`;
|
||||
amountCell.style.border = '1px solid #ccc';
|
||||
amountCell.style.padding = '8px 20px';
|
||||
|
||||
const valueCell = document.createElement('td');
|
||||
valueCell.textContent = data[token].value;
|
||||
valueCell.style.border = '1px solid #ccc';
|
||||
valueCell.style.padding = '8px 20px';
|
||||
|
||||
row.appendChild(nameCell);
|
||||
row.appendChild(amountCell);
|
||||
row.appendChild(valueCell);
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
}
|
||||
table.appendChild(thead);
|
||||
table.appendChild(tbody);
|
||||
tableContainer.appendChild(table);
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function toggleChart() {
|
||||
isPerTokenView = !isPerTokenView;
|
||||
const apiUrl = isPerTokenView ? '/api/v1/token' : '/api/v1/vault';
|
||||
const data = await fetchData(apiUrl);
|
||||
|
||||
if (!data) return; // Exit if data fetch fails
|
||||
|
||||
const chartDataTable = new google.visualization.DataTable();
|
||||
chartDataTable.addColumn('string', 'Token');
|
||||
chartDataTable.addColumn('number', 'Value');
|
||||
chartDataTable.addColumn({ type: 'string', role: 'tooltip', 'p': { 'html': false } });
|
||||
chartDataTable.addRows(transformDataForChart(data));
|
||||
|
||||
resizeAndDraw(chart, chartDataTable, options);
|
||||
updateText(!isPerTokenView);
|
||||
populateTable(data);
|
||||
}
|
||||
|
||||
function resizeAndDraw(chart, chartDataTable, options) {
|
||||
function resizeChart() {
|
||||
const width = window.innerWidth * 0.8;
|
||||
const height = window.innerHeight * 0.5;
|
||||
|
||||
const dynamicOptions = { ...options };
|
||||
if (width >= 700) {
|
||||
dynamicOptions.width = width;
|
||||
dynamicOptions.height = height;
|
||||
}
|
||||
|
||||
chart.draw(chartDataTable, dynamicOptions);
|
||||
}
|
||||
|
||||
resizeChart();
|
||||
window.addEventListener('resize', resizeChart);
|
||||
}
|
||||
|
||||
// Set button event listener
|
||||
document.getElementById('chart-header').addEventListener('click', toggleChart);
|
||||
};
|
||||
</script>
|
||||
</div><a class="btn btn-secondary" role="button" href="https://www.coingecko.com/en/portfolios/public/vault" target="_blank" style="margin: 10px;">View on Coingecko</a>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
@@ -189,6 +299,7 @@
|
||||
</div>
|
||||
</footer>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/bs-init.js"></script>
|
||||
<script src="https://www.gstatic.com/charts/loader.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user