Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial infrastructure for showing summary table instead of chart #280

Merged
merged 1 commit into from
Apr 6, 2024
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
9 changes: 9 additions & 0 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
{ "displayName": "Tooltips", "name": "tooltips", "kind": "Measure" }
],
"objects": {
"summary_table": {
"displayName": "Summary Table",
"properties": {
"show_table": {
"displayName": "Show Summary Table",
"type" : { "bool" : true }
}
}
},
"split_indexes_storage" : {
"displayName" : "Hidden",
"properties": {
Expand Down
36 changes: 36 additions & 0 deletions src/Classes/viewModelClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,28 @@ export type lineData = {
group: string;
}

export type summaryTableRowData = {
date: string;
numerator: number;
denominator: number;
value: number;
target: number;
alt_target: number;
ll99: number;
ll95: number;
ll68: number;
ul68: number;
ul95: number;
ul99: number;
speclimits_lower: number;
speclimits_upper: number;
}

export type plotData = {
x: number;
value: number;
aesthetics: defaultSettingsType["scatter"];
table_row: summaryTableRowData;
// ISelectionId allows the visual to report the selection choice to PowerBI
identity: ISelectionId;
// Flag for whether dot should be highlighted by selections in other charts
Expand Down Expand Up @@ -205,10 +223,28 @@ export default class viewModelClass {
"ast_colour", this.inputSettings.settings) as string;
}

const table_row: summaryTableRowData = {
date: this.controlLimits.keys[i].label,
numerator: this.controlLimits.numerators?.[i],
denominator: this.controlLimits.denominators?.[i],
value: this.controlLimits.values[i],
target: this.controlLimits.targets[i],
alt_target: this.controlLimits.alt_targets[i],
ll99: this.controlLimits?.ll99?.[i],
ll95: this.controlLimits?.ll95?.[i],
ll68: this.controlLimits?.ll68?.[i],
ul68: this.controlLimits?.ul68?.[i],
ul95: this.controlLimits?.ul95?.[i],
ul99: this.controlLimits?.ul99?.[i],
speclimits_lower: this.controlLimits?.speclimits_lower?.[i],
speclimits_upper: this.controlLimits?.speclimits_upper?.[i]
}

this.plotPoints.push({
x: index,
value: this.controlLimits.values[i],
aesthetics: aesthetics,
table_row: table_row,
identity: host.createSelectionIdBuilder()
.withCategory(this.inputData.categories,
this.inputData.limitInputArgs.keys[i].id)
Expand Down
32 changes: 32 additions & 0 deletions src/D3 Plotting Functions/drawSummaryTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { plotData } from "../Classes/viewModelClass";
import type { divBaseType, Visual } from "../visual";

export default function drawSummaryTable(selection: divBaseType, visualObj: Visual) {
selection.select("svg").attr("width", 0).attr("height", 0);

if (selection.select(".table-group").empty()) {
const table = selection.append("table").classed("table-group", true);
table.append("thead")
.append("tr")
.classed("table-header", true);
table.append('tbody')
.classed("table-body", true);
}

const plotPoints: plotData[] = visualObj.viewModel.plotPoints;

selection.select(".table-header")
.selectAll("th")
.data(Object.keys(plotPoints[0].table_row))
.join("th")
.text((d) => d);

selection.select(".table-body")
.selectAll('tr')
.data(plotPoints)
.join('tr')
.selectAll('td')
.data((d) => Object.values(d.table_row))
.join('td')
.text((d) => d);
}
1 change: 1 addition & 0 deletions src/D3 Plotting Functions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { default as drawYAxis } from "./drawYAxis"
export { default as updateHighlighting } from "./updateHighlighting"
export { default as drawErrors } from "./drawErrors"
export { default as initialiseSVG } from "./initialiseSVG"
export { default as drawSummaryTable } from "./drawSummaryTable"
3 changes: 3 additions & 0 deletions src/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ const defaultSettings = {
date_format_year: { default: "YYYY", valid: ["YYYY", "YY", "(blank)"]},
date_format_delim: { default: "/", valid: ["/", "-", " "]},
date_format_locale: { default: "en-GB", valid: ["en-GB", "en-US"]}
},
summary_table: {
show_table: { default: false }
}
};

Expand Down
61 changes: 38 additions & 23 deletions src/visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@
import type powerbi from "powerbi-visuals-api";
type EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
type VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
type VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import * as d3 from "./D3 Plotting Functions/D3 Modules";
import { drawXAxis, drawYAxis, drawTooltipLine, drawLines,
drawDots, drawIcons, updateHighlighting, addContextMenu,
drawErrors, initialiseSVG } from "./D3 Plotting Functions"
drawErrors, initialiseSVG, drawSummaryTable } from "./D3 Plotting Functions"
import { defaultSettingsKey, viewModelClass } from "./Classes"
import { validateDataView } from "./Functions";

export type svgBaseType = d3.Selection<SVGSVGElement, unknown, null, undefined>;
export type divBaseType = d3.Selection<HTMLDivElement, unknown, null, undefined>;

export class Visual implements powerbi.extensibility.IVisual {
host: powerbi.extensibility.visual.IVisualHost;
div: divBaseType;
svg: svgBaseType;
viewModel: viewModelClass;
selectionManager: powerbi.extensibility.ISelectionManager;

constructor(options: powerbi.extensibility.visual.VisualConstructorOptions) {
this.svg = d3.select(options.element).append("svg");
this.div = d3.select(options.element).append("div");
this.svg = this.div.append("svg");
this.host = options.host;
this.viewModel = new viewModelClass();

Expand All @@ -30,48 +34,48 @@ export class Visual implements powerbi.extensibility.IVisual {
this.svg.call(initialiseSVG);
}

public update(options: powerbi.extensibility.visual.VisualUpdateOptions) {
public update(options: VisualUpdateOptions) {
try {
this.host.eventService.renderingStarted(options);
// Remove printed error if refreshing after a previous error run
this.svg.select(".errormessage").remove();
this.svg.attr("width", options.viewport.width)
.attr("height", options.viewport.height)

this.viewModel.inputSettings.update(options.dataViews[0]);
if (this.viewModel.inputSettings.validationStatus.error !== "") {
this.svg.call(drawErrors, options, this.viewModel.inputSettings.validationStatus.error, "settings");
this.host.eventService.renderingFinished(options);
this.processVisualError(options,
this.viewModel.inputSettings.validationStatus.error,
"settings");
return;
}

const checkDV: string = validateDataView(options.dataViews,
this.viewModel.inputSettings);
if (checkDV !== "valid") {
if (this.viewModel.inputSettings.settings.canvas.show_errors) {
this.svg.call(drawErrors, options, checkDV);
} else {
this.svg.call(initialiseSVG, true);
}
this.host.eventService.renderingFinished(options);
this.processVisualError(options, checkDV);
return;
}

this.viewModel.update(options, this.host);
if (this.viewModel.inputData.validationStatus.status !== 0) {
this.svg.call(drawErrors, options, this.viewModel.inputData.validationStatus.error);
this.host.eventService.renderingFinished(options);
this.processVisualError(options,
this.viewModel.inputData.validationStatus.error);
return;
}

this.svg.call(drawXAxis, this)
.call(drawYAxis, this)
.call(drawTooltipLine, this)
.call(drawLines, this)
.call(drawDots, this)
.call(drawIcons, this)
.call(updateHighlighting, this)
.call(addContextMenu, this)
if (this.viewModel.inputSettings.settings.summary_table.show_table) {
this.div.call(drawSummaryTable, this);
} else {
this.svg.attr("width", options.viewport.width)
.attr("height", options.viewport.height)
.call(drawXAxis, this)
.call(drawYAxis, this)
.call(drawTooltipLine, this)
.call(drawLines, this)
.call(drawDots, this)
.call(drawIcons, this)
.call(updateHighlighting, this)
.call(addContextMenu, this)
}

if (this.viewModel.inputData.warningMessage !== "") {
this.host.displayWarningIcon("Invalid inputs or settings ignored.\n",
Expand All @@ -86,6 +90,17 @@ export class Visual implements powerbi.extensibility.IVisual {
}
}

processVisualError(options: VisualUpdateOptions, message: string, type: string = null): void {
this.svg.attr("width", options.viewport.width)
.attr("height", options.viewport.height)
if (this.viewModel.inputSettings.settings.canvas.show_errors) {
this.svg.call(drawErrors, options, message, type);
} else {
this.svg.call(initialiseSVG, true);
}
this.host.eventService.renderingFinished(options);
}

// Function to render the properties specified in capabilities.json to the properties pane
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumerationObject {
return this.viewModel.inputSettings.createSettingsEntry(options.objectName as defaultSettingsKey);
Expand Down