Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!
I have an R powered visual to which I would like add user parameters to change things like point color and weight for the plot.
As I have understood it, to do this I have to change the capabilities.json file and visual.ts
This is what i added in the capabilities.json
"objects": { "rcv_script": { "properties": { "provider": { "type": { "text": true } }, "source": { "type": { "scripting": { "source": true } } } } }, "settings_point_params": { "displayName": "Point aesthetics", "description": "Color and size", "properties":{ "pointColor":{ "displayName":"Point color", "description":"Point color", "type":{ "fill":{ "solid":{ "color": true } } } }, "weight":{ "displayName":"Weight", "description":"Weight", "type":{ "numeric":true } } } } }
And this is what I have in visual.ts
module powerbi.extensibility.visual { "use strict"; // below is a snippet of a definition for an object which will contain the property values // selected by the users /*interface VisualSettings { lineColor: string; }*/ // to allow this scenario you should first the following JSON definition to the capabilities.json file // under the "objects" property: // "settings": { // "displayName": "Visual Settings", // "description": "Visual Settings Tooltip", // "properties": { // "lineColor": { // "displayName": "Line Color", // "type": { "fill": { "solid": { "color": true }}} // } // } // } // powerbi.extensibility.utils.dataview import DataViewObjectsModule = powerbi.extensibility.utils.dataview.DataViewObject; // in order to improve the performance, one can update the <head> only in the initial rendering. // set to 'true' if you are using different packages to create the widgets const updateHTMLHead: boolean = false; const renderVisualUpdateType: number[] = [ VisualUpdateType.Resize, VisualUpdateType.ResizeEnd, VisualUpdateType.Resize + VisualUpdateType.ResizeEnd ]; //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based interface VisualSettingsSplineParams { lineColor: string; conf1: string; conf2: string; } interface VisualSettingsPointParams { pointColor: string; weight: number; } interface VisualSettingsAxesParams { colLabel: string; textSize: number; scaleXformat: string; scaleYformat: string; sizeTicks: string; axisXisPercentage: boolean; } //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based export class Visual implements IVisual { private rootElement: HTMLElement; private headNodes: Node[]; private bodyNodes: Node[]; private settings: VisualSettings; //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based private settings_funnel: VisualSettingsSplineParams; private settings_point: VisualSettingsPointParams; private settings_axes: VisualSettingsAxesParams; //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based public constructor(options: VisualConstructorOptions) { if (options && options.element) { this.rootElement = options.element; } this.headNodes = []; this.bodyNodes = []; //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based this.settings_funnel = <VisualSettingsSplineParams>{ lineColor: "blue", conf1: "0.95", conf2: "0.999" }; this.settings_point = <VisualSettingsPointParams>{ pointColor: "orange", weight: 1 }; this.settings_axes = <VisualSettingsAxesParams>{ colLabel: "gray", textSize: 12, scaleXformat: "comma", scaleYformat: "none", sizeTicks: "8", axisXisPercentage: true }; //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based } public update(options: VisualUpdateOptions): void { if (!options || !options.type || !options.viewport || !options.dataViews || options.dataViews.length === 0 || !options.dataViews[0]) { return; } const dataView: DataView = options.dataViews[0]; this.settings = Visual.parseSettings(dataView); //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based this.updateObjects(dataView.metadata.objects); //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based let payloadBase64: string = null; if (dataView.scriptResult && dataView.scriptResult.payloadBase64) { payloadBase64 = dataView.scriptResult.payloadBase64; } if (renderVisualUpdateType.indexOf(options.type) === -1) { if (payloadBase64) { this.injectCodeFromPayload(payloadBase64); } } else { this.onResizing(options.viewport); } } public onResizing(finalViewport: IViewport): void { /* add code to handle resizing of the view port */ } private injectCodeFromPayload(payloadBase64: string): void { // inject HTML from payload, created in R // the code is injected to the 'head' and 'body' sections. // if the visual was already rendered, the previous DOM elements are cleared ResetInjector(); if (!payloadBase64) { return; } // create 'virtual' HTML, so parsing is easier let el: HTMLHtmlElement = document.createElement("html"); try { el.innerHTML = window.atob(payloadBase64); } catch (err) { return; } // if 'updateHTMLHead == false', then the code updates the header data only on the 1st rendering // this option allows loading and parsing of large and recurring scripts only once. if (updateHTMLHead || this.headNodes.length === 0) { while (this.headNodes.length > 0) { let tempNode: Node = this.headNodes.pop(); document.head.removeChild(tempNode); } let headList: NodeListOf<HTMLHeadElement> = el.getElementsByTagName("head"); if (headList && headList.length > 0) { let head: HTMLHeadElement = headList[0]; this.headNodes = ParseElement(head, document.head); } } // update 'body' nodes, under the rootElement while (this.bodyNodes.length > 0) { let tempNode: Node = this.bodyNodes.pop(); this.rootElement.removeChild(tempNode); } let bodyList: NodeListOf<HTMLBodyElement> = el.getElementsByTagName("body"); if (bodyList && bodyList.length > 0) { let body: HTMLBodyElement = bodyList[0]; this.bodyNodes = ParseElement(body, this.rootElement); } RunHTMLWidgetRenderer(); } private static parseSettings(dataView: DataView): VisualSettings { return VisualSettings.parse(dataView) as VisualSettings; } //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based /** * This function gets called by the update function above. You should read the new values of the properties into * your settings object so you can use the new value in the enumerateObjectInstances function below. * * Below is a code snippet demonstrating how to expose a single property called "lineColor" from the object called "settings" * This object and property should be first defined in the capabilities.json file in the objects section. * In this code we get the property value from the objects (and have a default value in case the property is undefined) */ public updateObjects(objects: DataViewObjects) { this.settings_funnel = <VisualSettingsSplineParams>{ lineColor: DataViewObjectsModule.getValue<string>(objects, 'lineColor', 'blue'), conf1: DataViewObjectsModule.getValue<string>(objects, 'conf1', "0.95"), conf2: DataViewObjectsModule.getValue<string>(objects, 'conf2', "0.999") }; this.settings_point = <VisualSettingsPointParams>{ pointColor: DataViewObjectsModule.getValue<string>(objects, 'pointColor', 'orange'), weight: DataViewObjectsModule.getValue<number>(objects, 'weight', 1) }; this.settings_axes = <VisualSettingsAxesParams>{ colLabel: DataViewObjectsModule.getValue<string>(objects, 'colLabel', "gray"), textSize: DataViewObjectsModule.getValue<number>(objects, 'textSize', 12), scaleXformat: DataViewObjectsModule.getValue<string>(objects, 'scaleXformat', "comma"), scaleYformat: DataViewObjectsModule.getValue<string>(objects, 'scaleYformat', "none"), sizeTicks: DataViewObjectsModule.getValue<string>(objects, 'sizeTicks', "8"), axisXisPercentage: DataViewObjectsModule.getValue<boolean>(objects, 'axisXisPercentage', true) }; } //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based /** * This function gets called for each of the objects defined in the capabilities files and allows you to select which of the * objects and properties you want to expose to the users in the property pane. * */ public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject { //RVIZ_IN_PBI_GUIDE:BEGIN:Added to create HTML-based let objectName = options.objectName; let objectEnumeration = []; switch (objectName) { case 'settings_point_params': objectEnumeration.push({ objectName: objectName, properties: { pointColor: this.settings_point.pointColor, weight: this.settings_point.weight }, selector: null }); break; }; //RVIZ_IN_PBI_GUIDE:END:Added to create HTML-based return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options); } } }
Supposedly, after doing this and packaging the visual I should see the new user parameters in Power BI desktop but that is not the case .. only the rcv_script shows up.
Is there something I'm missing?
Solved! Go to Solution.
That work well with the code that you have shared.
Could you please double check that this code works well of you as well?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Just as an update, I have figured out the fix:
Update the line
this.settings_point = <VisualSettingsPointParams>{ pointColor: DataViewObjectsModule.getValue<string>(objects, 'pointColor', 'orange'), weight: DataViewObjectsModule.getValue<number>(objects, 'weight', 1) };
To this:
this.settings_point = <VisualSettingsPointParams>{ pointColor: DataViewObjectsModule.getValue<string>(objects, 'pointColor', this.settings_point.pointColor), weight: DataViewObjectsModule.getValue<number>(objects, 'weight', this.settings_point.weight) };
I think that you should return objectEnumeration in enumerateObjectInstances method.
Please let us know if that resolves the issue.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
I have changed the return statement in enumerateObjectInstances from
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
to
return objectEnumeration;
as suggested.
Still there is not change. The new user parameters do not show up in power BI
That work well with the code that you have shared.
Could you please double check that this code works well of you as well?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
welp ..
I cant hope to know how this happened but i copied the visual.ts from the one you had to my working visual and now the user parameters show up ...
for some reason when i change the color it gets reverted back to whatever i have set as default, but that's a topic for another thread
thank you
Please let me know if you need any help with color reverting issue.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Hi Ignat,
I've implemented the code sample you shared and am also having the same issue of colors reverting to default (only in the selector pane, not on the visual itself). Is there a fix for this?
Regards,
Richard
Just as an update, I have figured out the fix:
Update the line
this.settings_point = <VisualSettingsPointParams>{ pointColor: DataViewObjectsModule.getValue<string>(objects, 'pointColor', 'orange'), weight: DataViewObjectsModule.getValue<number>(objects, 'weight', 1) };
To this:
this.settings_point = <VisualSettingsPointParams>{ pointColor: DataViewObjectsModule.getValue<string>(objects, 'pointColor', this.settings_point.pointColor), weight: DataViewObjectsModule.getValue<number>(objects, 'weight', this.settings_point.weight) };
User | Count |
---|---|
15 | |
2 | |
1 | |
1 | |
1 |
User | Count |
---|---|
16 | |
11 | |
5 | |
4 | |
3 |