Build Your Custom Visuals in Power BI (Step-by-Step)

In this blog post, I show you how to create your own custom visuals in Power BI.
You can easily create your own visuals and put them together with the existing visuals in your report. You can also submit your visual into Office Store (Seller Dashboard) for publishing.

Note : I described about custom visuals in the previous post “How to create Power BI custom visuals (Japanese)“, but the new development tool (the following command-line tool) is released and generally available. Please use this new tool.

Setup your dev env

For custom visual development, all you have to prepare is PC (or Mac), Node.js, and Power BI service account (free). Nothing else is needed !

Before development, you must install the Power BI visual tool (command-line tool) which is used for all following development tasks.

npm install -g powerbi-visuals-tools

Create New Project

Next, you create the new custom visual project using “pbiviz” command previously installed.
Here we create the project named “MyTestVisual” as follows.

pbiviz new myTestVisual
cd myTestVisual
npm install

The folder “myTestVisual” is created, and all the project files are located in this folder.
You can change these source code as you like.

Anyway, Run and Test !

The source code is written by the typescript.
Please see the source code of src/visual.ts in your project folder. This is the main logic of your custom visuals, and it’s just displaying the simple text as follows. (When the “update” method is called for re-drawing, the “updateCount” is incremented each time.)

module powerbi.extensibility.visual {
  export class Visual implements IVisual {
    private target: HTMLElement;
    private updateCount: number;

    constructor(options: VisualConstructorOptions) {
      console.log('Visual constructor', options);
      this.target = options.element;
      this.updateCount = 0;
    }

    public update(options: VisualUpdateOptions) {
      console.log('Visual update', options);
      this.target.innerHTML = '<p>Update count: <em>${(this.updateCount++)}</em></p>';
    }

    public destroy(): void {
      //TODO: Perform any cleanup tasks here
    }
  }
}

Now let’s look at this sample in your Power BI !
Move to the visual project folder (which contains pbiviz.json), and please type the following command.
This launches the http server (https://localhost:8080/), and starts (hosts) this visual in this server.

pbiviz start

Open and login to Power BI service (https://app.powerbi.com). Then select [Settings] menu like the following screenshot.

When the setting page is displayed, select [Enable developer visual for testing].

This enables developer visual in your visual pane. After you enable this, you can see the following icon (Developer Visual icon) in the visual pane on Power BI service.

When you insert this visual into your page, the local visual (which is hosted in https://localhost:8080/) is displayed like the following screenshot.
If you resize this visual, you can see that the count is incremented by re-drawing.

Note : If you see the error like the following screenshot, it might be that the server certificate of https (https://localhost:8080) is not installed in your client. Please see “PowerBI-visuals : HTTPS Certificate Setup” and install the certificate. Or, permit this page to browse using browser settings.

The “pbiviz” (Visual Builder) is having the built-in file watcher. If you change your source code, it detects your changes and the source code is compiled (re-built) soon. (You can check the work in Power BI service immediately.)

Build your own visuals !

Super, Super Basic

As I described above, the main class of your custom visual is in src/visual.ts and this class implements IVisual interface.
The important methods of your visual class (IVisual) is the constructor and “update” method. You must setup your visual in your constructor, and draw your visual in the “update” method.

The “update” method passes “options” as an argument, and options.dataViews includes all the data for visualization. (You can take multiple dataViews, but we assume only one dataView in this blog post. We always refer as options.dataViews[0].)
The dataView is including the properties of “metadata”, “categorical”, “matrix”, “table”, and “tree”. The “metadata” is including the metadata information like “what properties are included”, “which type is each property”, “what option (which I explain later) is selected” and etc.
When you change your code (src/visual.ts) as follows, you can see like the following screenshot. (The json string of options.dataViews[0].metadata.columns is displayed.)

export class Visual implements IVisual {
  private target: HTMLElement;

  constructor(options: VisualConstructorOptions) {
    var captionArea = document.createElement("div");
    captionArea.innerHTML = "This is test chart";
    options.element.appendChild(captionArea);
    this.target = document.createElement("div");
    options.element.appendChild(this.target);
  }

  public update(options: VisualUpdateOptions) {
    this.target.innerHTML =
      JSON.stringify(options.dataViews[0].metadata.columns);
  }

  public destroy(): void {
    //TODO: Perform any cleanup tasks here
  }
}

The others (“categorical”, “matrix”, “table”, and “tree”) are including data itself. The data of “categorical”, “matrix”, “table”, and “tree” is the same data which the user has specified, but the expression of these data differs for each other.
Here I want to explain the details of each data expression (“categorical”, “matrix”, “table”, and “tree”), but “categorical” and “table” is most commonly used data expression, and I’ll explain only these 2 samples.

For example, we assume the following source.

ItemName Year Country Cost
Mouse 2014 Japan 25
Power Unit 2015 Japan 30
Accesory 2016 Japan 18
Cable 2015 North America 14
Mouse 2016 North America 30
Phone 2016 China 100

In this case, “categorical” expression would be like following. (As I describe later, this expression depends on the capabilities definition. Below is one of the examples for your understanding.)

{
  "categories": [
    {
      "source":{
        "displayName": "Country"
      }
      "values":[
        "Japan",
        "Japan",
        "Japan",
        "North America",
        "North America",
        "China"
      ]
    },
    {
      "source":{
        "displayName": "Year"
      }
      "values":[
        "2014",
        "2015",
        "2016",
        "2015",
        "2016",
        "2016"
      ]
    }
  ],
  "values":[
    {
      "source":{
        "displayName": "Cost"
      }
      "values":[
        "25",
        "30",
        "18",
        "14",
        "30",
        "100"
      ]
    }
  ]
}

The “table” expression would be like following.

{
  "columns":[
    {"displayName": "Year"},
    {"displayName": "Country"},
    {"displayName": "Cost"}
  ],
  "rows":[
    [2014, "Japan", 25],
    [2015, "Japan", 30],
    [2016, "Japan", 18],
    [2015, "North America", 14],
    [2016, "North America", 30],
    [2016, "China", 100]
  ]
}

If you want to see these data (“metadata”, “categorical”, “matrix”, “table”, and “tree”) in debug-time, you can use the following button in the Developer Visual. (When you click the following “view dataView as json” button, the following screenshot is displayed.)

dataRoles and dataViewMappings

The previous data expression is determined by your definition called “capabilities”.
Open the capabilities.json in your project root folder, and please update this json as follows. (The property “kind” means that “0” is “grouping data” and “1” is “measuring data”.)

{
  "dataRoles": [
    {
      "displayName": "Summarize Category",
      "name": "myCategory",
      "kind": 0
    },
    {
      "displayName": "Measure Data",
      "name": "myMeasure",
      "kind": 1
    }
  ],
  "dataViewMappings": [
    {
      "categorical": {
        "categories": {
          "for": {
            "in": "myCategory"
          },
          "dataReductionAlgorithm": {
            "top": {}
          }
        },
        "values": {
          "select": [
            {
              "bind": {
                "to": "myMeasure"
              }
            }
          ]
        }
      }
    }
  ]
}

If you insert this visual in your page, you can see the visual pane like the following screenshot. As you can see, the defined dataRoles (“Summarize Category” and “Measure Data”) is displayed in the visual pane.

Please drag the following data (“Country” and “Cost”) from the data source which is having the table as the previous example in the database.

Then you can get the following json as options.dataViews[0].categorical in the “update” method. (Note that options.dataViews[0].categorical doesn’t return the following string, but you can retrieve each element like options.dataViews[0].categorical.categories and options.dataViews[0].categorical.values.)
As you can see, the following data is summarized by Country.

{
  "categories": [
    {
      "source": {
        "roles": {
          "myCategory": true
        },
        "displayName": "Country",
        "index": 0,
        ...
      },
      "values": [
        "China",
        "Japan",
        "North America"
      ],
      "identity": [...],
      "identityFields": [...]
    }
  ],
  "values": [
    {
      "source": {
        "roles": {
          "myMeasure": true
        },
        "displayName": "Cost",
        "index": 1,
        "isMeasure": true,
        ...
      },
      "values": [
        100,
        73,
        44
      ],
      "minLocal": 44,
      "maxLocal": 100
    }
  ]
}

Next example shows how you can use “group by” in your capabilities.json.

{
  "dataRoles": [
    {
      "displayName": "Summarize Category",
      "name": "myCategory",
      "kind": 0
    },
    {
      "displayName": "Measure Data",
      "name": "myMeasure",
      "kind": 1
    },
    {
      "displayName": "Grouping",
      "name": "myGroup",
      "kind": 0
    }
  ],
  "dataViewMappings": [
    {
      "categorical": {
        "categories": {
          "for": {
            "in": "myCategory"
          },
          "dataReductionAlgorithm": {
            "top": {}
          }
        },
        "values": {
          "group": {
            "by": "myGroup",
            "select": [
              {
                "for": {
                  "in": "myMeasure"
                }
              }
            ]
          }
        }
      }
    }
  ]
}

If you insert this visual in your page, you can see the visual pane like the following screenshot. Here we can see “Grouping” area in the visual pane.

If you select “Year” as grouping data, you can see the following dataView result as the categorical data.
As you can see, the result data is expressed as “Cost” data of 2 dimensions of categories (“Country” and “Year”).

{
  "categories": [
    {
      "source": {
        "roles": {
          "myCategory": true
        },
        "displayName": "Country",
        "index": 0,
        ...
      },
      "values": [
        "China",
        "Japan",
        "North America"
      ],
      "identity": [...],
      "identityFields": [...]
    }
  ],
  "values": [
    {
      "source": {
        "roles": {
          "myMeasure": true
        },
        "displayName": "Cost",
        "index": 1,
        "isMeasure": true,
        "groupName": 2014,
        ...
      },
      "values": [
        { },
        25,
        { }
      ],
      "identity": {...}
    },
    {
      "source": {
        "roles": {
          "myMeasure": true
        },
        "displayName": "Cost",
        "index": 1,
        "isMeasure": true,
        "groupName": 2015,
        ...
      },
      "values": [
        { },
        30,
        14
      ],
      "identity": {...}
    },
    {
      "source": {
        "roles": {
          "myMeasure": true
        },
        "displayName": "Cost",
        "index": 1,
        "isMeasure": true,
        "groupName": 2016,
        ...
      },
      "values": [
        100,
        18,
        30
      ],
      "identity": {...}
    }
  ]
}

If you want to get data as “table” (not “categorical”), you should write as follows in the capabilities.json.

{
  "dataRoles": [
    {
      "displayName": "Summarize Category",
      "name": "myCategory",
      "kind": 0
    },
    {
      "displayName": "Measure Data",
      "name": "myMeasure",
      "kind": 1
    }
  ],
  "dataViewMappings": [
    {
      "table": {
        "rows": {
          "select": [
            { "for": { "in": "myCategory" } },
            { "for": { "in": "myMeasure" } }
          ]
        }
      }
    }
  ]
}

If you select “Country” and “Cost” as input data, you can get the following data in options.dataViews[0].table. (Note that options.dataViews[0].table doesn’t return the following string, but you can retrieve each element like options.dataViews[0].table.columns, options.dataViews[0].table.rows, and etc.)

{
  "columns": [
    {
      "roles": {
        "myCategory": true
      },
      "displayName": "Country",
      "index": 0,
      ...
    },
    {
      "roles": {
        "myMeasure": true
      },
      "displayName": "Cost",
      "index": 1,
      "isMeasure": true,
      ...
    }
  ],
  "rows": [
    [
      "China",
      100
    ],
    [
      "Japan",
      73
    ],
    [
      "North America",
      44
    ]
  ],
  "identity": [...],
  "identityFields": [...]
}

The following document is very useful resource for dataRoles and DataViewMappings.

PowerBI-visuals : DataViewMappings
https://github.com/Microsoft/PowerBI-visuals/blob/master/Capabilities/DataViewMappings.md

Custom Visual Properties

As you saw before, you can specify “what kind of data the user can input” using the dataRoles definition in capabilities.json. But you can add other custom properties in your visuals.

First, you define your custom object (using “objects”) and custom property (using “properties”) using capabilities.json as follows.

{
  "dataRoles": [
    ...
  ],
  "dataViewMappings": [
    ...
  ],
  "objects": {
    "myCustomObj": {
      "displayName": "Test Object",
      "properties": {
        "myprop": {
          "displayName": "Test Property",
          "type": { "bool": true }
        }
      }
    }
  }
}

After you modify capabilities.json, you must implement “enumerateObjectInstances” method in your visual class (src/visual.ts). In this method, the property value is populated by the variable (in this case, “this.myVisualProp”).
If the user change this properties’ value, the “update” method is called. Then your code should save this value into the variable (“this.myVisualProp”) and do the appropriate task in the “update” method. (The following example is just showing the value in the visual UI.)

export class Visual implements IVisual {
  private target: HTMLElement;
  private myVisualProp: boolean;

  constructor(options: VisualConstructorOptions) {
    var captionArea = document.createElement("div");
    captionArea.innerHTML = "This is test chart";
    options.element.appendChild(captionArea);
    this.target = document.createElement("div");
    options.element.appendChild(this.target);

    this.myVisualProp = false;
  }

  public update(options: VisualUpdateOptions) {
    // This example just shows the selected property in visual.
    this.myVisualProp = options.dataViews[0].metadata.objects["myCustomObj"]["myprop"];
    this.target.innerHTML =
      "Custom Prop is " + this.myVisualProp;
  }

  public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
    let objectName = options.objectName;
    let objectEnumeration: VisualObjectInstance[] = [];

    switch (objectName) {
      case 'myCustomObj':
        objectEnumeration.push({
          objectName: objectName,
          properties: {
            myprop: this.myVisualProp,
          },
          selector: null
        });
        break;
    };

    return objectEnumeration;
  }

  public destroy(): void {
    //TODO: Perform any cleanup tasks here
  }
}

The result looks like as follows.

In this example we’ve created the simple boolean property, but you can also use other types of properties including the color pallet like the following screenshot.

In this example I’ve just explained custom properties. But you can also support other advanced capabilities like “highlighting”. (The highlighting enables selected value highlighted and causes all other visuals on the page, as the built-in visual does.) For the highlighting capabilities, see “PowerBI-visuals : Highlighting” for details.

Visualize your data !

After you determine the data format using dataViewMappings, now you can start to build your own visuals.

Here we assume the previous “table” format of data.
In this case, options.dataViews[0].table.columns returns :

{
  "0":{
    "roles": {"myCategory": true},
    "displayName": "Country",
    ...
  },
  "1":{
    "roles": {"myMeasure": true},
    "displayName": "Cost",
    ...
  }
}

options.dataViews[0].table.rows returns :

[
  ["China", 100],
  ["Japan", 73],
  ["North America", 44]
]

We use these data for our visualization.

You can use your favorite external library for visualization (see “PowerBI-visuals – Adding External Libraries“), but the d3.js is included in custom visuals by default, and here we also use this library for drawing.

Before using d3.js in your typescript, you must include the type definition for the d3. Please type the following command and include d3 type definition in your project.

Note : If you search d3 type definition using “typings” command (like the following), you can find 2 definitions in both “npm” source and “dt” (DefinitelyTyped) source. You must use one in “dt” source using “–source” option.
typings search --name d3

Note : Now d3 version 4 is released and compatible for typescript 2.0 (not compatible for typescript 1.8.x). Because pbiviz (visual tools) is now still using typescript 1.8.x, then you must specify d3 old version (commit# 7d3a939fbe55576fad2e074d007f7cc671aa0e78) which is compatible for typescript 1.8.x, instead of “typings install d3 --source dt --global” (Described on Dec 2016)

npm install -g typings
typings install d3=github:DefinitelyTyped/DefinitelyTyped/d3/d3.d.ts#7d3a939fbe55576fad2e074d007f7cc671aa0e78 --source dt --global

Next you must modify tsconfig.json in your project as follows (add the line of the bold font).

{
  "compilerOptions": {
    "allowJs": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "ES5",
    "sourceMap": true,
    "out": "./.tmp/build/visual.js"
  },
  "files": [
    ".api/v1.1.0/PowerBI-visuals.d.ts",
    "src/visual.ts",
    "typings/index.d.ts"
  ]
}

Now it’s ready !
You can implement your custom visuals (src/visual.ts) as follows using d3.js. Note that here we’re using the fixed label (“Country”, “Cost”), the fixed color (fill-in color in chart), and so on. But you can also retrieve these values from metadata or columns definition. Sorry, but now I’m cutting these code in this example for your understanding. (Please add these code in your production.)

export interface TestItem {
  Country: string;
  Cost: number;
}

export class Visual implements IVisual {
  private svg: d3.Selection<SVGElement>;
  private g: d3.Selection<SVGElement>;
  private margin = { top: 20, right: 20, bottom: 200, left: 70 };

  constructor(options: VisualConstructorOptions) {
    // append svg graphics
    this.svg = d3.select(options.element).append('svg');
    this.g = this.svg.append('g');
  }

  public update(options: VisualUpdateOptions) {
    // "this" scope will change in the nested function
    var _this = this;

    // get height and width from viewport
    _this.svg.attr({
      height: options.viewport.height,
      width: options.viewport.width
    });
    var gHeight = options.viewport.height
      - _this.margin.top
      - _this.margin.bottom;
    var gWidth = options.viewport.width
      - _this.margin.right
      - _this.margin.left;
    _this.g.attr({
      height: gHeight,
      width: gWidth
    });
    _this.g.attr('transform',
      'translate(' + _this.margin.left + ',' + _this.margin.top + ')');

    // convert data format
    var dat =
      Visual.converter(options.dataViews[0].table.rows);

    // setup d3 scale
    var xScale = d3.scale.ordinal()
      .domain(dat.map(function (d) { return d.Country; }))
      .rangeRoundBands([0, gWidth], 0.1);
    var yMax =
      d3.max(dat, function (d) { return d.Cost + 10 });
    var yScale = d3.scale.linear()
      .domain([0, yMax])
      .range([gHeight, 0]);

    // remove exsisting axis and bar
    _this.svg.selectAll('.axis').remove();
    _this.svg.selectAll('.bar').remove();

    // draw x axis
    var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient('bottom');
    _this.g
      .append('g')
      .attr('class', 'x axis')
      .style('fill', 'black') // you can get from metadata
      .attr('transform', 'translate(0,' + (gHeight - 1) + ')')
      .call(xAxis)
      .selectAll('text') // rotate text
      .style('text-anchor', 'end')
      .attr('dx', '-.8em')
      .attr('dy', '-.6em')
      .attr('transform', 'rotate(-90)');

    // draw y axis
    var yAxis = d3.svg.axis()
      .scale(yScale)
      .orient('left');
    _this.g
      .append('g')
      .attr('class', 'y axis')
      .style('fill', 'black') // you can get from metadata
      .call(yAxis);

    // draw bar
    var shapes = _this.g
      .append('g')
      .selectAll('.bar')
      .data(dat);

    shapes.enter()
      .append('rect')
      .attr('class', 'bar')
      .attr('fill', 'green')
      .attr('stroke', 'black')
      .attr('x', function (d) {
        return xScale(d.Country);
      })
      .attr('width', xScale.rangeBand())
      .attr('y', function (d) {
        return yScale(d.Cost);
      })
      .attr('height', function (d) {
        return gHeight - yScale(d.Cost);
      });

    shapes
      .exit()
      .remove();
  }

  public destroy(): void {
    //TODO: Perform any cleanup tasks here
  }

  // convert data as following
  //
  //[
  //  "Japan",
  //  100
  //],
  //[
  //  "America",
  //  300
  //],
  //...
  //
  // -->
  //
  // [{"Country" : "Japan",   "Cost" : 100},
  //  {"Country" : "America", "Cost" : 300},
  // ...]
  //
  public static converter(rows: DataViewTableRow): TestItem[] {
    var resultData: TestItem[] = [];

    for (var i = 0;
      i < rows.length;
      i++) {
      var row = rows[i];
      resultData.push({
        Country: row[0],
        Cost: row[1]
      });
    }

    return resultData;
  }
}

When you insert this visual in your page, you can see your visual as follows.

Packaging and Distributions

The programming has done. Now you can create your distributable package using the following command.
After the command has completed, the pakage file is created as dist/{your project name}.pbiviz. (This .pbiviz file is the zip file, and you can extract and see the resource in this package.)

pbiviz package

After you have created your package (.pbiviz), you can import this package by selecting […] – [import a custom visual] (see the following screenshot) in the visual pane of Power BI Desktop or Power BI services.

 

With Real-time, Embedded, and more …

You can use your custom visuals in Power BI Embedded. That is, you can include your own custom visuals into your PowerBI integrated applications. (But, note that the PowerPoint export is not supported in custom visuals …)

This custom visual can also be updated by real-time in your Power BI dashboard. (For example, pin to the dashboard, and push the rows into the dataset using rest api.)

 

If you have completed, you can share your visuals in the Power BI community (see below), and everybody can download your custom visuals. You can also check these useful visuals as your development examples.

Power BI : Visual Gallery
https://app.powerbi.com/visuals/

Please refer the following useful document for details.

PowerBI-visuals : Developer’s documents
https://github.com/Microsoft/PowerBI-visuals#developing-your-first-powerbi-visual

 

Advertisements

19 thoughts on “Build Your Custom Visuals in Power BI (Step-by-Step)

  1. This is one of the more useful tutorials I have found as most seem to relate to the online tools.
    The only bit which confused me was the section “Super, Super Basic”, the second screenshot confused me until i realised that I needed to link the visualisation to some data to view the meta.
    Good but could use reorganising a bit 🙂

    Like

  2. I want to render my own js chart library to Power BI,
    I understand that d3.js is also getting reffered in the .ts file,
    But what if I want to render everything from my personal library js file keeping in context the life cycle of power bi visuals(init, update, destroy)

    Like

  3. At the step to install d3 from DT source, I am getting this error about –global switch

    >typings install d3 –source dt –global

    Error Message :
    typings ERR! message Attempted to compile “d3” as a global module, but it looks like an external module. You’ll need to remove the global option to continue.

    The [node_modules] folder never gets created.
    If I remove the –global switch and run the command

    >typings install d3 –source dt

    [modules] folder gets created under [typings] folder and there is error in the file [typings] –> [modules] –>[d]–> index.d.ts file with error message –
    Export declarations may only appear at the top level of a module

    Like

    • Thank you for your feedback.
      What you’re saying is right, because new version of d3 definition is released. This version is compatible for the new version of typescript 2.0, but pbiviz is still using typescript 1.8 and error occurs.
      For the time being, please use the definition commit# 7d3a939fbe55576fad2e074d007f7cc671aa0e78 which is compatible for typescript 1.8.x.
      I added this description in my post. (Thanks again)

      Like

      • hi ,i cannot understand your description,can you tell me how to solve this error ?and how to use the definition commit# 7d3a939fbe55576fad2e074d007f7cc671aa0e78 which is compatible for typescript 1.8.x?

        Like

      • npm install -g typings
        typings install d3=github:DefinitelyTyped/DefinitelyTyped/d3/d3.d.ts#7d3a939fbe55576fad2e074d007f7cc671aa0e78 –source dt –global

        after this a new error appeared :
        step: pbiviz start
        error message:
        info Building visual…
        error TYPESCRIPT /src/visual.ts : (34,22) Cannot find namespace ‘d3’.
        error TYPESCRIPT /src/visual.ts : (35,20) Cannot find namespace ‘d3’.
        error TYPESCRIPT /src/visual.ts : (68,34) Argument of type ‘DataViewTableRow[
        ]’ is not assignable to parameter of type ‘DataViewTableRow’.
        Types of property ‘push’ are incompatible.
        Type ‘(…items: DataViewTableRow[]) => number’ is not assignable to type ‘(
        …items: PrimitiveValue[]) => number’.
        Types of parameters ‘items’ and ‘items’ are incompatible.
        Type ‘PrimitiveValue’ is not assignable to type ‘DataViewTableRow’.
        Type ‘string’ is not assignable to type ‘DataViewTableRow’.
        error TYPESCRIPT /src/visual.ts : (75,53) Property ‘Cost’ does not exist on t
        ype ‘{}’.
        error TYPESCRIPT C:/Program Files/nodejs/project/bxChart/typings/globals/d3/i
        ndex.d.ts : (746,22) Interface ‘_Selection’ incorrectly extends interface ‘an
        y[]’.
        Types of property ‘sort’ are incompatible.
        Type ‘(comparator?: (a: T, b: T) => number) => _Selection’ is not assigna
        ble to type ‘(compareFn?: (a: any, b: any) => number) => this’.
        Type ‘_Selection’ is not assignable to type ‘this’.

        Like

      • Hello

        please tell me
        When you install d3
        It is said to be “No dependencies”
        Running the package
        Error is output
        At Promise (username AppData Roaming npm node_modules powerbi-visuals-tools lib VisualPackage.js: 67: 35)
        At Function.loadVisualPackage (username AppData Roaming npm node_modules powerbi-visuals-tools lib VisualPackage.js: 62: 16)
        At Object. (username AppData Roaming npm node_modules powerbi-visuals-tools bin pbiviz-start.js: 43: 15)
        At Module._ compile (module.js: 571: 32)
        At Object.Module._extensions .. js (module.js: 580: 10)
        At Module.load (module.js: 488: 32)
        At tryModuleLoad (module.js: 447: 12)
        At Function.Module._load (module.js: 439: 3)
        At Module.runMain (module.js: 605: 10)
        At run (bootstrap_node.js: 423: 7)

        How can I move without error?

        Like

    • hi ,i get a Error Message same to you,
      Error Message :
      typings ERR! message Attempted to compile “d3” as a global module, but it looks like an external module. You’ll need to remove the global option to continue.

      can you tell me how to solve this error ?and how to use the definition commit# 7d3a939fbe55576fad2e074d007f7cc671aa0e78 which is compatible for typescript 1.8.x?

      Like

  4. Thank you for sharing this. This is really helpful. As I can see the heatmap you have created above. I would really appreciate if you would share me how you have done so.

    Like

  5. It’s so wonderful, and actually it’s the only useful tutorial about programming Power BI custom visual I found on Internet.

    Thank you, Tsuyoshi.

    Like

  6. Thanks a lot, This is the most useful guidance that I have even seen about PowerBi custom visual.
    Could you please help how to config capabilities.json if I would like to get the raw input data such as
    {
    “columns”:[
    {“displayName”: “Year”},
    {“displayName”: “Country”},
    {“displayName”: “Cost”}
    ],
    “rows”:[
    [2014, “Japan”, 25],
    [2015, “Japan”, 30],
    [2016, “Japan”, 18],
    [2015, “North America”, 14],
    [2016, “North America”, 30],
    [2016, “China”, 100]
    ]
    }

    Like

  7. Thank you very much, this tutorial was very helpful!

    To make the final barchart work I had to make a few changes to the ‘converter’ method:

    public static converter(rows: DataViewTableRow[]): TestItem[] {
    var resultData: TestItem[] = [];

    for (var i = 0;
    i < rows.length;
    i++) {
    var row = rows[i];
    resultData.push({
    Country: String(row[0]),
    Cost: +row[1]
    });
    }

    return resultData;
    }

    I am not sure, why I had to change it, maybe it is because I use api v.1.5.0 instead of v.1.1.0.

    Like

  8. This didn’t work until I also ran:
    npm install powerbi-visuals-utils-dataviewutils –save

    Before…
    pbiviz start

    Like

  9. Hi, Thanks for the tutorial. I have one problem. I get an error message with this line of code:
    this.myVisualProp = options.dataViews[0].metadata.objects[“myCustomObj”][“myprop”];
    Error: Type ‘DataViewPropertyValue’ is not assignable to type boolean
    Type ‘string’ is not assignable to type boolean.
    (property) powerbi.extensiblity.visial.Visual.myVisualProp: boolean

    Am I missing a config setting or a reference, or is this old version API issues?

    Pieter

    Like

    • Found a soution, i used a cast in that line of code as follows:
      //working code
      this.myVisualProp = options.dataViews[0].metadata.objects[“myCustomObj”][“myprop”];

      //error code:
      this.myVisualProp = options.dataViews[0].metadata.objects[“myCustomObj”][“myprop”];

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s