Forum Discussion

dbardele's avatar
dbardele
Frequent Visitor
7 years ago
Solved

Custom Visual cut off after resizing in Power BI Service

Hello, I'm new to developing custom visuals but I have something (sort of) working after following tutorials and watching YouTube videos. However, I cannot get mine to resize bigger than a postage stamp, nor to do so in real time as I change the viewport. This also was a problem when I was resizing the tutorial "Update Counter"...my counter didn't count up at all even though I was following the tutorial exactly. I'm wondering if it's because I'm using a different version of pbiviz (3.1.1) than the tutorial was written in.

 

Here is the code that I think defines sizing (unfortunately I cannot attach screengrabs of the visual). However, I may be missing something in one of the other files. Any advice will be greatly appreciated. Thanks!

 

Dom

 

import "./../style/visual.less";

import powerbi from "powerbi-visuals-api";
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;

import * as d3 from "d3";

export class Visual implements IVisual {

private svgRoot: d3.Selection<SVGElement, {}, HTMLElement, any>;
private xAxis: d3.Selection<SVGElement, {}, HTMLElement, any>;
private yAxis: d3.Selection<SVGElement, {}, HTMLElement, any>;
private line: d3.Selection<SVGElement, {}, HTMLElement, any>;
private circle: d3.Selection<SVGElement, {}, HTMLElement, any>;
private padding: number = 20;

constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);

this.svgRoot = d3.select(options.element)
.append("svg")
.append("g");

this.xAxis = this.svgRoot
.append("g")
.attr("class", "x axis")
.style("stroke", "black")
.style("stroke-width", "1");

this.yAxis = this.svgRoot
.append("g")
.attr("class", "y axis")
.style("stroke", "black")
.style("stroke-width", "1");

/*
this.line = this.svgRoot
.append("g")
.style("stroke", "black");
*/

this.RenderVisual(options.element.clientWidth, options.element.clientHeight);

}

public update(options: VisualUpdateOptions) {

console.log('Visual update', options);

// let dataView: DataView = options.dataViews[0]

this.RenderVisual(options.viewport.width + 20, options.viewport.height + 20);

}

private RenderVisual(clientWidth: number, clientHeight: number) {

this.svgRoot
.attr("width", clientWidth)
.attr("height", clientHeight);

var plot = {
xOffset: 0, // this.padding,
yOffset: 0, // this.padding,
width: clientWidth - (this.padding * 2),
height: clientHeight - (this.padding * 2),
};
  • Hi there,

    Once thing I'd suggest is that this part of your code needs tweaking to make the visual keep track with the viewport:

    this.svgRoot = d3.select(options.element)
        .append("svg")
        .append("g");

    This is assigning the variable to the <g> (group) element that you append to the <svg> element, rather than the <svg> element itself.

    When you call renderVisual, it's resizing the <g> element, and not the parent <svg>, e.g.:

    The parent <svg> (as it has no explicit width & height attributes) will get rendered using the browser default (in my case it's 300 x 150 pixels.

    Because the <g> element sits inside it, the parent will never grow to fit it.

    It might be better to, set your svgRoot to the actual <svg> element, i.e.:

    this.svgRoot = d3.select(options.element)
        .append("svg");

    This way, renderVisual will resize the container element, e.g.:

    Note that if you still want to group your axis elements, then you'll need to add in the parent <g> to group them somewehre else, as we removed it from the code, but this should allow you to size your SVG canvas with the viewport accordingly.

    Good luck!

    Daniel

3 Replies

  • dm-p's avatar
    dm-p
    Super User

    Hi there,

    Once thing I'd suggest is that this part of your code needs tweaking to make the visual keep track with the viewport:

    this.svgRoot = d3.select(options.element)
        .append("svg")
        .append("g");

    This is assigning the variable to the <g> (group) element that you append to the <svg> element, rather than the <svg> element itself.

    When you call renderVisual, it's resizing the <g> element, and not the parent <svg>, e.g.:

    The parent <svg> (as it has no explicit width & height attributes) will get rendered using the browser default (in my case it's 300 x 150 pixels.

    Because the <g> element sits inside it, the parent will never grow to fit it.

    It might be better to, set your svgRoot to the actual <svg> element, i.e.:

    this.svgRoot = d3.select(options.element)
        .append("svg");

    This way, renderVisual will resize the container element, e.g.:

    Note that if you still want to group your axis elements, then you'll need to add in the parent <g> to group them somewehre else, as we removed it from the code, but this should allow you to size your SVG canvas with the viewport accordingly.

    Good luck!

    Daniel

    • dbardele's avatar
      dbardele
      Frequent Visitor

      Oh my goodness THANK YOU! That fixed it. It's still not resizing automatically when I drag the window size around like in the tutorial, but I can live with that. As soon as I click refresh, it resizes to the viewport window.

       

      Thanks again! On to find the next thing that will confound me...

       

      Dom

      • dm-p's avatar
        dm-p
        Super User

        No probs! Glad you're sorted. There will be many confounding things to work on ;), but chip away at them...

        FYI if you need to refresh the visual to fix your issue, that suggests something to do with code in the constructor method (which runs on instantiation) is working vs. the update method (which runs for every change afterwards).

        I notice that you have a renderVisual call in both of these methods. It will be better to try and manage it in the update method rather than the constructor (use the contructor to create the element placeholders, but handle sizing and drawing that depends on changes to the visual in update).

        Here's a simple custom visual I did for a presentation recently - it's a knock-off of the circle-card visual and is done on the older tooling, but if you look at the function code, the approach is similar. It might help you with obtaining some code to handle resizing and where to do it in the workflow.