Skip to content
Snippets Groups Projects
Unverified Commit a241ca34 authored by Tom Robinson's avatar Tom Robinson Committed by GitHub
Browse files

Merge pull request #9416 from metabase/issue-9407

Show series title in tooltip
parents 3805410f 76c69ef9
No related merge requests found
......@@ -112,10 +112,26 @@ function applyChartTooltips(
// edge cases handled by the code below
const seriesIndex = determineSeriesIndexFromElement(this, isStacked);
const seriesSettings = chart.settings.series(series[seriesIndex]);
const seriesTitle = seriesSettings && seriesSettings.title;
const card = series[seriesIndex].card;
const isSingleSeriesBar =
this.classList.contains("bar") && series.length === 1;
const isMultiseries = series.length > 1;
const isBreakoutMultiseries = isMultiseries && card._breakoutColumn;
const isArea = this.classList.contains("area");
const isBar = this.classList.contains("bar");
const isSingleSeriesBar = isBar && !isMultiseries;
// always format the second column as the series name?
function getColumnDisplayName(col) {
// don't replace with series title for breakout multiseries since the series title is shown in the breakout value
if (col === cols[1] && !isBreakoutMultiseries && seriesTitle) {
return seriesTitle;
} else {
return getFriendlyName(col);
}
}
let data = [];
if (Array.isArray(d.key)) {
......@@ -123,11 +139,15 @@ function applyChartTooltips(
if (d.key._origin) {
data = d.key._origin.row.map((value, index) => {
const col = d.key._origin.cols[index];
return { key: getFriendlyName(col), value: value, col };
return {
key: getColumnDisplayName(col),
value: value,
col,
};
});
} else {
data = d.key.map((value, index) => ({
key: getFriendlyName(cols[index]),
key: getColumnDisplayName(cols[index]),
value: value,
col: cols[index],
}));
......@@ -140,12 +160,12 @@ function applyChartTooltips(
data = [
{
key: getFriendlyName(cols[0]),
key: getColumnDisplayName(cols[0]),
value: d.data.key,
col: cols[0],
},
{
key: getFriendlyName(cols[1]),
key: getColumnDisplayName(cols[1]),
value: isNormalized
? formatValue(d.data.value, {
number_style: "percent",
......@@ -156,6 +176,10 @@ function applyChartTooltips(
},
];
// NOTE: The below overcomplicated code is due to using index (i) of
// the element in the DOM, as returned by d3
// It would be much preferable to somehow get the row more directly
// now add entries to the tooltip for columns that aren't the X or Y axis. These aren't in
// the normal `cols` array, which is just the cols used in the graph axes; look in `_rawCols`
// for any other columns. If we find them, add them at the end of the `data` array.
......@@ -204,7 +228,7 @@ function applyChartTooltips(
}
// otherwise just create a new object for any other columns.
return {
key: getFriendlyName(col),
key: getColumnDisplayName(col),
value: rawRow[i],
col: col,
};
......@@ -212,14 +236,14 @@ function applyChartTooltips(
}
}
if (data && series.length > 1) {
if (card._breakoutColumn) {
data.unshift({
key: getFriendlyName(card._breakoutColumn),
value: card._breakoutValue,
col: card._breakoutColumn,
});
}
if (isBreakoutMultiseries) {
data.unshift({
key: getFriendlyName(card._breakoutColumn),
// Use series title if it's set
value: seriesTitle ? seriesTitle : card._breakoutValue,
// Don't include the column if series title is set (it's already formatted)
col: seriesTitle ? null : card._breakoutColumn,
});
}
data = _.uniq(data, d => d.col);
......
......@@ -13,10 +13,50 @@ const DEFAULT_SETTINGS = {
"graph.x_axis.axis_enabled": true,
"graph.y_axis.axis_enabled": true,
"graph.colors": ["#00FF00", "#FF0000"],
series: () => ({ display: "bar" }),
column: () => ({ date_style: "MMMM D, YYYY" }),
series: () => DEFAULT_SERIES_SETTINGS,
column: () => DEFAULT_COLUMN_SETTINGS,
};
const DEFAULT_SERIES_SETTINGS = {
display: "bar",
};
const DEFAULT_COLUMN_SETTINGS = {
date_style: "MMMM D, YYYY",
};
function MainSeries(chartType, settings = {}) {
return {
card: {
display: chartType,
visualization_settings: {
...DEFAULT_SETTINGS,
...settings,
},
},
data: {
cols: [
StringColumn({ display_name: "Category", source: "breakout" }),
NumberColumn({ display_name: "Sum", source: "aggregation" }),
],
rows: [["A", 1]],
},
};
}
function ExtraSeries() {
return {
card: {},
data: {
cols: [
StringColumn({ display_name: "Category", source: "breakout" }),
NumberColumn({ display_name: "Count", source: "aggregation" }),
],
rows: [["A", 2]],
},
};
}
describe("LineAreaBarRenderer-bar", () => {
let element;
const qsa = selector => [...element.querySelectorAll(selector)];
......@@ -33,86 +73,115 @@ describe("LineAreaBarRenderer-bar", () => {
document.body.removeChild(document.getElementById("fixture"));
});
["area", "bar"].forEach(chartType =>
["stacked", "normalized"].forEach(stack_type =>
// FIXME: failing on CI
xit(`should render a ${stack_type ||
""} ${chartType} chart with 2 series`, () => {
const onHoverChange = jest.fn();
renderLineAreaBar(
element,
[
{
card: {
display: chartType,
visualization_settings: {
...DEFAULT_SETTINGS,
"stackable.stack_type": stack_type,
},
},
data: {
cols: [
StringColumn({
display_name: "Category",
source: "breakout",
}),
NumberColumn({
display_name: "Sum",
source: "aggregation",
}),
],
rows: [["A", 1]],
},
},
{
card: {},
data: {
cols: [
StringColumn({
display_name: "Category",
source: "breakout",
}),
NumberColumn({
display_name: "Count",
source: "aggregation",
}),
],
rows: [["A", 2]],
},
},
],
{
onHoverChange,
},
);
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
dispatchUIEvent(qsa(".bar, .dot")[1], "mousemove");
const { calls } = onHoverChange.mock;
if (stack_type === "normalized") {
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "% Sum", value: "33%" },
]);
expect(getDataKeyValues(calls[1][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "% Count", value: "67%" },
]);
} else {
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Sum", value: 1 },
]);
expect(getDataKeyValues(calls[1][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Count", value: 2 },
]);
}
}),
),
);
it(`should render an bar chart with 1 series`, () => {
const onHoverChange = jest.fn();
renderLineAreaBar(element, [MainSeries("bar")], {
onHoverChange,
});
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
const { calls } = onHoverChange.mock;
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Sum", value: 1 },
]);
});
it(`should render an bar chart with 2 series`, () => {
const onHoverChange = jest.fn();
renderLineAreaBar(element, [MainSeries("bar"), ExtraSeries()], {
onHoverChange,
});
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
dispatchUIEvent(qsa(".bar, .dot")[1], "mousemove");
const { calls } = onHoverChange.mock;
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Sum", value: 1 },
]);
expect(getDataKeyValues(calls[1][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Count", value: 2 },
]);
});
it(`should render an bar stacked chart with 2 series`, () => {
const onHoverChange = jest.fn();
renderLineAreaBar(
element,
[MainSeries("bar", { "stackable.stack_type": "stacked" }), ExtraSeries()],
{
onHoverChange,
},
);
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
dispatchUIEvent(qsa(".bar, .dot")[1], "mousemove");
const { calls } = onHoverChange.mock;
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Sum", value: 1 },
]);
expect(getDataKeyValues(calls[1][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Count", value: 2 },
]);
});
it(`should render an bar normalized chart with 2 series`, () => {
const onHoverChange = jest.fn();
renderLineAreaBar(
element,
[
MainSeries("bar", { "stackable.stack_type": "normalized" }),
ExtraSeries(),
],
{ onHoverChange },
);
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
dispatchUIEvent(qsa(".bar, .dot")[1], "mousemove");
const { calls } = onHoverChange.mock;
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "% Sum", value: "33%" },
]);
expect(getDataKeyValues(calls[1][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "% Count", value: "67%" },
]);
});
it("should replace the aggregation name with the series name", () => {
const onHoverChange = jest.fn();
renderLineAreaBar(
element,
[
MainSeries("bar", {
series: () => ({ ...DEFAULT_SERIES_SETTINGS, title: "Foo" }),
}),
],
{ onHoverChange },
);
// hover over each bar
dispatchUIEvent(qsa(".bar, .dot")[0], "mousemove");
const { calls } = onHoverChange.mock;
expect(getDataKeyValues(calls[0][0])).toEqual([
{ key: "Category", value: "A" },
{ key: "Foo", value: 1 },
]);
});
});
function getDataKeyValues(hover) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment