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 implementation of scorecard/summary table functionality #313

Merged
merged 19 commits into from
Aug 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
102 changes: 100 additions & 2 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{ "displayName": "Outcome/Numerator", "name": "numerators", "kind": "Measure" },
{ "displayName": "Denominator", "name": "denominators", "kind": "Measure" },
{ "displayName": "ID Key (Date)", "name": "key", "kind": "Grouping" },
{ "displayName": "Indicator", "name": "indicator", "kind": "Grouping" },
{ "displayName": "Grouping (Summary Table)", "name": "indicator", "kind": "Grouping" },
{ "displayName": "Rebaseline Groupings", "name": "groupings", "kind": "Measure" },
{ "displayName": "SD (for xbar)", "name": "xbar_sds", "kind": "Measure" },
{ "displayName": "Tooltips", "name": "tooltips", "kind": "Measure" }
Expand Down Expand Up @@ -117,7 +117,7 @@
}
},
"outliers" : {
"displayName": "Outlier Highlighting",
"displayName": "Outlier Detection",
"properties": {
"process_flag_type": {
"displayName": "Type of Change to Flag",
Expand Down Expand Up @@ -759,6 +759,104 @@
"show_table": {
"displayName": "Show Summary Table",
"type" : { "bool" : true }
},
"table_header_font": {
"displayName": "Header Font",
"type": { "formatting": { "fontFamily": true } }
},
"table_header_size": {
"displayName": "Header Font Size",
"type": { "formatting": { "fontSize": true } }
},
"table_header_colour":{
"displayName": "Header Font Colour",
"type": { "fill": { "solid": { "color": true } } }
},
"table_header_bg_colour":{
"displayName": "Header Background Colour",
"type": { "fill": { "solid": { "color": true } } }
},
"table_header_font_weight": {
"displayName": "Header Font Weight",
"type": {
"enumeration" : [
{ "displayName" : "Normal", "value" : "normal" },
{ "displayName" : "Bold", "value" : "bold" }
]
}
},
"table_header_text_transform": {
"displayName": "Header Text Transform",
"type": {
"enumeration" : [
{ "displayName" : "Uppercase", "value" : "uppercase" },
{ "displayName" : "Lowercase", "value" : "lowercase" },
{ "displayName" : "Capitalise", "value" : "capitalize" },
{ "displayName" : "None", "value" : "none" }
]
}
},
"table_header_text_align": {
"displayName": "Text Alignment",
"type": { "formatting": { "alignment": true } }
},
"table_body_font": {
"displayName": "Body Font",
"type": { "formatting": { "fontFamily": true } }
},
"table_body_size": {
"displayName": "Body Font Size",
"type": { "formatting": { "fontSize": true } }
},
"table_body_colour":{
"displayName": "Body Font Colour",
"type": { "fill": { "solid": { "color": true } } }
},
"table_body_bg_colour":{
"displayName": "Body Background Colour",
"type": { "fill": { "solid": { "color": true } } }
},
"table_body_font_weight": {
"displayName": "Font Weight",
"type": {
"enumeration" : [
{ "displayName" : "Normal", "value" : "normal" },
{ "displayName" : "Bold", "value" : "bold" }
]
}
},
"table_body_text_transform": {
"displayName": "Text Transform",
"type": {
"enumeration" : [
{ "displayName" : "Uppercase", "value" : "uppercase" },
{ "displayName" : "Lowercase", "value" : "lowercase" },
{ "displayName" : "Capitalise", "value" : "capitalize" },
{ "displayName" : "None", "value" : "none" }
]
}
},
"table_body_text_align": {
"displayName": "Text Alignment",
"type": { "formatting": { "alignment": true } }
},
"table_opacity": {
"displayName": "Opacity",
"type": { "numeric": true }
},
"table_opacity_unselected": {
"displayName": "Opacity if Unselected",
"type": { "numeric": true }
},
"table_text_overflow": {
"displayName": "Text Overflow Handling",
"type": {
"enumeration" : [
{ "displayName" : "Ellipsis", "value" : "ellipsis" },
{ "displayName" : "Truncate", "value" : "clip" },
{ "displayName" : "None", "value" : "none" }
]
}
}
}
},
Expand Down
10 changes: 6 additions & 4 deletions src/Classes/derivedSettingsClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class derivedSettingsClass {
multiplier: number
percentLabels: boolean
chart_type_props: {
name: string,
needs_denominator: boolean,
denominator_optional: boolean,
numerator_non_negative: boolean,
Expand All @@ -31,11 +32,11 @@ export default class derivedSettingsClass {
value_name: string
}

update(inputSettings: defaultSettingsType) {
const chartType: string = inputSettings.spc.chart_type;
update(inputSettingsSpc: defaultSettingsType["spc"]) {
const chartType: string = inputSettingsSpc.chart_type;
const pChartType: boolean = ["p", "pp"].includes(chartType);
const percentSettingString: string = inputSettings.spc.perc_labels;
let multiplier: number = inputSettings.spc.multiplier;
const percentSettingString: string = inputSettingsSpc.perc_labels;
let multiplier: number = inputSettingsSpc.multiplier;
let percentLabels: boolean;

if (percentSettingString === "Yes") {
Expand All @@ -53,6 +54,7 @@ export default class derivedSettingsClass {
}

this.chart_type_props = {
name: chartType,
needs_denominator: ["p", "pp", "u", "up", "xbar", "s"].includes(chartType),
denominator_optional: ["i", "i_m", "i_mm", "run", "mr"].includes(chartType),
numerator_non_negative: ["p", "pp", "u", "up", "s", "c", "g", "t"].includes(chartType),
Expand Down
14 changes: 4 additions & 10 deletions src/Classes/plotPropertiesClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,22 @@ export type axisProperties = {
};

export default class plotPropertiesClass {
width: number;
height: number;
displayPlot: boolean;
xAxis: axisProperties;
yAxis: axisProperties;
xScale: d3.ScaleLinear<number, number, never>;
yScale: d3.ScaleLinear<number, number, never>;

// Separate function so that the axis can be re-calculated on changes to padding
initialiseScale(): void {
initialiseScale(svgWidth: number, svgHeight: number): void {
this.xScale = d3.scaleLinear()
.domain([this.xAxis.lower, this.xAxis.upper])
.range([this.xAxis.start_padding,
this.width - this.xAxis.end_padding]);
svgWidth - this.xAxis.end_padding]);

this.yScale = d3.scaleLinear()
.domain([this.yAxis.lower, this.yAxis.upper])
.range([this.height - this.yAxis.start_padding,
.range([svgHeight - this.yAxis.start_padding,
this.yAxis.end_padding]);
}

Expand All @@ -53,10 +51,6 @@ export default class plotPropertiesClass {
derivedSettings: derivedSettingsClass,
colorPalette: colourPaletteType): void {

// Get the width and height of plotting space
this.width = options.viewport.width;
this.height = options.viewport.height;

this.displayPlot = plotPoints
? plotPoints.length > 1
: null;
Expand Down Expand Up @@ -154,6 +148,6 @@ export default class plotPropertiesClass {
label_colour: colorPalette.isHighContrast ? colorPalette.foregroundColour : inputSettings.y_axis.ylimit_label_colour
};

this.initialiseScale();
this.initialiseScale(options.viewport.width, options.viewport.height);
}
}
43 changes: 41 additions & 2 deletions src/Classes/settingsClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type DataViewPropertyValue = powerbi.default.DataViewPropertyValue
type VisualObjectInstanceEnumerationObject = powerbi.default.VisualObjectInstanceEnumerationObject;
type VisualObjectInstance = powerbi.default.VisualObjectInstance;
type VisualObjectInstanceContainer = powerbi.default.VisualObjectInstanceContainer;
import { extractConditionalFormatting } from "../Functions";
import { extractConditionalFormatting, isNullOrUndefined } from "../Functions";
import { default as defaultSettings, type settingsValueTypes, settingsPaneGroupings, settingsPaneToggles } from "../defaultSettings";
import derivedSettingsClass from "./derivedSettingsClass";
import { type ConditionalReturnT, type SettingsValidationT } from "../Functions/extractConditionalFormatting";
Expand All @@ -19,6 +19,10 @@ export type defaultSettingsKey = keyof defaultSettingsType;
export type defaultSettingsNestedKey = NestedKeysOf<defaultSettingsType[defaultSettingsKey]>;
export type settingsScalarTypes = number | string | boolean;

export type optionalSettingsTypes = Partial<{
[K in keyof typeof defaultSettings]: Partial<defaultSettingsType[K]>;
}>;

export type paneGroupingsNestedKey = "all" | NestedKeysOf<typeof settingsPaneGroupings[keyof typeof settingsPaneGroupings]>;
export type paneTogglesNestedKey = "all" | NestedKeysOf<typeof settingsPaneToggles[keyof typeof settingsPaneToggles]>;

Expand All @@ -33,6 +37,8 @@ export default class settingsClass {
settings: defaultSettingsType;
derivedSettings: derivedSettingsClass;
validationStatus: SettingsValidationT;
settingsGrouped: defaultSettingsType[];
derivedSettingsGrouped: derivedSettingsClass[];

/**
* Function to read the values from the settings pane and update the
Expand All @@ -46,6 +52,22 @@ export default class settingsClass {
// Get the names of all classes in settingsObject which have values to be updated
const allSettingGroups: string[] = Object.keys(this.settings);

const is_grouped: boolean = inputView.categorical.values?.source?.roles?.indicator;
let group_idxs: number[] = new Array<number>();
this.settingsGrouped = new Array<defaultSettingsType>();
if (is_grouped) {
group_idxs = inputView.categorical.values.grouped().map(d => {
this.settingsGrouped.push(Object.fromEntries(Object.keys(defaultSettings).map((settingGroupName) => {
return [settingGroupName, Object.fromEntries(Object.keys(defaultSettings[settingGroupName]).map((settingName) => {
return [settingName, defaultSettings[settingGroupName][settingName]];
}))];
})) as settingsValueTypes);

return d.values[0].values.findIndex(d_in => !isNullOrUndefined(d_in));
});
}


allSettingGroups.forEach((settingGroup: defaultSettingsKey) => {
const condFormatting: ConditionalReturnT<defaultSettingsType[defaultSettingsKey]>
= extractConditionalFormatting(inputView?.categorical, settingGroup, this.settings);
Expand Down Expand Up @@ -73,10 +95,27 @@ export default class settingsClass {
= condFormatting?.values
? condFormatting?.values[0][settingName]
: defaultSettings[settingGroup][settingName]["default"]

if (is_grouped) {
group_idxs.forEach((idx, idx_idx) => {
this.settingsGrouped[idx_idx][settingGroup][settingName]
= condFormatting?.values
? condFormatting?.values[idx][settingName]
: defaultSettings[settingGroup][settingName]["default"]
})
}
})
})

this.derivedSettings.update(this.settings)
this.derivedSettings.update(this.settings.spc)
this.derivedSettingsGrouped = new Array<derivedSettingsClass>();
if (is_grouped) {
this.settingsGrouped.forEach((d) => {
const newDerived = new derivedSettingsClass();
newDerived.update(d.spc);
this.derivedSettingsGrouped.push(newDerived);
})
}
}

/**
Expand Down
Loading