credger/public/pure.html

127 lines
5.6 KiB
HTML
Raw Normal View History

2019-11-20 17:04:29 +01:00
<html>
<head>
2019-11-21 12:38:35 +01:00
<meta charset="UTF-8">
2019-11-20 17:04:29 +01:00
<script>
2019-11-21 11:23:20 +01:00
const fetch_from_API = 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();
};
2019-11-20 17:04:29 +01:00
const API = {
2019-11-21 11:23:20 +01:00
balance: (period, categories, depth) => fetch_from_API( "/api/ledger/balance",
{ period: period,
categories: categories,
depth: depth } ),
register: (period, categories) => fetch_from_API( "/api/ledger/register",
{ period: period,
categories: categories } ),
2019-11-20 17:04:29 +01:00
2019-11-21 11:23:20 +01:00
graph_values: (period, categories, granularity) => fetch_from_API( "/api/ledger/graph_values",
{ period: period,
categories: categories,
granularity: granularity } ),
accounts: () => fetch_from_API( "/api/ledger/accounts" )
2019-11-20 17:04:29 +01:00
}
2019-11-21 11:23:20 +01:00
const Utils = {
text_to_color: ( text ) => {
let hash = 0
for (let i = 0; i < text.length; i++)
hash = (((hash << 5) - hash) + text.charCodeAt(i)) | 0;
hash = Math.abs( hash );
let shash = hash.toString(16).substr(0, 6).padEnd( 6, '0' );
return `#${shash}`;
}
};
const UI = {
2019-11-21 12:38:49 +01:00
/* https://medium.com/@heyoka/scratch-made-svg-donut-pie-charts-in-html5-2c587e935d72 */
2019-11-21 11:23:20 +01:00
donut: ( element, dataset ) => {
2019-11-21 12:38:49 +01:00
const thickness = 9;
2019-11-21 11:23:20 +01:00
let filed_percent = 0;
const data_to_donut_segment = ( data ) => {
2019-11-21 12:38:49 +01:00
if ( data.amount > 0 ) {
const stroke_dashoffset = ( percent ) => {
let offset = 100 - filed_percent;
2019-11-21 11:23:20 +01:00
2019-11-21 12:38:49 +01:00
return offset > 100 ? offset - 100 : offset;
};
2019-11-21 11:23:20 +01:00
2019-11-21 12:38:49 +01:00
const donut_segment = `<circle class="donut-segment ${data.account.split(':').join(' ')}" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="${data.color}" stroke-width="${thickness}" stroke-dasharray="${data.percent} ${100 - data.percent}" stroke-dashoffset="${stroke_dashoffset( data.percent )}"><title>${data.tooltip}</title></circle>`;
filed_percent += data.percent;
2019-11-21 11:23:20 +01:00
2019-11-21 12:38:49 +01:00
return donut_segment;
} else
return '';
2019-11-21 11:23:20 +01:00
};
element.innerHTML = `<svg width="100%" height="100%" viewBox="0 0 42 42" class="donut">
<circle class="donut-hole" cx="21" cy="21" r="15.91549430918954" fill="#fff"></circle>
2019-11-21 12:38:49 +01:00
<circle class="donut-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#d2d3d4" stroke-width="${thickness}"></circle>
2019-11-21 11:23:20 +01:00
${dataset.map( line => data_to_donut_segment( line ) ).join("")}
</svg><pre>${JSON.stringify( dataset )}</pre>`;
}
};
2019-11-21 12:38:49 +01:00
let current_period;
const Period = {
set: ( period ) => {
current_period = period;
document.querySelector( "#period #display" ).innerHTML = current_period.toISOString();
monthly( current_period.toISOString().split("T")[0].slice( 0, -3 ), "#month" );
},
get: () => current_period,
prev: () => {
current_period.setMonth( current_period.getMonth() - 1 );
Period.set( current_period );
},
next: () => {
current_period.setMonth( current_period.getMonth() + 1 );
Period.set( current_period );
},
};
const monthly = ( month, element_selector ) => {
API.balance( month, ["Expenses"].join(" "), 3 )
.then( balance => {
const total = balance.reduce( (memo, line) => memo + line.amount, 0 );
UI.donut( document.querySelector( `${element_selector} #donut` ),
balance.sort( (a, b) => b.amount - a.amount )
.map( line => {
line.color = Utils.text_to_color( line.account );
line.percent = ( line.amount / total ) * 100;
line.tooltip = `${line.account} : ${line.amount} €`;
return line;
} ) );
} );
};
2019-11-20 17:04:29 +01:00
</script>
</head>
<body>
2019-11-21 12:38:49 +01:00
<div id="period">
<button onclick="Period.prev()">-</button>
<button onclick="Period.next()">+</button>
<h3 id="display"></h3>
</div>
<div id="month">
<div id="donut" style="height: 256; width: 256;"></div>
</div>
2019-11-21 11:23:20 +01:00
2019-11-20 17:04:29 +01:00
<script>
2019-11-21 12:38:49 +01:00
Period.set( new Date() );
2019-11-20 17:04:29 +01:00
</script>
</body>
</html>