credger/public/plotly.html

149 lines
6.7 KiB
HTML
Raw Permalink Normal View History

2021-05-20 23:07:14 +02:00
<html>
<head>
<meta charset="UTF-8">
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
2021-05-21 15:57:39 +02:00
let selected_accounts = [];
2021-05-20 23:07:14 +02:00
const API = {
fetch: async ( endpoint, params = {} ) => {
let url = new URL( endpoint, `${location.protocol}//${location.host}` );
url.search = new URLSearchParams( params );
const response = await fetch( url );
return await response.json();
},
balance: ( period, categories, depth ) => API.fetch( "/api/ledger/balance", { period: period, categories: categories, depth: depth } ),
register: ( period, categories ) => API.fetch( "/api/ledger/register", { period: period, categories: categories } ),
graph_values: ( period, categories, granularity ) => API.fetch( "/api/ledger/graph_values", { period: period, categories: categories, granularity: granularity } ),
accounts: () => API.fetch( "/api/ledger/accounts" )
}
const Controls = {
2021-05-21 15:57:39 +02:00
accounts_list: {
init: async ( ui_id ) => {
2021-05-20 23:07:14 +02:00
let accounts = await API.accounts();
let ui_accounts = document.querySelector(`#${ui_id}`);
let content = "<select name=\"accounts\" multiple size=\"20\">";
2021-05-21 15:57:39 +02:00
let account_to_option = ( account, selected ) => `<option value="${account.join(':')}" ${selected ? "selected" : ""}>${account.join(':')}</option>`;
2021-05-20 23:07:14 +02:00
for ( let i = 1 ; i < accounts.reduce( (memo, a) => a.length > memo ? a.length : memo, 0 ) ; i++ ) {
content += `
2021-05-21 15:57:39 +02:00
<optgroup label="Depth: ${i}">
${accounts.filter( a => a.length == i ).map( account => account_to_option( account, ((account.length == 1 && account[0] == "Assets") || (account.length == 2 && account[0] == "Expenses")))).join('')}
</optgroup>`;
2021-05-20 23:07:14 +02:00
}
content += "</select>";
2021-05-20 23:07:14 +02:00
ui_accounts.innerHTML = content;
let ui_accounts_select = document.querySelector(`#${ui_id} select`);
ui_accounts_select.addEventListener( 'change', event => Controls.accounts_list.onchange( event.target ) );
Controls.accounts_list.onchange( ui_accounts_select );
2021-05-20 23:07:14 +02:00
},
onchange: element => {
selected_accounts = Array.from( element.options ).filter( o => o.selected ).map( o => o.value );
Controls.main_graph.set( selected_accounts );
}
2021-05-21 15:57:39 +02:00
},
accounts_sliders: {
init: async ( ui_id ) => {
let accounts = await API.accounts();
let ui_accounts = document.querySelector(`#${ui_id}`);
let content = "<select name=\"accounts\" multiple size=\"20\">";
let accounts_depths = {};
let onchange = () => {
selected_accounts = Object.keys( accounts_depths )
.filter( act => accounts_depths[act] > 0 )
2021-05-24 12:26:06 +02:00
.map( act => accounts.filter( a => a[0] == act && a.length <= accounts_depths[act] ) )
.flat();
Controls.main_graph.set( selected_accounts );
};
ui_accounts.innerHTML = accounts.filter( act => act.length == 1 ).map( act => {
let max_depth = accounts.filter(a => a[0] == act[0]).map(a => a.length).sort().reverse()[0];
let val = 0;
if (act[0] == "Income")
val = 1;
else if (act[0] == "Expenses")
val = 2;
accounts_depths[ act[0] ] = val;
2021-05-24 12:26:06 +02:00
return `<div style="float: left; width: 100%;"><label for="myRange-${act[0]}" style="float: left;">${act}</label><input style="float: right;" type="range" min="0" max="${max_depth}" value="${val}" ${val == 0 ? 'disabled' : ''} class="slider" name="myRange-${act[0]}" id="myRange-${act[0]}"></div>`;
}).join('');
Object.keys( accounts_depths ).forEach( act => {
document.querySelector( `#myRange-${act}` )
.addEventListener( 'change', event => {
accounts_depths[act] = event.target.value;
onchange();
});
2021-05-21 15:57:39 +02:00
});
onchange();
}
},
main_graph: {
init: ( ui_id ) => {
let layout = {
2021-05-24 12:26:06 +02:00
xaxis: { title: 'Dates',
tickangle: -45 },
yaxis: {title: 'Montant'},
barmode: 'relative',
2021-05-24 12:26:06 +02:00
title: '€'
};
Controls.main_graph.set = async ( accounts ) => {
if (accounts.length < 1)
return;
let values = await API.graph_values( "", accounts.map(a => a.join(':')).join(" "), "monthly" );
Plotly.react( ui_id,
Object.keys(values)
.map( act => {
let v = values[ act ].sort( (a, b) => b.date - a.date );
return {
name: act,
type: "bar",
2021-05-24 12:26:06 +02:00
x: v.map( reg => new Date( reg.date ) ),
y: v.map( reg => reg.amount)
};
} ),
layout );
};
2021-05-21 15:57:39 +02:00
}
},
2021-05-20 23:07:14 +02:00
};
</script>
</head>
<body>
<div id="accounts" style="float: left; width: 19%;"></div>
2021-05-20 23:07:14 +02:00
2021-05-21 15:57:39 +02:00
<div id="mainGraph" style="float: right; width: 79%;" ></div>
2021-05-20 23:07:14 +02:00
<script>
(async () => {
Controls.main_graph.init( "mainGraph" );
// Controls.accounts_list.init( "accounts" );
Controls.accounts_sliders.init( "accounts" );
2021-05-20 23:07:14 +02:00
})();
</script>
</body>
</html>