d3.jssvgtypescriptpowerbibullet-chart

Power BI Different style in dashboard than Developer tools Preview Options


First try at power BI Custom graphics, pardon me for some inconsistencies.

I'm trying to edit the Bullet Chart "BulletChartbySQLBI", so that it can meet my needs, but i cant seem to figure out why that the styling applied in dev. tools preview does not stay when importing to the dashboard, colors and text formatting.

+ Question

Another problem that i have is that i can't seem to place the title on top of the main bar, so that i can place the text there, i tried to use css styling, with no success, and then tried to change the way that the svg is drawn so that the text appears on top, but also with no success.

Code developed in: https://app.powerbi.com/devTools

Data Preview: SimpleGauge(Single+Categorical)

module powerbi.visuals {

//Model
export interface BulletCharttestBI4ALL {
    label: string;
    label2: string;
    showLabel: boolean;
    color: string;
    color2: string;
    states: number[];
    value: number;
    target: number;
    comparison: number;
    min: number;
    max: number;
    selector: data.Selector;
    toolTipInfo: TooltipDataItem[];
}

export var bulletChartProps = {   //PROPRIEDADES para o power BI  // Replicar  linha 187  e  427
    general: {
        fill: <DataViewObjectPropertyIdentifier>{ objectName: 'Cores', propertyName: 'fill' },
        fill2: <DataViewObjectPropertyIdentifier>{ objectName: 'Cores', propertyName: 'fill2' },
    },
    label: {
        show: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'show' },
        text: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'text' },
        text2: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'text2' }
    },
};

//Visual
export class BulletCharttestBI4ALL1 implements IVisual {

    //Variables
    private svg: D3.Selection;
    private svgBullet: D3.Selection;
    private svgTitle: D3.Selection;
    private svgSubtitle: D3.Selection;

    private dataView: DataView;
    private data: BulletCharttestBI4ALL;

    public static getDefaultData(): BulletCharttestBI4ALL {
        return {
            color: '#36bba3',
            color2: 'lightsteelblue',
            label: 'YTD stuff',
            label2: '2015',
            showLabel: true,
            states: [],
            min: 0,
            max: 100,
            value: 0,
            target: 0,
            comparison: 0,
            toolTipInfo: [],
            selector: SelectionId.createNull().getSelector()
        };
    }

    //Capabilities
    public static capabilities: VisualCapabilities = {
        dataRoles: [
             {
                name: 'Y',
                kind: VisualDataRoleKind.Measure,
                displayName: data.createDisplayNameGetter('Role_DisplayName_Value'),
            }, {
                name: 'ComparisonValue',
                kind: VisualDataRoleKind.Measure,
                displayName: 'Comparison Value',
            }, {
                name: 'TargetValue',
                kind: VisualDataRoleKind.Measure,
                displayName: data.createDisplayNameGetter('Role_DisplayName_TargetValue'),
            }, {
                name: 'MinValue',
                kind: VisualDataRoleKind.Measure,
                displayName: data.createDisplayNameGetter('Role_DisplayName_MinValue'),
            }, {
                name: 'MaxValue',
                kind: VisualDataRoleKind.Measure,
                displayName: data.createDisplayNameGetter('Role_DisplayName_MaxValue'),

            }, {
                name: 'QualitativeState1Value',
                kind: VisualDataRoleKind.Measure,
                displayName: 'Qualitative State 1',
            }, {
                name: 'QualitativeState2Value',
                kind: VisualDataRoleKind.Measure,
                displayName: 'Qualitative State 2',
            }, {
                name: 'QualitativeState3Value',
                kind: VisualDataRoleKind.Measure,
                displayName: 'Qualitative State 3',
            }
        ],
        objects: {

            general: {
                displayName: data.createDisplayNameGetter('Visual_General'),
                properties: {
                    fill: {
                        displayName: 'Main Color',
                        type: { fill: { solid: { color: true } } }
                    },
                    fill2: {
                        displayName: 'Comparison Color',
                        type: { fill: { solid: { color: true } } }
                    },
                },
            },

            label: {
                displayName: "Label",
                properties: {
                    show: {
                        displayName: data.createDisplayNameGetter('Visual_Show'),
                        type: { bool: true }
                    },
                    text: {
                        displayName: 'Label',
                        type: { text: true }
                    },
                    text2: {
                        displayName: 'Sub Label',
                        type: { text: true }
                    },
                },
            },
        },
        dataViewMappings: [{
            conditions: [
                { 'Y': { max: 1 }, 'ComparisonValue': { max: 1 }, 'TargetValue': { max: 1 }, 'MinValue': { max: 1 }, 'MaxValue': { max: 1 }, 'QualitativeState1Value': { max: 1 }, 'QualitativeState2Value': { max: 1 }, 'QualitativeState3Value': { max: 1 } },
            ],
            categorical: {
                values: {
                    select: [
                        { bind: { to: 'Y' } },
                        { bind: { to: 'ComparisonValue' } },
                        { bind: { to: 'TargetValue' } },
                        { bind: { to: 'MaxValue' } },
                        { bind: { to: 'QualitativeState1Value' } },
                        { bind: { to: 'QualitativeState2Value' } },
                        { bind: { to: 'QualitativeState3Value' } },
                    ]
                },
            },
        }],
        suppressDefaultTitle: true,
    };

    //One time setup
    public init(options: VisualInitOptions): void {
        this.svg = d3.select(options.element.get(0))
            .append('svg')
            .classed('bullet', true);

        this.svgBullet = this.svg
            .append('g');

        var labels = this.svgBullet
            .append('g')
            .style('text-anchor', 'end')
            .style("position", "relative")
            .style("z-index", "9999");

        this.svgTitle = labels
            .append('text')
            .attr("dx", "-1em")       //localizaçaõ do texto
            .classed('title', true);

        this.svgSubtitle = labels
            .append('text')
            .attr('dy', '1em')         //localizaçaõ do texto
            .classed('subtitle', true);
    }

    //Convert the dataview into its view model
    public static converter(dataView: DataView): BulletCharttestBI4ALL {

        var data: BulletCharttestBI4ALL = BulletCharttestBI4ALL1.getDefaultData();

        if (dataView.categorical) {

            if (dataView.metadata) {
                var objects = dataView.metadata.objects;

                if (objects) {
                    data.color = DataViewObjects.getFillColor(objects, bulletChartProps.general.fill, data.color);
                    data.color2 = DataViewObjects.getFillColor(objects, bulletChartProps.general.fill2, data.color2);
                    data.label = DataViewObjects.getValue(objects, bulletChartProps.label.text, data.label);
                    data.label2 = DataViewObjects.getValue(objects, bulletChartProps.label.text2, data.label2);
                    data.showLabel = DataViewObjects.getValue(objects, bulletChartProps.label.show, data.showLabel);
                }

                var toolTipItems = [];

                var values = dataView.categorical.values;

                if (values && dataView.metadata.columns) {
                    for (var i = 0; i < values.length; i++) {

                        var col = dataView.metadata.columns[i];
                        var value = values[i].values[0] || 0;
                        if (col && col.roles) {

                            var pushToTooltips = false;

                            if (col.roles['Y']) {
                                data.value = value;
                                pushToTooltips = true;

                            } else if (col.roles['MaxValue']) {
                                data.max = value;
                            } else if (col.roles['TargetValue']) {
                                data.target = value;
                                pushToTooltips = true;
                            } else if (col.roles['ComparisonValue']) {
                                data.comparison = value;
                                pushToTooltips = true;
                            } else if (col.roles['QualitativeState1Value'] || col.roles['QualitativeState2Value'] || col.roles['QualitativeState3Value']) {
                                if (value)
                                    data.states.push(value);
                            }

                            if (value && pushToTooltips)
                                toolTipItems.push({ value: value, metadata: values[i] });
                        }
                    }
                }

                if (toolTipItems.length > 0) {
                    data.toolTipInfo = TooltipBuilder.createTooltipInfo({
                        objectName: 'general',
                        propertyName: 'formatString',
                    }, null, null, null, null, toolTipItems);
                }
            }
        }

        return data;
    }

   //Drawing the visual
    public update(options: VisualUpdateOptions) {
        if (!options.dataViews || !options.dataViews[0]) return;
        var dataView = this.dataView = options.dataViews[0];
        var viewport = options.viewport;

        this.data = BulletCharttestBI4ALL1.converter(dataView);

        var maxValue = Math.max(this.data.target, this.data.value, this.data.comparison, this.data.max);
        if (this.data.states.length === 0)
            this.data.states = [Math.ceil(maxValue) / 3, (Math.ceil(maxValue) / 3) * 2, Math.ceil(maxValue)];

        var sortedRanges = this.data.states.slice().sort(d3.descending);
        sortedRanges.unshift(maxValue+1);

        var titleWidth = TextMeasurementService.measureSvgTextWidth({ fontFamily: 'tahoma', fontSize: '16px', text: this.data.label });
        var showSubtitle = (this.data.label2.length > 0);
        var subtitleWidth = TextMeasurementService.measureSvgTextWidth({ fontFamily: 'tahoma', fontSize: '12px', text: this.data.label2 });
        var labelWidth = (this.data.showLabel ? Math.max(titleWidth, subtitleWidth) : 0);

        var height = 25;
        var width = viewport.width - 50;



        this.svg
            .attr({
                'height': 60,
                'width': viewport.width - 40
            });


         if (this.data.showLabel) {

            this.svgBullet.attr('transform', 'translate(' + (labelWidth + 20) + ',5)');

            this.svgTitle
                .attr("position", "absolute")
                .style('display', 'block')
                .attr("text-anchor", "middle")
                .attr('transform', 'translate(30,' + ((height / 2) + (showSubtitle ? 0 : 5)) + ')')
                .text(this.data.label)
                .style("z-index", "10000");


            if (showSubtitle) {
                this.svgSubtitle
                    .style('display', 'block')
                    .attr("position", "absolute")
                    .style("z-index", "10000")
                    .attr('transform', 'translate(30,' + ((height / 2) - 5) + ')')
                    .text(this.data.label2);
            } else {
                this.svgSubtitle.style('display', 'none');
            }



        } else {
                            this.svgBullet.attr('transform', 'translate(10,50)');
            this.svgTitle.style('display', 'none');
            this.svgSubtitle.style('display', 'none');
        }       





        //Scale on X-axis
        var scale = d3.scale.linear()
            .domain([0, Math.max(sortedRanges[0], this.data.target, this.data.value)])
            .range([0, width]);

        //Ranges
        var range = this.svgBullet.selectAll('rect.range')
            .data(sortedRanges);

        range.enter()
            .append('rect')
            .attr('class', function (d, i) { return 'range s' + i; });

        range
            .attr('x', 0)
            .attr('width', function (d) { return Math.abs(scale(d) - scale(0)); })
            .attr('height', height);

        //Comparison measure
        this.svgBullet.selectAll('rect.measure').remove();
        if (this.data.comparison > 0) {
            var comparison = this.svgBullet
                .append('rect')
                .classed('measure', true)
                .style('fill', this.data.color2);

            comparison
                .attr('width', scale(this.data.comparison))
                .attr('height', height)
                .attr('x', 0)
                .attr('y', height - 25);
        }

        //Main measure


        var measure = this.svgBullet
            .append('rect')
            .style("height", height)
            .classed('measure', true)
            .style("z-index", "0")
            .attr("position", "relative")
            .attr("z-index", "0")
            .style('fill', this.data.color);

        measure
            .attr('width', scale(this.data.value))
            .attr('height', height - 25)
            .attr('x', 0)
            .attr("z-index", "0")
            .attr('y', height - 25);

        //Target markers
        this.svgBullet.selectAll('line.marker').remove();
        var marker = this.svgBullet
            .append('line')
            .classed('marker', true);

        marker
            .attr('x1', scale(this.data.target))
            .attr('x2', scale(this.data.target))
            .attr('y1', height / 20)
            .attr('y2', height + 2);

        //Ticks
        var format = scale.tickFormat(10);

        var tick = this.svgBullet.selectAll('g.tick')
            .data(scale.ticks(10), function (d) {
                return this.textContent || format(d);
            });

        var tickEnter = tick.enter()
            .append('g')
            .attr('class', 'tick');

        tickEnter.append('line')
            .attr('y1', height)
            .attr('y2', height * 7 / 6);

        tickEnter
            .append('text')
            .attr('text-anchor', 'middle')
            .attr('dy', '1em')
            .attr('y', height * 7 / 6)
            .text(format);

        tickEnter
            .attr('transform', function (d) {
                return 'translate(' + scale(d) + ',0)';
            });

        var tickUpdate = tick.transition()
            .duration(0)
            .attr('transform', function (d) {
                return 'translate(' + scale(d) + ',0)';
            })
            .style('opacity', 1);

        tickUpdate.select('line')
            .attr('y1', height)
            .attr('y2', height * 7 / 6);

        tickUpdate.select('text')
            .attr('y', height * 7 / 6);

        tick.exit().transition()
            .duration(0)
            .attr('transform', function (d) {
                return 'translate(' + scale(d) + ',0)';
            })
            .style('opacity', 1e-6)
            .remove();

        TooltipManager.addTooltip(this.svgBullet, (tooltipEvent: TooltipEvent) => this.data.toolTipInfo);
    } 

    //Make visual properties available in the property pane in Power BI
    public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
        var enumeration = new ObjectEnumerationBuilder();

        if (!this.data)
            this.data = BulletCharttestBI4ALL1.getDefaultData();

        switch (options.objectName) {
            case 'general':
                enumeration.pushInstance({
                    objectName: 'general',
                    displayName: 'Cores das Barras',
                    selector: null,
                    properties: {
                        fill: this.data.color,       //PROPRIEDADES
                        fill2: this.data.color2
                    }
                });
                break;

            case 'label':
                enumeration.pushInstance({
                    objectName: 'label',
                    displayName: 'Título',
                    selector: null,
                    properties: {
                        show: this.data.showLabel,   //PROPRIEDADES
                        text: this.data.label,
                        text2: this.data.label2
                    }
                });
                break;



        }

        return enumeration.complete();
    }

    //Free up resources
    public destroy(): void {
        this.svg = null;
        this.svgTitle = this.svgSubtitle = this.svgBullet = null;
    }
}
}

If someone could enlighten me, i would appreciate it, Cheers


Solution

  • So after some hard thinking, i figure it out.

    For the first part, the problem was that, power bi does not let you upload the same graph with some modifications, i had to change the naming in the code so that it'll assume the different graph.

    The second part was the tricky one, after moving around i found that the codes always broke, so i thought that calling the title again would do the trick, so it did! I hidden the other title and called again after the bar is drawn.

    Revised code:

     module powerbi.visuals {
    
    //Model
    export interface BulletCharttestBI4ALL1 {
        label: string;
        label2: string;
        showLabel: boolean;
        color: string;
        color2: string;
        states: number[];
        value: number;
        target: number;
        comparison: number;
        min: number;
        max: number;
        selector: data.Selector;
        toolTipInfo: TooltipDataItem[];
    }
    
    export var bulletChartProps = {   //PROPRIEDADES para o power BI  // Replicar  linha 187  e  427
        general: {
            fill: <DataViewObjectPropertyIdentifier>{ objectName: 'Cores', propertyName: 'fill' },
            fill2: <DataViewObjectPropertyIdentifier>{ objectName: 'Cores', propertyName: 'fill2' },
        },
        label: {
            show: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'show' },
            text: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'text' },
            text2: <DataViewObjectPropertyIdentifier>{ objectName: 'Titulo', propertyName: 'text2' }
        },
    };
    
    //Visual
    export class BulletCharttestBI4ALL2 implements IVisual {
    
        //Variables
    
        private svg: D3.Selection;
        private svgBullet: D3.Selection;
        private svgTitle: D3.Selection;
        private svgSubtitle: D3.Selection;
    
    
        private dataView: DataView;
        private data: BulletCharttestBI4ALL1;
    
        public static getDefaultData(): BulletCharttestBI4ALL1 {
            return {
                color: '#36bba3',
                color2: 'lightsteelblue',
                label: 'YTD stuff',
                label2: '2015',
                showLabel: true,
                states: [],
                min: 0,
                max: 100,
                value: 0,
                target: 0,
                comparison: 0,
                toolTipInfo: [],
                selector: SelectionId.createNull().getSelector()
            };
        }
    
        //Capabilities
        public static capabilities: VisualCapabilities = {
            dataRoles: [
                 {
                    name: 'Y',
                    kind: VisualDataRoleKind.Measure,
                    displayName: data.createDisplayNameGetter('Role_DisplayName_Value'),
                }, {
                    name: 'ComparisonValue',
                    kind: VisualDataRoleKind.Measure,
                    displayName: 'Comparison Value',
                }, {
                    name: 'TargetValue',
                    kind: VisualDataRoleKind.Measure,
                    displayName: data.createDisplayNameGetter('Role_DisplayName_TargetValue'),
                }, {
                    name: 'MinValue',
                    kind: VisualDataRoleKind.Measure,
                    displayName: data.createDisplayNameGetter('Role_DisplayName_MinValue'),
                }, {
                    name: 'MaxValue',
                    kind: VisualDataRoleKind.Measure,
                    displayName: data.createDisplayNameGetter('Role_DisplayName_MaxValue'),
    
                }, {
                    name: 'QualitativeState1Value',
                    kind: VisualDataRoleKind.Measure,
                    displayName: 'Qualitative State 1',
                }, {
                    name: 'QualitativeState2Value',
                    kind: VisualDataRoleKind.Measure,
                    displayName: 'Qualitative State 2',
                }, {
                    name: 'QualitativeState3Value',
                    kind: VisualDataRoleKind.Measure,
                    displayName: 'Qualitative State 3',
                }
            ],
            objects: {
    
                general: {
                    displayName: data.createDisplayNameGetter('Visual_General'),
                    properties: {
                        fill: {
                            displayName: 'Main Color',
                            type: { fill: { solid: { color: true } } }
                        },
                        fill2: {
                            displayName: 'Comparison Color',
                            type: { fill: { solid: { color: true } } }
                        },
                    },
                },
    
                label: {
                    displayName: "Label",
                    properties: {
                        show: {
                            displayName: data.createDisplayNameGetter('Visual_Show'),
                            type: { bool: true }
                        },
                        text: {
                            displayName: 'Label',
                            type: { text: true }
                        },
                        text2: {
                            displayName: 'Sub Label',
                            type: { text: true }
                        },
                    },
                },
            },
            dataViewMappings: [{
                conditions: [
                    { 'Y': { max: 1 }, 'ComparisonValue': { max: 1 }, 'TargetValue': { max: 1 }, 'MinValue': { max: 1 }, 'MaxValue': { max: 1 }, 'QualitativeState1Value': { max: 1 }, 'QualitativeState2Value': { max: 1 }, 'QualitativeState3Value': { max: 1 } },
                ],
                categorical: {
                    values: {
                        select: [
                            { bind: { to: 'Y' } },
                            { bind: { to: 'ComparisonValue' } },
                            { bind: { to: 'TargetValue' } },
                            { bind: { to: 'MaxValue' } },
                            { bind: { to: 'QualitativeState1Value' } },
                            { bind: { to: 'QualitativeState2Value' } },
                            { bind: { to: 'QualitativeState3Value' } },
                        ]
                    },
                },
            }],
            suppressDefaultTitle: true,
        };
    
        //One time setup
        public init(options: VisualInitOptions): void {
            this.svg = d3.select(options.element.get(0))
                .append('svg')
                .classed('bullet', true);
    
            this.svgBullet = this.svg
                .append('g');
    
            var labels = this.svgBullet
                .append('g')
                .style('text-anchor', 'end');
    
            this.svgTitle = labels
                .append('text')
                .attr("dx", "-1em")       //localizaçaõ do texto
                .classed('title', true);
    
            this.svgSubtitle = labels
                .append('text')
                .attr('dy', '1em')
                .classed('subtitle', true);
        }
    
        //Convert the dataview into its view model
        public static converter(dataView: DataView): BulletCharttestBI4ALL1 {
    
            var data: BulletCharttestBI4ALL1 = BulletCharttestBI4ALL2.getDefaultData();
    
            if (dataView.categorical) {
    
                if (dataView.metadata) {
                    var objects = dataView.metadata.objects;
    
                    if (objects) {
                        data.color = DataViewObjects.getFillColor(objects, bulletChartProps.general.fill, data.color);
                        data.color2 = DataViewObjects.getFillColor(objects, bulletChartProps.general.fill2, data.color2);
                        data.label = DataViewObjects.getValue(objects, bulletChartProps.label.text, data.label);
                        data.label2 = DataViewObjects.getValue(objects, bulletChartProps.label.text2, data.label2);
                        data.showLabel = DataViewObjects.getValue(objects, bulletChartProps.label.show, data.showLabel);
                    }
    
                    var toolTipItems = [];
    
                    var values = dataView.categorical.values;
    
                    if (values && dataView.metadata.columns) {
                        for (var i = 0; i < values.length; i++) {
    
                            var col = dataView.metadata.columns[i];
                            var value = values[i].values[0] || 0;
                            if (col && col.roles) {
    
                                var pushToTooltips = false;
    
                                if (col.roles['Y']) {
                                    data.value = value;
                                    pushToTooltips = true;
    
                                } else if (col.roles['MaxValue']) {
                                    data.max = value;
                                } else if (col.roles['TargetValue']) {
                                    data.target = value;
                                    pushToTooltips = true;
                                } else if (col.roles['ComparisonValue']) {
                                    data.comparison = value;
                                    pushToTooltips = true;
                                } else if (col.roles['QualitativeState1Value'] || col.roles['QualitativeState2Value'] || col.roles['QualitativeState3Value']) {
                                    if (value)
                                        data.states.push(value);
                                }
    
                                if (value && pushToTooltips)
                                    toolTipItems.push({ value: value, metadata: values[i] });
                            }
                        }
                    }
    
                    if (toolTipItems.length > 0) {
                        data.toolTipInfo = TooltipBuilder.createTooltipInfo({
                            objectName: 'general',
                            propertyName: 'formatString',
                        }, null, null, null, null, toolTipItems);
                    }
                }
            }
    
            return data;
        }
    
       //Drawing the visual
        public update(options: VisualUpdateOptions) {
            if (!options.dataViews || !options.dataViews[0]) return;
            var dataView = this.dataView = options.dataViews[0];
            var viewport = options.viewport;
    
            this.data = BulletCharttestBI4ALL2.converter(dataView);
    
            var maxValue = Math.max(this.data.target, this.data.value, this.data.comparison, this.data.max);
            if (this.data.states.length === 0)
                this.data.states = [Math.ceil(maxValue) / 3, (Math.ceil(maxValue) / 3) * 2, Math.ceil(maxValue)];
    
            var sortedRanges = this.data.states.slice().sort(d3.descending);
            sortedRanges.unshift(maxValue+1);
    
            var titleWidth = TextMeasurementService.measureSvgTextWidth({ fontFamily: 'tahoma', fontSize: '16px', text: this.data.label });
            var showSubtitle = (this.data.label2.length > 0);
            var subtitleWidth = TextMeasurementService.measureSvgTextWidth({ fontFamily: 'tahoma', fontSize: '12px', text: this.data.label2 });
            var labelWidth = (this.data.showLabel ? Math.max(titleWidth, subtitleWidth) : 0);
    
            var height = 25;
            var width = viewport.width - 50;
    
    
            this.svg      // Coloca conteúdo dentro das variaveis
                .attr({
                    'height': 60,
                    'width': viewport.width - 40
                });
    
    
    
             if (this.data.showLabel) {       // Coloca conteúdo dentro das variaveis
    
                this.svgBullet.attr('transform', 'translate(' + (labelWidth + 20) + ',5)');
    
                this.svgTitle
                    .attr("position", "absolute")
                    .style('display', 'block')
                    .attr("text-anchor", "middle")
                    .attr('transform', 'translate(30,' + ((height / 2) + (showSubtitle ? 0 : 5)) + ')')
                  //  .text(this.data.label)
                    .style("z-index", "10000");
    
    
                if (showSubtitle) {
                    this.svgSubtitle
                        .style('display', 'block')
                        .attr("position", "absolute")
                        .style("z-index", "10000")
                        .attr('transform', 'translate(30,' + ((height / 2) - 2) + ')')
                        //.text(this.data.label2);
                } else {
                    this.svgSubtitle.style('display', 'none');
                }
    
    
    
            } else {
                this.svgBullet.attr('transform', 'translate(10,50)');
                this.svgTitle.style('display', 'none');
                this.svgSubtitle.style('display', 'none');
            }  
    
    
            //Scale on X-axis
            var scale = d3.scale.linear()
                .domain([0, Math.max(sortedRanges[0], this.data.target, this.data.value)])
                .range([0, width]);
    
            //Ranges       (NÃO É USADO)
            var range = this.svgBullet.selectAll('rect.range')
                .data(sortedRanges);
    
            range.enter()
                .append("g")     //NB
                .append('rect')
                .attr('class', function (d, i) { return 'range s' + i; });
    
            range
                .attr('x', 0)
                .attr('width', function (d) { return Math.abs(scale(d) - scale(0)); })
                .attr('height', height);
    
    
            //Comparison measure       (NAO É UUSADO)
            this.svgBullet.selectAll('rect.measure').remove();
            if (this.data.comparison > 0) {
                var comparison = this.svgBullet
                    .append("g")                  //NB
                    .append('rect')
                    .classed('measure', true)
                    .style('fill', this.data.color2);
    
                comparison
                    .attr('width', scale(this.data.comparison))
                    .attr('height', height)
                    .attr('x', 0)
                    .attr('y', height - 25);
            }
    
    
            //Main measure      //  Barra principal
            var measure = this.svgBullet
                .append("g")    //NB
                .append('rect')
                .style("height", height)
                .classed('measure', true)
                .style('fill', this.data.color);
    
    
            measure        //  Barra principal
                .attr('width', scale(this.data.value))
                .attr('height', height - 25)
                .attr('x', 0)
                .attr("z-index", "0")
                .attr('y', height - 25);
    
    
             this.svgBullet        //Coloca texto em cima da barra   YEY!!!!!!!!!!!!!!!!!!!!!!!!!!!
                .append("text")
                .text(this.data.label)
                .attr("text-anchor", "middle")
                .attr('transform', 'translate(40,' + ((height / 1.4) + (showSubtitle ? 0 : 5)) + ')'); 
    
    
            //Target markers     TARGET
            this.svgBullet.selectAll('line.marker').remove();
            var marker = this.svgBullet
                .append('line')
                .classed('marker', true);
    
            marker
                .attr('x1', scale(this.data.target))
                .attr('x2', scale(this.data.target))
                .attr('y1', height / 20)
                .attr('y2', height + 2);
    
            //Ticks    (NAO USADO)
            var format = scale.tickFormat(10);
    
            var tick = this.svgBullet.selectAll('g.tick')
                .data(scale.ticks(10), function (d) {
                    return this.textContent || format(d);
                });
    
            var tickEnter = tick.enter()
                .append('g')
                .attr('class', 'tick');
    
            tickEnter.append('line')
                .attr('y1', height)
                .attr('y2', height * 7 / 6);
    
            tickEnter
                .append('text')
                .attr('text-anchor', 'middle')
                .attr('dy', '1em')
                .attr('y', height * 7 / 6)
                .text(format);
    
            tickEnter
                .attr('transform', function (d) {
                    return 'translate(' + scale(d) + ',0)';
                });
    
            var tickUpdate = tick.transition()
                .duration(0)
                .attr('transform', function (d) {
                    return 'translate(' + scale(d) + ',0)';
                })
                .style('opacity', 1);
    
            tickUpdate.select('line')
                .attr('y1', height)
                .attr('y2', height * 7 / 6);
    
            tickUpdate.select('text')
                .attr('y', height * 7 / 6);
    
            tick.exit().transition()
                .duration(0)
                .attr('transform', function (d) {
                    return 'translate(' + scale(d) + ',0)';
                })
                .style('opacity', 1e-6)
                .remove();
    
            TooltipManager.addTooltip(this.svgBullet, (tooltipEvent: TooltipEvent) => this.data.toolTipInfo);
        } 
    
        //Make visual properties available in the property pane in Power BI
        public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration {
            var enumeration = new ObjectEnumerationBuilder();
    
            if (!this.data)
                this.data = BulletCharttestBI4ALL2.getDefaultData();
    
            switch (options.objectName) {
                case 'general':
                    enumeration.pushInstance({
                        objectName: 'general',
                        displayName: 'Cores das Barras',
                        selector: null,
                        properties: {
                            fill: this.data.color,       //PROPRIEDADES
                            fill2: this.data.color2
                        }
                    });
                    break;
    
                case 'label':
                    enumeration.pushInstance({
                        objectName: 'label',
                        displayName: 'Título',
                        selector: null,
                        properties: {
                            show: this.data.showLabel,   //PROPRIEDADES
                            text: this.data.label,
                            text2: this.data.label2
                        }
                    });
                    break;
    
    
    
            }
    
            return enumeration.complete();
        }
    
        //Free up resources
        public destroy(): void {
            this.svg = null;
            this.svgTitle = this.svgSubtitle = this.svgBullet = null;
        }
    }
    }