From 28156a5a6bd7eaa296fd0ebbcd294ee5d25016f5 Mon Sep 17 00:00:00 2001 From: Chukwuleta Tobechi <47084273+TChukwuleta@users.noreply.github.com> Date: Fri, 30 Aug 2024 08:58:50 +0100 Subject: [PATCH] Include hover to display total sales per day (#6174) * Include hover to display total sales per day * Add label to top items as well * Bring in recent Chart modifications from app --------- Co-authored-by: Dennis Reimann --- .../Components/AppSales/Default.cshtml.js | 14 +++++- .../Components/AppTopItems/Default.cshtml.js | 13 ++++- .../StoreWalletBalance/Default.cshtml | 2 +- .../chartist/chartist-plugin-tooltip.css | 49 ++++++++++++++----- .../chartist/chartist-plugin-tooltip.js | 31 ++++++------ .../wwwroot/vendor/chartist/chartist.css | 6 +-- 6 files changed, 78 insertions(+), 37 deletions(-) diff --git a/BTCPayServer/Components/AppSales/Default.cshtml.js b/BTCPayServer/Components/AppSales/Default.cshtml.js index d1975b8d2..ffdd13980 100644 --- a/BTCPayServer/Components/AppSales/Default.cshtml.js +++ b/BTCPayServer/Components/AppSales/Default.cshtml.js @@ -8,17 +8,27 @@ if (!window.appSales) { const data = model; const render = (data, period) => { + document.querySelector(`#${id} .sales-count`).innerText = data.salesCount; + const series = data.series.map(s => s.salesCount); const labels = data.series.map((s, i) => period === 'Month' ? (i % 5 === 0 ? s.label : '') : s.label); const min = Math.min(...series); const max = Math.max(...series); const low = min === max ? 0 : Math.max(min - ((max - min) / 5), 0); - document.querySelector(`#${id} .sales-count`).innerText = data.salesCount; + const tooltip = Chartist.plugins.tooltip2({ + template: '
Sales: {{value}}
', + offset: { + x: 0, + y: -8 + } + }); new Chartist.Bar(`#${id} .ct-chart`, { labels, series: [series] }, { - low + low, + axisY: { onlyInteger: true }, + plugins: [tooltip] }); }; diff --git a/BTCPayServer/Components/AppTopItems/Default.cshtml.js b/BTCPayServer/Components/AppTopItems/Default.cshtml.js index 2d6c09583..8f7ae5208 100644 --- a/BTCPayServer/Components/AppTopItems/Default.cshtml.js +++ b/BTCPayServer/Components/AppTopItems/Default.cshtml.js @@ -3,14 +3,23 @@ if (!window.appTopItems) { dataLoaded (model) { const id = `AppTopItems-${model.id}`; const series = model.salesCount; - new Chartist.Bar(`#${id} .ct-chart`, { series }, { + const labels = model.entries.map(e => e.title); + const tooltip = Chartist.plugins.tooltip2({ + template: '
{{meta}} - Sales: {{value}}
', + offset: { + x: 0, + y: -8 + } + }); + new Chartist.Bar(`#${id} .ct-chart`, { series, labels }, { distributeSeries: true, horizontalBars: true, showLabel: false, stackBars: true, axisY: { offset: 0 - } + }, + plugins: [tooltip] }); } }; diff --git a/BTCPayServer/Components/StoreWalletBalance/Default.cshtml b/BTCPayServer/Components/StoreWalletBalance/Default.cshtml index 59264fcda..6a67d32ad 100644 --- a/BTCPayServer/Components/StoreWalletBalance/Default.cshtml +++ b/BTCPayServer/Components/StoreWalletBalance/Default.cshtml @@ -89,7 +89,7 @@ const max = Math.max(...series); const low = Math.max(min - ((max - min) / 5), 0); const tooltip = Chartist.plugins.tooltip2({ - template: '{{value}}', + template: '
{{value}}
', offset: { x: 0, y: -16 diff --git a/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.css b/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.css index f5c410a7d..b056e7271 100644 --- a/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.css +++ b/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.css @@ -3,21 +3,21 @@ * @author Antonia Ciocodeica * @version 0.1 22 Nov 2016 */ + .chartist-tooltip { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; position: absolute; left: 0; top: 0; z-index: 1000; - display: block; - padding: var(--btcpay-space-xs) var(--btcpay-space-s); visibility: hidden; transform: translateY(3em); opacity: 0; - border-radius: var(--btcpay-border-radius); - border: 1px solid var(--btcpay-body-border-light); - color: var(--btcpay-body-text); - background-color: var(--btcpay-bg-tile); - transition: transform var(--btcpay-transition-duration-fast) ease-in-out; + transition: transform 50ms ease-in-out; + pointer-events: none; } .chartist-tooltip:not([hidden]) { margin: 0; @@ -26,12 +26,34 @@ opacity: 1; } +.chartist-tooltip .chartist-tooltip-inner { + display: block; + padding: var(--btcpay-space-xs) var(--btcpay-space-s); + border-radius: var(--btcpay-border-radius); + border: 1px solid var(--btcpay-body-border-light); + color: var(--btcpay-body-text); + background-color: var(--btcpay-bg-tile); +} +.chartist-tooltip .chartist-tooltip-value { + color: var(--btcpay-body-text-muted); + background-color: var(--btcpay-bg-tile); + border-radius: var(--btcpay-border-radius); + padding: 0 var(--btcpay-space-s); + font-size: var(--btcpay-font-size-s); +} +.chartist-tooltip .chartist-tooltip-line { + width: 1px; + height: 100%; + background: var(--btcpay-body-text); + opacity: .8; +} + /* Tooltip arrow */ -.chartist-tooltip::before { +.chartist-tooltip-inner::before { content: '\25BC'; position: absolute; left: calc(50% - .5em); - top: 100%; + top: 90%; z-index: -1; font-size: 1.3em; line-height: .5em; @@ -40,19 +62,20 @@ transform: scaleY(0.7); text-shadow: 0 0.25em 0.35em rgba(0, 0, 0, 0.1); } -.chartist-tooltip--left::before { +.chartist-tooltip--left .chartist-tooltip-inner::before { left: 0.75em; } -.chartist-tooltip--right::before { +.chartist-tooltip--right .chartist-tooltip-inner::before { left: auto; right: 0.75em; } /* Adds a small point transition (line charts) when the point is active */ -.ct-point { +.ct-chart[data-charttooltip-id] .ct-point { + border: 16px solid transparent; transition: all 0.2s ease-in-out; } /* Increased specificity intended to overwrite the default chartist style */ .ct-chart-line.ct-chart-line .ct-point--hover { - stroke-width: 1.25em; + stroke-width: 8px; } diff --git a/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.js b/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.js index b37092a66..b1e760a0a 100644 --- a/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.js +++ b/BTCPayServer/wwwroot/vendor/chartist/chartist-plugin-tooltip.js @@ -84,6 +84,7 @@ var tooltipElement = getTooltipElement(); var pointValues = getPointValues(); var hideDelayTimer; + var containerRect; options.template = tooltipElement.innerHTML; @@ -178,7 +179,6 @@ var valueGroup; var valueIndex; var itemData; - var seriesData; clearTimeout(hideDelayTimer); @@ -199,21 +199,15 @@ seriesData = chart.options.reverseData ? seriesData.reverse()[seriesIndex] : seriesData[seriesIndex]; seriesData = (!Array.isArray(seriesData) && typeof seriesData == 'object' && seriesData.data) ? seriesData.data : seriesData; - if (!seriesData) { - return; - } - + if (!seriesData) return; itemData = (!Array.isArray(seriesData) && typeof seriesData == 'object') ? seriesData : seriesData[valueIndex]; - - if (typeof itemData == 'undefined') { - return; - } - + if (!itemData && typeof seriesData == 'number') itemData = { value: seriesData, meta: chart.data.labels[seriesIndex] }; + if (typeof itemData == 'undefined') return; meta = itemData.meta; value = itemData.value || itemData; - + if (typeof itemData == 'undefined') return; if (typeof options.valueTransformFunction === 'function') { - value = options.valueTransformFunction.call(chart, value); + value = options.valueTransformFunction.call(chart, value, chart.data.labels[valueIndex], valueIndex); } // Remove the hover class and the aria-describedby attribute from the currently active triggers @@ -241,7 +235,6 @@ // series name textMarkup = textMarkup.replace(new RegExp('{{seriesName}}', 'gi'), seriesName || ''); - console.log(textMarkup) tooltipElement.innerHTML = textMarkup; tooltipElement.removeAttribute('hidden'); setTooltipPosition(triggerElement); @@ -318,9 +311,13 @@ * @param Boolean ignoreClasses */ function setTooltipPosition(relativeElement, ignoreClasses) { - var positionData = getTooltipPosition(relativeElement); + containerRect = chart.container.getBoundingClientRect(); + var isLine = tooltipElement.innerHTML.match('chartist-tooltip-line'); + var positionData = getTooltipPosition(relativeElement, isLine); tooltipElement.style.transform = 'translate(' + positionData.left + 'px, ' + positionData.top + 'px)'; + if (isLine) + tooltipElement.style.height = containerRect.height + options.offset.y + 'px'; if (ignoreClasses) { return; @@ -336,7 +333,7 @@ * @param Element relativeElement * @return Object positionData */ - function getTooltipPosition(relativeElement) { + function getTooltipPosition(relativeElement, isLine) { var positionData = { alignment: 'center', }; @@ -345,7 +342,9 @@ var boxData = relativeElement.getBoundingClientRect(); var left = boxData.left + window.scrollX + options.offset.x - width / 2 + boxData.width / 2; - var top = boxData.top + window.scrollY - height + options.offset.y; + var top = isLine + ? containerRect.top + window.scrollY + options.offset.y + : boxData.top + window.scrollY - height + options.offset.y; // Minimum horizontal collision detection if (left + width > document.body.clientWidth) { diff --git a/BTCPayServer/wwwroot/vendor/chartist/chartist.css b/BTCPayServer/wwwroot/vendor/chartist/chartist.css index 323e1d231..d58a8b0a7 100644 --- a/BTCPayServer/wwwroot/vendor/chartist/chartist.css +++ b/BTCPayServer/wwwroot/vendor/chartist/chartist.css @@ -144,7 +144,7 @@ text-anchor: end; } .ct-grid { - stroke: rgba(128, 128, 128, .125); + stroke: rgba(128, 128, 128, .05); stroke-width: 1px; stroke-dasharray: 2px; } @@ -152,7 +152,7 @@ fill: none; } .ct-point { - stroke-width: 7px; + stroke-width: 4px; stroke-linecap: round; } .ct-line { @@ -161,7 +161,7 @@ .ct-area { stroke: none; - fill-opacity: 0.1; } + fill-opacity: 0.05; } .ct-bar { fill: none;