diff --git a/CHANGELOG.md b/CHANGELOG.md index d16ed7a..bcc32bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.1.0 +* Fix x-axis settings +* Fix colors in high contrast mode + ## 3.0.0.0 * Update packages to the latest versions * Replace custom scroll with native diff --git a/README.md b/README.md index ed0485d..d542474 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # PowerBI-visuals-Tornado -[![build](https://github.com/microsoft/PowerBI-visuals-Tornado/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/microsoft/PowerBI-visuals-Tornado/actions/workflows/build.yml) +[![build](https://github.com/microsoft/PowerBI-visuals-Tornado/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/microsoft/PowerBI-visuals-Tornado/actions/workflows/build.yml) > A bar chart with category values listed vertically. Use for comparing the relative importance of a variable between two distinct groups. -![Tornado chart screenshot](https://github.com/microsoft/PowerBI-visuals-Tornado/blob/master/assets/screenshot.png?raw=true) +![Tornado chart screenshot](https://github.com/microsoft/PowerBI-visuals-Tornado/blob/main/assets/screenshot.png?raw=true) # Overview Tornado charts, are a special type of Bar chart, where the data categories are listed vertically instead of the standard horizontal presentation, and the categories are ordered so that the largest bar appears at the top of the chart, the second largest appears second from the top, and so on. They are so named because the final chart visually resembles either one half of or a complete tornado. diff --git a/package-lock.json b/package-lock.json index 144f978..2ca8faa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "powerbi-visuals-tornadochart", - "version": "3.0.0.0", + "version": "3.0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "powerbi-visuals-tornadochart", - "version": "3.0.0.0", + "version": "3.0.1.0", "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "^6.9.1", diff --git a/package.json b/package.json index 40ef0bf..fe09bad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "powerbi-visuals-tornadochart", - "version": "3.0.0.0", + "version": "3.0.1.0", "author": { "name": "Microsoft", "email": "pbicvsupport@microsoft.com" diff --git a/pbiviz.json b/pbiviz.json index 4398821..b70555f 100644 --- a/pbiviz.json +++ b/pbiviz.json @@ -1,10 +1,10 @@ { "visual": { "name": "TornadoChart", - "displayName": "Tornado 3.0.0.0", + "displayName": "Tornado 3.0.1.0", "guid": "TornadoChart1452517688218", "visualClassName": "TornadoChart", - "version": "3.0.0.0", + "version": "3.0.1.0", "description": "A bar chart with category values listed vertically. Use for comparing the relative importance of a variable between two distinct groups.", "supportUrl": "https://community.powerbi.com", "gitHubUrl": "https://github.com/Microsoft/PowerBI-visuals-Tornado" diff --git a/src/TornadoChart.ts b/src/TornadoChart.ts index 5f46d92..03fffbc 100644 --- a/src/TornadoChart.ts +++ b/src/TornadoChart.ts @@ -39,11 +39,13 @@ type Selection = d3Selection; import DataView = powerbiVisualsApi.DataView; import IViewport = powerbiVisualsApi.IViewport; +import DataViewObject = powerbiVisualsApi.DataViewObject; import DataViewObjects = powerbiVisualsApi.DataViewObjects; import DataViewObjectPropertyIdentifier = powerbiVisualsApi.DataViewObjectPropertyIdentifier; import DataViewValueColumn = powerbiVisualsApi.DataViewValueColumn; import DataViewCategorical = powerbiVisualsApi.DataViewCategorical; import DataViewValueColumns = powerbiVisualsApi.DataViewValueColumns; +import DataViewObjectWithId = powerbiVisualsApi.DataViewObjectWithId; import DataViewMetadataColumn = powerbiVisualsApi.DataViewMetadataColumn; import DataViewCategoryColumn = powerbiVisualsApi.DataViewCategoryColumn; import DataViewValueColumnGroup = powerbiVisualsApi.DataViewValueColumnGroup; @@ -214,7 +216,7 @@ export class TornadoChart implements IVisual { for (let seriesIndex = 0; seriesIndex < Math.min(values.length, TornadoChart.MaxSeries); seriesIndex++) { const columnGroup: DataViewValueColumnGroup = groupedValues && groupedValues.length > seriesIndex && groupedValues[seriesIndex].values ? groupedValues[seriesIndex] : null; - const parsedSeries: TornadoChartSeries = TornadoChart.parseSeries(dataView, values, hostService, seriesIndex, hasDynamicSeries, columnGroup, colors, formattingSettings); + const parsedSeries: TornadoChartSeries = TornadoChart.parseSeries(dataView, values, hostService, seriesIndex, hasDynamicSeries, columnGroup, colors); const currentSeries: DataViewValueColumn = values[seriesIndex]; const measureName: string = currentSeries.source.queryName; @@ -287,8 +289,7 @@ export class TornadoChart implements IVisual { index: number, isGrouped: boolean, columnGroup: DataViewValueColumnGroup, - colors: IColorPalette, - formattingSettings: TornadoChartSettingsModel): TornadoChartSeries { + colors: IColorPalette): TornadoChartSeries { if (!dataView) { return; @@ -308,15 +309,18 @@ export class TornadoChart implements IVisual { sourceGroupName = "" + source.groupName; } - let objects: DataViewObjects; + let objects: DataViewObjects, + categoryAxisObject: DataViewObject | DataViewObjectWithId[]; const displayName: PrimitiveValue = source ? sourceGroupName ? sourceGroupName : source.displayName : null; if (isGrouped && columnGroup && columnGroup.objects) { + categoryAxisObject = columnGroup.objects ? columnGroup.objects["categoryAxis"] : null; objects = columnGroup.objects; } else if (source && source.objects) { + categoryAxisObject = objects ? objects["categoryAxis"] : null; objects = source.objects; } else if (dataView && dataView.metadata && dataView.metadata.objects) { objects = dataView.metadata.objects; @@ -327,7 +331,12 @@ export class TornadoChart implements IVisual { ["purple", "teal"][index], objects, colors); - const categoryAxisEnd: number = formattingSettings.categoryAxisCardSettings.end.value; + let categoryAxisEnd: number = categoryAxisObject ? categoryAxisObject["end"] : null; + if(!categoryAxisEnd){ + if(objects?.categoryAxis?.end){ + categoryAxisEnd = objects.categoryAxis.end as number; + } + } return { fill: fillColor, @@ -991,7 +1000,7 @@ export class TornadoChart implements IVisual { labelSelectionMerged .select(TornadoChart.LabelText.selectorName) - .attr("fill", (p: TornadoChartPoint) => p.label.color) + .attr("fill", (p: TornadoChartPoint) => this.colorHelper.isHighContrast ? this.colorHelper.getHighContrastColor("foreground", p.color) : p.label.color) .attr("font-size", fontSizeInPx) .attr("font-family", labelFontFamily) .attr("font-weight", labelFontIsBold ? "bold" : "normal") @@ -1062,7 +1071,7 @@ export class TornadoChart implements IVisual { categoriesSelectionMerged .select(TornadoChart.CategoryText.selectorName) - .attr("fill", color) + .attr("fill", this.colorHelper.isHighContrast ? this.colorHelper.getHighContrastColor("foreground", color) : color) .attr("font-size", fontSizeInPx) .attr("font-family", categoryFontFamily) .attr("font-weight", categoryFontIsBold ? "bold" : "normal") @@ -1086,12 +1095,14 @@ export class TornadoChart implements IVisual { if (!legend) { return; } + + const legendLabelsColor: string = formattingSettings.legendCardSettings.labelColor.value.value; const legendData: LegendData = { title: legend.title, dataPoints: legend.dataPoints, fontSize: formattingSettings.legendCardSettings.font.fontSize.value, fontFamily: formattingSettings.legendCardSettings.font.fontFamily.value, - labelColor: formattingSettings.legendCardSettings.labelColor.value.value + labelColor: this.colorHelper.isHighContrast ? this.colorHelper.getHighContrastColor("foreground", legendLabelsColor) : legendLabelsColor }; if (this.dataView.legendObjectProperties) { @@ -1105,10 +1116,10 @@ export class TornadoChart implements IVisual { } this.legend.drawLegend(legendData, { ...this.viewport }); - d3Select(this.element.node()).selectAll("g#legendGroup text") - .style("font-weight", () => this.formattingSettings.legendCardSettings.font.bold.value ? "bold" : "normal") - .style("font-style", () => this.formattingSettings.legendCardSettings.font.italic.value ? "italic" : "normal") - .style("text-decoration", () => this.formattingSettings.legendCardSettings.font.underline.value ? "underline" : "none"); + this.element.selectAll("g#legendGroup text") + .style("font-weight", () => this.formattingSettings.legendCardSettings.font.bold.value ? "bold" : "normal") + .style("font-style", () => this.formattingSettings.legendCardSettings.font.italic.value ? "italic" : "normal") + .style("text-decoration", () => this.formattingSettings.legendCardSettings.font.underline.value ? "underline" : "none"); if (legendData.dataPoints.length > 0 && formattingSettings.legendCardSettings.show.value) { this.updateViewport(); diff --git a/src/TornadoChartSettingsModel.ts b/src/TornadoChartSettingsModel.ts index a17f476..6c4c286 100644 --- a/src/TornadoChartSettingsModel.ts +++ b/src/TornadoChartSettingsModel.ts @@ -34,17 +34,7 @@ class CategoryAxisCardSettings extends Card { name: "end", displayName: "End", displayNameKey: "Visual_XAxisEnd", - value: 0, - options: { - minValue: { - type: powerbiVisualsApi.visuals.ValidatorType.Min, - value: 0, - }, - maxValue: { - type: powerbiVisualsApi.visuals.ValidatorType.Max, - value: 25, - } - } + value: 0 }); name: string = "categoryAxis"; @@ -313,17 +303,7 @@ export class TornadoChartSettingsModel extends Model { value: dataPoint.categoryAxisEnd ? dataPoint.categoryAxisEnd : 0, selector: ColorHelper.normalizeSelector( dataPoint.selectionId.getSelector(), - false), - options: { - minValue: { - type: powerbiVisualsApi.visuals.ValidatorType.Min, - value: 0, - }, - maxValue: { - type: powerbiVisualsApi.visuals.ValidatorType.Max, - value: 25, - } - } + false) }) ); } diff --git a/src/TornadoWebBehavior.ts b/src/TornadoWebBehavior.ts index 0f5c833..1218668 100644 --- a/src/TornadoWebBehavior.ts +++ b/src/TornadoWebBehavior.ts @@ -69,7 +69,7 @@ export class TornadoWebBehavior implements IInteractiveBehavior { event.ctrlKey || event.metaKey || event.shiftKey); }); - this.columns.on("keypress", (event : KeyboardEvent, dataPoint: TornadoChartPoint) => { + this.columns.on("keydown", (event : KeyboardEvent, dataPoint: TornadoChartPoint) => { if(event?.code == "Enter" || event?.code == "Space") { selectionHandler.handleSelection( diff --git a/test/TornadoChartBuilder.ts b/test/TornadoChartBuilder.ts index 985b718..4e62db9 100644 --- a/test/TornadoChartBuilder.ts +++ b/test/TornadoChartBuilder.ts @@ -97,8 +97,7 @@ export class TornadoChartBuilder extends VisualBuilderBase { dataViewValueColumns: DataViewValueColumns, index: number, isGrouped: boolean, - columnGroup: DataViewValueColumnGroup, - formattingSettings: TornadoChartSettingsModel): TornadoChartSeries { + columnGroup: DataViewValueColumnGroup): TornadoChartSeries { return VisualClass.parseSeries( dataView, @@ -107,8 +106,7 @@ export class TornadoChartBuilder extends VisualBuilderBase { index, isGrouped, columnGroup, - this.visual.colors, - formattingSettings); + this.visual.colors); } public converter(dataView: DataView, formattingSettings: TornadoChartSettingsModel): TornadoChartDataView { diff --git a/test/visualTest.ts b/test/visualTest.ts index e0e1366..7ba8c76 100644 --- a/test/visualTest.ts +++ b/test/visualTest.ts @@ -167,15 +167,15 @@ describe("TornadoChart", () => { }); it("every argument is null", () => { - callParseSeriesAndExpectExceptions(null, null, null, null, null, null); + callParseSeriesAndExpectExceptions(null, null, null, null, null); }); it("every argument is undefined", () => { - callParseSeriesAndExpectExceptions(undefined, undefined, undefined, undefined, undefined, undefined); + callParseSeriesAndExpectExceptions(undefined, undefined, undefined, undefined, undefined); }); it("index is negative, other arguments are null", () => { - callParseSeriesAndExpectExceptions(null, null, -5, null, null, null); + callParseSeriesAndExpectExceptions(null, null, -5, null, null); }); it("every argument is correct", () => { @@ -185,8 +185,7 @@ describe("TornadoChart", () => { dataView.categorical!.values!, index, true, - dataView.categorical!.values!.grouped()[index], - visualBuilder.instance.formattingSettings)!; + dataView.categorical!.values!.grouped()[index])!; expect(series.categoryAxisEnd).toBeDefined(); expect(series.name).toBeDefined(); @@ -203,8 +202,7 @@ describe("TornadoChart", () => { dataViewValueColumns: DataViewValueColumns | null | undefined, index: number | null | undefined, isGrouped: boolean | null | undefined, - columnGroup: DataViewValueColumnGroup | null | undefined, - formattingSettings: TornadoChartSettingsModel | null | undefined): TornadoChartSeries | undefined { + columnGroup: DataViewValueColumnGroup | null | undefined): TornadoChartSeries | undefined { let series: TornadoChartSeries | undefined = undefined; expect(() => { @@ -213,8 +211,7 @@ describe("TornadoChart", () => { dataViewValueColumns!, index!, isGrouped!, - columnGroup!, - formattingSettings!); + columnGroup!); }).not.toThrow(); return series;