Skip to content

Commit b6684b7

Browse files
authored
Merge pull request #8104 from MannXo/fix/8100-unified-hoverlabel-align
fix: Apply `hoverlabel.align` to unified hover label items
2 parents 1f53454 + dc20017 commit b6684b7

6 files changed

Lines changed: 117 additions & 50 deletions

File tree

‎draftlogs/8104_fix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix `hoverlabel.align` so that it aligns the item text in `x unified` and `y unified` hover labels [[#8104](https://github.com/plotly/plotly.js/pull/8104)], with thanks to @MannXo for the contribution!

‎src/components/fx/layout_attributes.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ module.exports = {
188188
editType: 'none',
189189
description: [
190190
'Sets the horizontal alignment of the text content within hover label box.',
191-
'Has an effect only if the hover label text spans more two or more lines'
191+
'Has an effect only if the hover label text spans two or more lines'
192192
].join(' ')
193193
},
194194
namelength: {

‎src/components/legend/draw.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,17 @@ function computeLegendDimensions(gd, groups, traces, legendObj, scrollBox) {
10661066
Drawing.setRect(traceToggle, 0, -h / 2, w, h);
10671067
});
10681068

1069+
if (legendObj._inHover) {
1070+
const textRight = legendObj._width - bw2 - itemGap - titleSize[0];
1071+
traces.each(function (d) {
1072+
if (d[0].textAlign !== 'right') return;
1073+
d3.select(this)
1074+
.select('.' + legendId + 'text')
1075+
.attr('text-anchor', 'end')
1076+
.call(svgTextUtils.positionText, textRight);
1077+
});
1078+
}
1079+
10691080
// align legend title horizontally
10701081
var titleEl = scrollBox.select('.' + legendId + 'titletext');
10711082
if(titleEl.node()) {

‎src/types/generated/schema.d.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ export interface ColorBar {
438438

439439
export interface HoverLabel {
440440
/**
441-
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans more two or more lines
441+
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans two or more lines
442442
* @default 'auto'
443443
*/
444444
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
@@ -1577,7 +1577,7 @@ export interface CandlestickData {
15771577
hoverinfo?: 'x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}) | ('x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}))[];
15781578
hoverlabel?: {
15791579
/**
1580-
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans more two or more lines
1580+
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans two or more lines
15811581
* @default 'auto'
15821582
*/
15831583
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
@@ -6074,7 +6074,7 @@ export interface OhlcData {
60746074
hoverinfo?: 'x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}) | ('x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}))[];
60756075
hoverlabel?: {
60766076
/**
6077-
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans more two or more lines
6077+
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans two or more lines
60786078
* @default 'auto'
60796079
*/
60806080
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
@@ -16182,7 +16182,7 @@ export interface Layout {
1618216182
hoverdistance?: number;
1618316183
hoverlabel?: {
1618416184
/**
16185-
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans more two or more lines
16185+
* Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans two or more lines
1618616186
* @default 'auto'
1618716187
*/
1618816188
align?: 'left' | 'right' | 'auto';

‎test/jasmine/tests/hover_test.js‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7395,6 +7395,61 @@ describe('hovermode: (x|y)unified', function () {
73957395
.then(done, done.fail);
73967396
});
73977397

7398+
it('should align item text with hoverlabel.align', (done) => {
7399+
const getItems = () => {
7400+
const items = [];
7401+
getHoverLabel()
7402+
.selectAll('g.traces text.legendtext')
7403+
.each(function () {
7404+
const { left, right } = this.getBoundingClientRect();
7405+
items.push({
7406+
anchor: this.getAttribute('text-anchor'),
7407+
left,
7408+
right,
7409+
x: this.getAttribute('x')
7410+
});
7411+
});
7412+
return items;
7413+
};
7414+
let rightAlignedShort;
7415+
7416+
Plotly.newPlot(gd, [{ y: [1, 2, 3] }, { y: [1000000, 2000000, 3000000] }], {
7417+
hovermode: 'x unified',
7418+
hoverlabel: { align: 'right' },
7419+
showlegend: false,
7420+
width: 500,
7421+
height: 500
7422+
})
7423+
.then(() => {
7424+
_hover(gd, { xval: 1 });
7425+
const [short, long] = getItems();
7426+
expect([short.anchor, long.anchor]).toEqual(['end', 'end']);
7427+
// Compare anchor positions because the text rect can extend past the anchor by a font-dependent amount
7428+
expect(short.x).toBe(long.x);
7429+
expect(short.left).toBeGreaterThan(long.left);
7430+
rightAlignedShort = short;
7431+
7432+
return Plotly.relayout(gd, 'hoverlabel.align', 'left');
7433+
})
7434+
.then(() => {
7435+
_hover(gd, { xval: 1 });
7436+
const [short, long] = getItems();
7437+
expect([short.anchor, long.anchor]).toEqual(['start', 'start']);
7438+
expect(short.left).toBeCloseTo(long.left, 0);
7439+
7440+
return Plotly.restyle(gd, 'hoverlabel.align', 'right', [0]);
7441+
})
7442+
.then(() => {
7443+
_hover(gd, { xval: 1 });
7444+
const [short, long] = getItems();
7445+
expect([short.anchor, long.anchor]).toEqual(['end', 'start']);
7446+
// Same text and box as the first step, so the right-aligned item must not move
7447+
expect(short.x).toBe(rightAlignedShort.x);
7448+
expect(short.right).toBeCloseTo(rightAlignedShort.right, 0);
7449+
})
7450+
.then(done, done.fail);
7451+
});
7452+
73987453
it('should work with hovertemplate', function (done) {
73997454
var mockCopy = Lib.extendDeep({}, mock);
74007455
mockCopy.data[0].hovertemplate = 'hovertemplate: %{y:0.2f}';

0 commit comments

Comments
 (0)