Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/8104_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +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!
2 changes: 1 addition & 1 deletion src/components/fx/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ module.exports = {
editType: 'none',
description: [
'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'
'Has an effect only if the hover label text spans two or more lines'
].join(' ')
},
namelength: {
Expand Down
11 changes: 11 additions & 0 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,17 @@ function computeLegendDimensions(gd, groups, traces, legendObj, scrollBox) {
Drawing.setRect(traceToggle, 0, -h / 2, w, h);
});

if (legendObj._inHover) {
const textRight = legendObj._width - bw2 - itemGap - titleSize[0];
traces.each(function (d) {
if (d[0].textAlign !== 'right') return;
d3.select(this)
.select('.' + legendId + 'text')
.attr('text-anchor', 'end')
.call(svgTextUtils.positionText, textRight);
});
}

// align legend title horizontally
var titleEl = scrollBox.select('.' + legendId + 'titletext');
if(titleEl.node()) {
Expand Down
8 changes: 4 additions & 4 deletions src/types/generated/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export interface ColorBar {

export interface HoverLabel {
/**
* 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
* 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
* @default 'auto'
*/
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
Expand Down Expand Up @@ -1577,7 +1577,7 @@ export interface CandlestickData {
hoverinfo?: 'x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}) | ('x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}))[];
hoverlabel?: {
/**
* 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
* 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
* @default 'auto'
*/
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
Expand Down Expand Up @@ -6074,7 +6074,7 @@ export interface OhlcData {
hoverinfo?: 'x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}) | ('x' | 'y' | 'z' | 'text' | 'name' | 'all' | 'none' | 'skip' | (string & {}))[];
hoverlabel?: {
/**
* 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
* 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
* @default 'auto'
*/
align?: 'left' | 'right' | 'auto' | ('left' | 'right' | 'auto')[];
Expand Down Expand Up @@ -16182,7 +16182,7 @@ export interface Layout {
hoverdistance?: number;
hoverlabel?: {
/**
* 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
* 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
* @default 'auto'
*/
align?: 'left' | 'right' | 'auto';
Expand Down
55 changes: 55 additions & 0 deletions test/jasmine/tests/hover_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7395,6 +7395,61 @@ describe('hovermode: (x|y)unified', function () {
.then(done, done.fail);
});

it('should align item text with hoverlabel.align', (done) => {
const getItems = () => {
const items = [];
getHoverLabel()
.selectAll('g.traces text.legendtext')
.each(function () {
const { left, right } = this.getBoundingClientRect();
items.push({
anchor: this.getAttribute('text-anchor'),
left,
right,
x: this.getAttribute('x')
});
});
return items;
};
let rightAlignedShort;

Plotly.newPlot(gd, [{ y: [1, 2, 3] }, { y: [1000000, 2000000, 3000000] }], {
hovermode: 'x unified',
hoverlabel: { align: 'right' },
showlegend: false,
width: 500,
height: 500
})
.then(() => {
_hover(gd, { xval: 1 });
const [short, long] = getItems();
expect([short.anchor, long.anchor]).toEqual(['end', 'end']);
// Compare anchor positions because the text rect can extend past the anchor by a font-dependent amount
expect(short.x).toBe(long.x);
expect(short.left).toBeGreaterThan(long.left);
rightAlignedShort = short;

return Plotly.relayout(gd, 'hoverlabel.align', 'left');
})
.then(() => {
_hover(gd, { xval: 1 });
const [short, long] = getItems();
expect([short.anchor, long.anchor]).toEqual(['start', 'start']);
expect(short.left).toBeCloseTo(long.left, 0);

return Plotly.restyle(gd, 'hoverlabel.align', 'right', [0]);
})
.then(() => {
_hover(gd, { xval: 1 });
const [short, long] = getItems();
expect([short.anchor, long.anchor]).toEqual(['end', 'start']);
// Same text and box as the first step, so the right-aligned item must not move
expect(short.x).toBe(rightAlignedShort.x);
expect(short.right).toBeCloseTo(rightAlignedShort.right, 0);
})
.then(done, done.fail);
});

it('should work with hovertemplate', function (done) {
var mockCopy = Lib.extendDeep({}, mock);
mockCopy.data[0].hovertemplate = 'hovertemplate: %{y:0.2f}';
Expand Down
Loading
Loading