hledger/hledger-web/templates/chart.hamlet
Simon Michael de66e266f1 fix:web: dragging in chart now selects date ranges more accurately
Eg, previously you couldn't select a range including transactions
at the rightmost edge of the chart.
2025-06-29 11:05:38 -07:00

163 lines
5.3 KiB
Plaintext

$# If $ is the first character in a line, it must be \-escaped to hide it from hamlet.
<label #register-chart-label style=""><br>
<div #register-chart style="height:150px; margin-bottom:1em; display:block;">
<script type=text/javascript>
\$(document).ready(function() {
var $chartdiv = $('#register-chart');
if ($chartdiv.is(':visible')) {
\$('#register-chart-label').text('#{charttitle}');
var seriesData = [
$forall (c,items) <- percommoditytxnreports
// we render each commodity using two series:
// one with extra data points added to show a stepped balance line
{
data: [
$forall i <- reverse items
[
#{dayToUtcNoonTimestamp $ triDate i},
#{simpleMixedAmountQuantity $ triCommodityBalance c i}
],
],
label: '#{shownull $ T.unpack c}',
color: #{colorForCommodity c},
lines: {
show: true,
steps: true,
},
points: {
show: false,
},
clickable: false,
hoverable: false,
},
// and one with the original data, showing one clickable, hoverable point per transaction
{
data: [
$forall i <- reverse items
[
#{dayToUtcNoonTimestamp $ triDate i},
#{simpleMixedAmountQuantity $ triCommodityBalance c i},
'#{showZeroCommodity $ triCommodityAmount c i}',
'#{showZeroCommodity $ triCommodityBalance c i}',
'#{concat $ intersperse "\\n" $ lines $ T.unpack $ showTransaction $ triOrigTransaction i}',
#{tindex $ triOrigTransaction i}
],
],
label: '',
color: #{colorForCommodity c},
lines: {
show: false,
},
points: {
show: true,
},
},
];
var plot = registerChart($chartdiv, seriesData);
plot.setSelection({ xaxis: { from: 500, to: 700 } }); // ?
\$chartdiv.bind("plotclick", registerChartClick);
\$chartdiv.bind("plotselected", registerChartSelect);
};
});
//eslint-disable-next-line no-unused-vars
function registerChart($container, series) {
// https://github.com/flot/flot/blob/master/API.md
return $container.plot(
series,
{
xaxis: {
mode: "time",
timeformat: "%Y/%m/%d",
},
selection: {
mode: "x"
},
legend: {
position: 'sw'
},
grid: {
markings: function () {
var now = Date.now();
return [
{
xaxis: { to: now }, // past
yaxis: { to: 0 }, // <0
color: '#ffdddd',
},
{
xaxis: { from: now }, // future
yaxis: { from: 0 }, // >0
color: '#e0e0e0',
},
{
xaxis: { from: now }, // future
yaxis: { to: 0 }, // <0
color: '#e8c8c8',
},
{
yaxis: { from: 0, to: 0 }, // =0
color: '#bb0000',
lineWidth:1
},
];
},
hoverable: true,
autoHighlight: true,
clickable: true,
},
// https://github.com/krzysu/flot.tooltip
tooltip: true,
tooltipOpts: {
xDateFormat: "%Y/%m/%d",
content:
function(label, x, y, flotitem) {
var data = flotitem.series.data[flotitem.dataIndex];
return data[3]+" balance on %x after "+data[2]+" posted by transaction:<pre>"+data[4]+"</pre>";
},
onHover: function(flotitem, $tooltipel) {
\$tooltipel.css('border-color',flotitem.series.color);
},
},
}
).data("plot");
}
// Handle a click event on the chart.
function registerChartClick(ev, pos, item) {
if (!item) { return; }
var targetselector = '#' + item.series.data[item.dataIndex][5];
var $target = $(targetselector);
if ($target.length) {
window.location.hash = targetselector;
\$('html, body').animate({
scrollTop: $target.offset().top
}, 1000);
}
}
// Handle a selection (zoom) event on the chart.
function registerChartSelect(ev, ranges) {
console.log("selected", ranges.xaxis.from, ranges.xaxis.to);
// Reconstruct from/to dates carefully based on the selected x-values.
// Those x values are unix timestamps (milliseconds since epoch) enclosing the data points' timestamps.
// Those are generated by dayToJsTimestamp, and are UTC times representing the transaction dates.
var from = new Date(ranges.xaxis.from);
var fromy = from.getUTCFullYear();
var fromm = from.getUTCMonth() + 1;
var fromd = from.getUTCDate();
var to = new Date(ranges.xaxis.to + 1 * 24 * 60 * 60 * 1000);
var toy = to.getUTCFullYear();
var tom = to.getUTCMonth() + 1;
var tod = to.getUTCDate();
var range = fromy + "/" + fromm + "/" + fromd + "-" + toy + "/" + tom + "/" + tod;
var baselink = "@?{nodatelink}";
if (baselink.endsWith("?q")) {
document.location = baselink + "=date:" + range;
} else {
document.location = baselink + "%20date:" + range;
}
}