From 3d63772cdc63298ac4445a4c44f04340155795e5 Mon Sep 17 00:00:00 2001 From: NarasimhaShenoi <53594676+NarasimhaShenoi@users.noreply.github.com> Date: Thu, 9 Jul 2020 22:08:32 +0530 Subject: [PATCH] New: Suppressing Legend Items (#251) --- dev/app.js | 6 ++ dev/examples/controls/line.js | 18 +++++ dev/examples/data.js | 15 +++- docs/controls/Bar.md | 19 ++++- docs/controls/Bubble.md | 21 +++-- docs/controls/Line.md | 19 ++--- docs/controls/PairedResult.md | 40 ++++++++-- docs/controls/Scatter.md | 27 +++++-- src/main/js/helpers/legend.js | 16 +++- src/test/unit/controls/Line/LineLoad-spec.js | 81 ++++++++++++++++++++ 10 files changed, 226 insertions(+), 36 deletions(-) diff --git a/dev/app.js b/dev/app.js index e58b89b5c..20c2ee5b5 100644 --- a/dev/app.js +++ b/dev/app.js @@ -89,6 +89,7 @@ import { renderLineWithShapesShownPerDataSet, renderDisableCalibration, renderLineGraphAndLegendPaddingReduced, + renderSuppressLegend, renderLineWithSuppressedTrailingZeros } from "./examples/controls/line"; import { @@ -251,6 +252,11 @@ renderSiteApp( pathname: "/line/suppress-tick-values-trailing-zeros", content: renderLineWithSuppressedTrailingZeros, title: "Suppress Tick Values Trailing Zeros" + }, + { + pathname: "/line/Suppress-legend", + content: renderSuppressLegend, + title: "Suppress Legend" } ] }, diff --git a/dev/examples/controls/line.js b/dev/examples/controls/line.js index 3ea0f39b1..ff35a098c 100644 --- a/dev/examples/controls/line.js +++ b/dev/examples/controls/line.js @@ -579,6 +579,24 @@ export const renderLineGraphAndLegendPaddingReduced = (id) => { ); return lineTime; }; +export const renderSuppressLegend = (id) => { + const lineDefault = Carbon.api.graph(getDemoData(`#${id}`, "LINE_DEFAULT")); + lineDefault.loadContent( + Carbon.api.line(getDemoData(`#${id}`, "LINE_DEFAULT").data[0]) + ); + setTimeout( + () => + lineDefault.graphContainer + ? lineDefault.loadContent( + Carbon.api.line( + getDemoData(`#${id}`, "LINE_DEFAULT").data[7] + ) + ) + : "", + 750 + ); + return lineDefault; +}; export const renderLineWithSuppressedTrailingZeros = (id) => { const axisData = utils.deepClone( getDemoData(`#${id}`, "LINE_DECIMAL_AXES_VALUES") diff --git a/dev/examples/data.js b/dev/examples/data.js index b335e1570..57442cc4c 100644 --- a/dev/examples/data.js +++ b/dev/examples/data.js @@ -144,7 +144,20 @@ const DATA = [ y: Math.cos(i) * Math.PI * 7, x: 85 + i * 10 })) - } + }, + { + key: "uid_8", + label: { + display: "Data Label 8" + }, + shape: Carbon.helpers.SHAPES.DARK.TRIANGLE, + color: Carbon.helpers.COLORS.BLUE, + onClick: loadPopup, + values: [], + legendOptions: { + showElement: false, + } + }, ], showLabel: true, showLegend: true, diff --git a/docs/controls/Bar.md b/docs/controls/Bar.md index 486f63ddc..a44858a3f 100644 --- a/docs/controls/Bar.md +++ b/docs/controls/Bar.md @@ -209,13 +209,24 @@ Refer [Graph](../core/Graph.md) `Root` for more details. | Property Name | Expected | Default | Description | | ------------- | -------- | ------------ | ------------------------------------------------------------------------------ | -| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | -| regions | array | [] | Refer [Regions](#regions) | +| axisInfoRow | array | [] | Refer [Axis Info Row](#Axis-Info-Row) | | color | string | COLORS.BLACK | Color for the data point and line | +| group | string | key | Used for stacking bar content under another bar content. Refer [Group](#group) | +| legendOptions | object | undefined | Option to show legend. Refer [LegendOptions](#legendOptions) | | onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| regions | array | [] | Refer [Regions](#regions) | | style | object | {} | Any style that can be applied. Refer [Styles](#style) | -| group | string | key | Used for stacking bar content under another bar content. Refer [Group](#group) | -| axisInfoRow | array | [] | Refer [Axis Info Row](#Axis-Info-Row) | +| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | + +### LegendOptions + +Each bar can have a legendOptions object in [Values](#values) level. + +#### Optional + +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------- | ----------------------------------------------------- | +| showElement | boolean | true | Toggle to hide legend when legend item has no data. | ### Values diff --git a/docs/controls/Bubble.md b/docs/controls/Bubble.md index 4b9dd8e6a..d4a78a265 100644 --- a/docs/controls/Bubble.md +++ b/docs/controls/Bubble.md @@ -240,13 +240,24 @@ Refer [Graph](../core/Graph.md) `Root` for more details. | Property Name | Expected | Default | Description | | ------------- | -------- | ------------ | ----------------------------------------------------------------------------------------- | -| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | -| weight | object | {} | Provide min and max or maxRadius for weight based or custom sized bubble[Weight](#Weight) | -| hue | object | {} | Provide lowerShade and upperShadefor color based bubble [Hue](#Hue) | -| regions | array | [] | Refer [Regions](#regions) | -| label | object | {} | Display value for the data-set which the data points belong to | | color | string | COLORS.BLACK | Color for the bubbles | | onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| hue | object | {} | Provide lowerShade and upperShadefor color based bubble [Hue](#Hue) | +| label | object | {} | Display value for the data-set which the data points belong to | +| legendOptions | object | undefined | Toggle to show legend. Refer [LegendOptions](#legendOptions) | +| regions | array | [] | Refer [Regions](#regions) | +| weight | object | {} | Provide min and max or maxRadius for weight based or custom sized bubble[Weight](#Weight) | +| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | + +### LegendOptions + +Each bubble can have a legendOptions object in [Values](#values) level. + +#### Optional + +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------- | ----------------------------------------------------- | +| showElement | boolean | true | Toggle to hide legend when legend item has no data. | ### Weight diff --git a/docs/controls/Line.md b/docs/controls/Line.md index 316a7d66a..9c92218a3 100644 --- a/docs/controls/Line.md +++ b/docs/controls/Line.md @@ -174,16 +174,16 @@ Refer [Graph](../core/Graph.md) `Root` for more details. | Property Name | Expected | Default | Description | | ------------- | -------- | ------------------ | ---------------------------------------------------------------------------------------------- | -| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | -| type | string | LINE_TYPE.LINEAR | Nature of line that needs to be drawn (Linear or Cardinal) | -| regions | array | [] | Refer [Regions](#regions) | -| label | object | {} | Display value for the data-set which the data points belong to | | color | string | COLORS.BLACK | Color for the data point and line | -| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | +| label | object | {} | Display value for the data-set which the data points belong to | +| legendOptions | object | undefined | Toggle to show shape, line and legend. Refer [LegendOptions](#legendOptions) | | onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| regions | array | [] | Refer [Regions](#regions) | +| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | | style | object | {} | Any style that can be applied. Refer [Styles](#style) | -| legendOptions | object | undefined | Option to show/hide shape and/or line. Refer [LegendOptions](#legendOptions) | | showShapes | boolean | undefined | Option to show/hide shapes per data set. This option overrides the graph's showShapes property | +| type | string | LINE_TYPE.LINEAR | Nature of line that needs to be drawn (Linear or Cardinal) | +| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | ##### Style @@ -195,17 +195,18 @@ Each line can have a style object in [Values](#values) level. | --------------- | -------- | ------- | ------------------------------------------------------ | | strokeDashArray | string | "0" | Applies stroke-dasharray CSS property to the SVG line. | -##### LegendOptions +### LegendOptions Each line can have a legendOptions object in [Values](#values) level. -###### Required +#### Optional | Property Name | Expected | Default | Description | | ------------- | -------- | ------- | ----------------------------------------------------- | -| showShape | boolean | true | Display Shape in the legend. | | showLine | boolean | false | Display Line in the legend. | +| showShape | boolean | true | Display Shape in the legend. | | style | object | {} | Any style that can be applied. Refer [Styles](#style) | +| showElement | boolean | true | Toggle to hide legend when legend item has no data. | ### Values diff --git a/docs/controls/PairedResult.md b/docs/controls/PairedResult.md index 65557b146..3b8e320a6 100644 --- a/docs/controls/PairedResult.md +++ b/docs/controls/PairedResult.md @@ -108,16 +108,40 @@ Refer [Graph](../core/Graph.md) `Root` for more details. | key | string | Unique id which represents the data-set | | values | Array | [Values](#values) | +#### Optional + +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------------------ | ----------------------------------------------------------------------------------| +| color | string | COLORS.BLACK | Color for the data point | +| label | object | {} | Display value for the data-set which the data points belong to | +| legendOptions | object | undefined | Toggle to show shape, line and legend. Refer [LegendOptions](#legendOptions) | +| onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| regions | object | {} | Refer [Regions](#regions) | +| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | +| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | + +### LegendOptions + +Each paired result can have a legendOptions object in [Values](#values) level. + #### Optional -| Property Name | Expected | Default | Description | -| ------------- | -------- | ------------------ | --------------------------------------------------------------------- | -| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | -| regions | object | {} | Refer [Regions](#regions) | -| label | object | {} | Display value for the data-set which the data points belong to | -| color | string | COLORS.BLACK | Color for the data point | -| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | -| onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------- | ----------------------------------------------------- | +| showLine | boolean | false | Display Line in the legend. | +| showShape | boolean | true | Display Shape in the legend. | +| style | object | {} | Any style that can be applied. Refer [Styles](#style) | +| showElement | boolean | true | Toggle to hide legend when legend item has no data. | + +##### Style + +Each paired result can have a style object in [Values](#values) level. + +###### Optional + +| Property Name | Expected | Default | Description | +| --------------- | -------- | ------- | ------------------------------------------------------ | +| strokeDashArray | string | "0" | Applies stroke-dasharray CSS property to the SVG line. | ### Values diff --git a/docs/controls/Scatter.md b/docs/controls/Scatter.md index fdaf494d8..f4ef4d2f8 100644 --- a/docs/controls/Scatter.md +++ b/docs/controls/Scatter.md @@ -140,14 +140,15 @@ Refer [Graph](../core/Graph.md) `Root` for more details. #### Optional -| Property Name | Expected | Default | Description | -| ------------- | -------- | ------------------ | --------------------------------------------------------------------- | -| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | -| regions | array | [] | Refer [Regions](#regions) | -| label | object | {} | Display value for the data-set which the data points belong to | -| color | string | COLORS.BLACK | Color for the data point | -| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | -| onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------------------ | --------------------------------------------------------------------------------- | +| color | string | COLORS.BLACK | Color for the data point | +| label | object | {} | Display value for the data-set which the data points belong to | +| legendOptions | object | undefined | Toggle to show legend. Refer [LegendOptions](#legendOptions) | +| onClick | Function | undefined | Any action that can be performed when clicking on the data point | +| regions | array | [] | Refer [Regions](#regions) | +| shape | string | SHAPES.DARK.CIRCLE | Shape for representing the data points | +| yAxis | string | "y" | Setting for using different Y based axis. For now: its either Y or Y2 | ### Values @@ -164,6 +165,16 @@ Refer [Graph](../core/Graph.md) `Root` for more details. | ------------- | -------- | ------- | ---------------------------------------------------------- | | isCritical | boolean | `false` | Shows an indicator surrounding the data point when enabled | +### LegendOptions + +Each scatter can have a legendOptions object in [Values](#values) level. + +#### Optional + +| Property Name | Expected | Default | Description | +| ------------- | -------- | ------- | ----------------------------------------------------- | +| showElement | boolean | true | Toggle to hide legend when legend item has no data. | + ### Regions Each data-set can have 1 or more regions. `start` and `end` is necessary for rendering a horizontal area. diff --git a/src/main/js/helpers/legend.js b/src/main/js/helpers/legend.js index a7de05e77..fe4335357 100644 --- a/src/main/js/helpers/legend.js +++ b/src/main/js/helpers/legend.js @@ -44,6 +44,14 @@ const validateLegendLabel = (label) => { * @returns {string} Sanitized text */ const getText = (text) => utils.sanitize(text); +/** + * Hide legend when legend item has no data and showElement is set to false + * + * @private + * @param {object} input item object processed from the input JSON + * @returns {string} returns "none" if legend is to be hidden otherwise returns empty string + */ +const legendDisplayStyle = (input) => input.legendOptions && input.legendOptions.showElement === false && utils.isEmptyArray(input.values)? "none": ""; /** * Loads the legend items. The values are taken from the Labels property of the input JSON * The click and the hover events are only registered when there are datapoints matching the @@ -78,6 +86,7 @@ const loadLegendItem = (legendSVG, t, config, eventHandlers) => { .classed(styles.legendItem, true) .attr("aria-current", shouldForceDisableLegendItem || index > -1) .attr("aria-disabled", shouldForceDisableLegendItem) + .style("display", legendDisplayStyle(t)) .attr("role", "listitem") .attr("aria-labelledby", text) .attr("aria-describedby", t.key) @@ -125,6 +134,7 @@ const loadLegendItem = (legendSVG, t, config, eventHandlers) => { */ const processLegendOptions = (buttonPath, input) => { if (input.legendOptions) { + // Create a legend icon only if the showShape is true if (input.legendOptions.showShape) { createLegendIcon(buttonPath, input); } @@ -385,8 +395,12 @@ const loadPieLegendItem = (legendSVG, dataTarget, { hoverHandler }, config) => { const getDefaultLegendOptions = (graphConfig, dataTarget) => { const legendOptions = getDefaultValue(dataTarget.legendOptions, { showShape: true, - showLine: false + showLine: false, + showElement: true }); + legendOptions.showShape = getDefaultValue(legendOptions.showShape, true); + legendOptions.showLine = getDefaultValue(legendOptions.showLine, false); + legendOptions.showElement = getDefaultValue(legendOptions.showElement, true); legendOptions.style = getDefaultValue(legendOptions.style, {}); legendOptions.style = { strokeDashArray: getStrokeDashArray(legendOptions.style) diff --git a/src/test/unit/controls/Line/LineLoad-spec.js b/src/test/unit/controls/Line/LineLoad-spec.js index ea36bd70b..768d5cabc 100644 --- a/src/test/unit/controls/Line/LineLoad-spec.js +++ b/src/test/unit/controls/Line/LineLoad-spec.js @@ -1226,6 +1226,87 @@ describe("Line - Load", () => { done(); }); }); + describe("when the legend has no data", () => { + it ("should hide the legend if showElement is false", () => { + const input = getInput([], false, false); + input.legendOptions = { + showElement: false + } + graphDefault.loadContent(new Line(input)); + const legendContainer = fetchElementByClass( + lineGraphContainer, + styles.legendItem + ); + expect(legendContainer).not.toBeNull(); + expect(legendContainer.tagName).toBe("LI"); + const legendItem = document.body.querySelector( + `.${styles.legendItem}` + ); + expect(legendItem.getAttribute("style")).toBe("display: none; padding: 4px 8px;"); + }); + it ("should show the legend if showElement is true", () => { + const input = getInput([], false, false); + input.legendOptions = { + showElement: true, + } + graphDefault.loadContent(new Line(input)); + const legendContainer = fetchElementByClass( + lineGraphContainer, + styles.legendItem + ); + const legendItems = legendContainer.children; + expect(legendContainer).not.toBeNull(); + expect(legendContainer.tagName).toBe("LI"); + expect(legendItems.length).toBe(2); + const legendItem = document.body.querySelector( + `.${styles.legendItem}` + ); + expect(legendItem.getAttribute("aria-disabled")).toBe("true"); + expect(legendItem.getAttribute("aria-current")).toBe("true"); + }); + }); + describe("when the legend has data", () => { + it ("should show the legend if showElement is false", () => { + const input = getInput(valuesDefault, false, false); + input.legendOptions = { + showElement: true, + } + graphDefault.loadContent(new Line(input)); + const legendContainer = fetchElementByClass( + lineGraphContainer, + styles.legendItem + ); + const legendItems = legendContainer.children; + expect(legendContainer).not.toBeNull(); + expect(legendContainer.tagName).toBe("LI"); + expect(legendItems.length).toBe(2); + const legendItem = document.body.querySelector( + `.${styles.legendItem}` + ); + expect(legendItem.getAttribute("aria-disabled")).toBe("false"); + expect(legendItem.getAttribute("aria-current")).toBe("true"); + }); + it ("should show the legend if showElement is true", () => { + const input = getInput(valuesDefault, false, false); + input.legendOptions = { + showElement: true, + } + graphDefault.loadContent(new Line(input)); + const legendContainer = fetchElementByClass( + lineGraphContainer, + styles.legend + ); + const legendItems = legendContainer.children; + expect(legendContainer).not.toBeNull(); + expect(legendContainer.tagName).toBe("UL"); + expect(legendItems.length).toBe(1); + const legendItem = document.body.querySelector( + `.${styles.legendItem}` + ); + expect(legendItem.getAttribute("aria-disabled")).toBe("false"); + expect(legendItem.getAttribute("aria-current")).toBe("true"); + }); + }); }); describe("Prepares to load label shape", () => { let graph;