diff --git a/draftlogs/6725_fix.md b/draftlogs/6725_fix.md new file mode 100644 index 00000000000..24074a12749 --- /dev/null +++ b/draftlogs/6725_fix.md @@ -0,0 +1,4 @@ +``` + - Fix horizontal title alignment [[#6668](https://github.com/plotly/plotly.js/issues/6668)] + - Fix single-point histogram when user has provided bin widths [[#6661](https://github.com/plotly/plotly.js/issues/6661)] +``` \ No newline at end of file diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 741bb089895..aea451d150d 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -54,6 +54,30 @@ module.exports = function draw(gd, opts) { } }; +// After legend dimensions are calculated the title can be aligned horizontally left, center, right +function horizontalAlignTitle(titleEl, legendObj, bw) { + if((legendObj.title.side !== 'top center') && (legendObj.title.side !== 'top right')) return; + + var font = legendObj.title.font; + var lineHeight = font.size * LINE_SPACING; + var titleOffset = 0; + var textNode = titleEl.node(); + + var width = Drawing.bBox(textNode).width; // width of the title text + + if(legendObj.title.side === 'top center') { + titleOffset = 0.5 * (legendObj._width - 2 * bw - 2 * constants.titlePad - width); + } else if(legendObj.title.side === 'top right') { + titleOffset = legendObj._width - 2 * bw - 2 * constants.titlePad - width; + } + + svgTextUtils.positionText(titleEl, + bw + constants.titlePad + titleOffset, + bw + lineHeight + ); +} + + function drawOne(gd, opts) { var legendObj = opts || {}; @@ -148,8 +172,9 @@ function drawOne(gd, opts) { var title = legendObj.title; legendObj._titleWidth = 0; legendObj._titleHeight = 0; + var titleEl; if(title.text) { - var titleEl = Lib.ensureSingle(scrollBox, 'text', legendId + 'titletext'); + titleEl = Lib.ensureSingle(scrollBox, 'text', legendId + 'titletext'); titleEl.attr('text-anchor', 'start') .call(Drawing.font, title.font) .text(title.text); @@ -193,6 +218,11 @@ function drawOne(gd, opts) { var isPaperX = legendObj.xref === 'paper'; var isPaperY = legendObj.yref === 'paper'; + // re-calculate title position after legend width is derived. To allow for horizontal alignment + if(title.text) { + horizontalAlignTitle(titleEl, legendObj, bw); + } + if(!inHover) { var lx, ly; @@ -661,18 +691,13 @@ function computeTextDimensions(g, gd, legendObj, aTitle) { // approximation to height offset to center the font // to avoid getBoundingClientRect if(aTitle === MAIN_TITLE) { - var titleOffset = 0; if(legendObj.title.side === 'left') { // add extra space between legend title and itmes width += constants.itemGap * 2; - } else if(legendObj.title.side === 'top center') { - if(legendObj._width) titleOffset = 0.5 * (legendObj._width - 2 * bw - 2 * constants.titlePad - width); - } else if(legendObj.title.side === 'top right') { - if(legendObj._width) titleOffset = legendObj._width - 2 * bw - 2 * constants.titlePad - width; } svgTextUtils.positionText(textEl, - bw + constants.titlePad + titleOffset, + bw + constants.titlePad, bw + lineHeight ); } else { // legend item diff --git a/src/traces/histogram/calc.js b/src/traces/histogram/calc.js index 5a649692012..e705ddd36fa 100644 --- a/src/traces/histogram/calc.js +++ b/src/traces/histogram/calc.js @@ -308,8 +308,10 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) { // Edge case: single-valued histogram overlaying others // Use them all together to calculate the bin size for the single-valued one + // Don't re-calculate bin width if user manually specified it (checing in bingroup=='' or xbins is defined) if(isOverlay && !Registry.traceIs(trace, '2dMap') && newBinSpec._dataSpan === 0 && - pa.type !== 'category' && pa.type !== 'multicategory') { + pa.type !== 'category' && pa.type !== 'multicategory' && + trace.bingroup === '' && (typeof trace.xbins === 'undefined')) { // Several single-valued histograms! Stop infinite recursion, // just return an extra flag that tells handleSingleValueOverlays // to sort out this trace too diff --git a/test/image/baselines/legend_horizontal_one_row.png b/test/image/baselines/legend_horizontal_one_row.png index 7883a047c51..3888f600654 100644 Binary files a/test/image/baselines/legend_horizontal_one_row.png and b/test/image/baselines/legend_horizontal_one_row.png differ diff --git a/test/image/baselines/zz_histogram_overlay-1point-date.png b/test/image/baselines/zz_histogram_overlay-1point-date.png new file mode 100644 index 00000000000..3a72ebf390f Binary files /dev/null and b/test/image/baselines/zz_histogram_overlay-1point-date.png differ diff --git a/test/image/mocks/legend_horizontal_one_row.json b/test/image/mocks/legend_horizontal_one_row.json index 50888583bdb..95d6f576402 100644 --- a/test/image/mocks/legend_horizontal_one_row.json +++ b/test/image/mocks/legend_horizontal_one_row.json @@ -20,6 +20,7 @@ } ], "layout": { + "height": 300, "title": {"text": "Average Distribution per Month"}, "legend": { "orientation": "h", "title": { "text": "Legend Title", "side": "top center" }} } diff --git a/test/image/mocks/zz_histogram_overlay-1point-date.json b/test/image/mocks/zz_histogram_overlay-1point-date.json new file mode 100644 index 00000000000..50b9f0e8dd1 --- /dev/null +++ b/test/image/mocks/zz_histogram_overlay-1point-date.json @@ -0,0 +1,48 @@ +{ + "data": [ + { + "x": ["2023-05-22 09:29:56.00"], + "opacity": 1, + "type": "histogram", + "name": "Results B", + "marker": { + "color": "rgba(0, 255, 0, .2)", + "line": { + "color": "rgba(0, 255, 0, 1)", + "width": 2 + } + }, + "xbins": { + "size": "M1", + "start": "2023-05-01", + "end": "2023-07-01" + } + }, + { + "x": ["2023-05-21 09:29:56.00", "2023-05-26 09:29:56.00", "2023-06-21 09:29:56.00"], + "opacity": 1, + "type": "histogram", + "name": "Results A", + "marker": { + "color": "rgba(0, 0, 255, .2)", + "line": { + "color": "rgba(0, 0, 255, 1)", + "width": 2 + } + }, + "xbins": { + "size": "M1", + "start": "2023-05-01", + "end": "2023-07-01" + } + } + ], + "layout": { + "barmode": "overlay", + "title": { "text": "Sampled Results" }, + "xaxis": { + "title": { "text": "Date" } + }, + "yaxis": { "title": { "text": "Count" } } + } +}