From de66e266f1002129f174cd3380660be67665b74e Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Sun, 29 Jun 2025 11:05:38 -0700 Subject: [PATCH] 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. --- hledger-web/Hledger/Web/Handler/RegisterR.hs | 8 +++--- hledger-web/templates/chart.hamlet | 27 +++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/hledger-web/Hledger/Web/Handler/RegisterR.hs b/hledger-web/Hledger/Web/Handler/RegisterR.hs index 349a62d23..2997faa01 100644 --- a/hledger-web/Hledger/Web/Handler/RegisterR.hs +++ b/hledger-web/Hledger/Web/Handler/RegisterR.hs @@ -114,9 +114,9 @@ registerChartHtml q title percommoditytxnreports = $(hamletFile "templates/chart shownull c = if null c then " " else c nodatelink = (RegisterR, [("q", T.unwords $ removeDates q)]) -dayToJsTimestamp :: Day -> Integer -dayToJsTimestamp d = +-- | Makes a unix timestamp (milliseconds since epoch) corresponding to noon on the given date in UTC. +dayToUtcNoonTimestamp :: Day -> Integer +dayToUtcNoonTimestamp d = read (formatTime defaultTimeLocale "%s" t) * 1000 -- XXX read where - t = UTCTime d (secondsToDiffTime 0) - + t = UTCTime d (secondsToDiffTime $ 12 * 60 * 60) diff --git a/hledger-web/templates/chart.hamlet b/hledger-web/templates/chart.hamlet index 1a949c87e..e0471dd37 100644 --- a/hledger-web/templates/chart.hamlet +++ b/hledger-web/templates/chart.hamlet @@ -14,7 +14,7 @@ $# If $ is the first character in a line, it must be \-escaped to hide it from h data: [ $forall i <- reverse items [ - #{dayToJsTimestamp $ triDate i}, + #{dayToUtcNoonTimestamp $ triDate i}, #{simpleMixedAmountQuantity $ triCommodityBalance c i} ], ], @@ -35,7 +35,7 @@ $# If $ is the first character in a line, it must be \-escaped to hide it from h data: [ $forall i <- reverse items [ - #{dayToJsTimestamp $ triDate i}, + #{dayToUtcNoonTimestamp $ triDate i}, #{simpleMixedAmountQuantity $ triCommodityBalance c i}, '#{showZeroCommodity $ triCommodityAmount c i}', '#{showZeroCommodity $ triCommodityBalance c i}', @@ -125,9 +125,7 @@ $# If $ is the first character in a line, it must be \-escaped to hide it from h // Handle a click event on the chart. function registerChartClick(ev, pos, item) { - if (!item) { - return; - } + if (!item) { return; } var targetselector = '#' + item.series.data[item.dataIndex][5]; var $target = $(targetselector); if ($target.length) { @@ -142,14 +140,19 @@ $# If $ is the first character in a line, it must be \-escaped to hide it from h function registerChartSelect(ev, ranges) { console.log("selected", ranges.xaxis.from, ranges.xaxis.to); - // This should pick good from/to dates based on the selected x-values, which is tricky to get right. - // Round down for the 'from' day: + // 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); - // Round up for the 'to' day: - var to = new Date(ranges.xaxis.to + (24 * 60 * 60 * 1000) - 1); - var range = - from.getFullYear() + "/" + (from.getMonth() + 1) + "/" + from.getDate() + "-" + - to.getFullYear() + "/" + (to.getMonth() + 1) + "/" + to.getDate(); + 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;