Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!

Reply
pope
Frequent Visitor

Adding user parameters to an R powered visualization

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?

2 ACCEPTED SOLUTIONS
v-viig
Community Champion
Community Champion

That work well with the code that you have shared.

Could you please double check that this code works well of you as well?

image.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

View solution in original post

Anonymous
Not applicable

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)
            };
 

View solution in original post

8 REPLIES 8
v-viig
Community Champion
Community Champion

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

pbicvsupport@microsoft.com

 

pope
Frequent Visitor

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

v-viig
Community Champion
Community Champion

That work well with the code that you have shared.

Could you please double check that this code works well of you as well?

image.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

pope
Frequent Visitor

welp ..

Untitled.png

pope
Frequent Visitor

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 ...

Untitled.png

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

v-viig
Community Champion
Community Champion

Please let me know if you need any help with color reverting issue.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Anonymous
Not applicable

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

Anonymous
Not applicable

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)
            };
 

Helpful resources

Announcements
April AMA free

Microsoft Fabric AMA Livestream

Join us Tuesday, April 09, 9:00 – 10:00 AM PST for a live, expert-led Q&A session on all things Microsoft Fabric!

March Fabric Community Update

Fabric Community Update - March 2024

Find out what's new and trending in the Fabric Community.