Quantcast
Channel: Developer topics
Viewing all articles
Browse latest Browse all 17878

Adding ToolTips with Table DataBinding

$
0
0

I've created a custom visual (combination scatter plot and dual-line graph) and am attempting to add tooltips. I used table databinding and followed an example I found here for assigning an Identity. For some reason, the tooltips are each only showing one line (employee ID) and the ID is the same for each tooltip.

 

import DataViewObjects = powerbi.extensibility.utils.dataview.DataViewObjects;

module powerbi.extensibility.visual {
    "use strict";
    interface DataPoint {
        grade: number;
        minimum: number;
        maximum: number;
    };

    interface ViewModel {
        dataPoints: DataPoint[];
        rangePenData: RangePoint[];
        maxValue: number;
        minValue: number;
        maxGrade: number;
        minGrade: number;
    };

    interface RangePoint {
        grade: number;
        rangePen: number;
        employeeID: string;
        tooltips: VisualTooltipDataItem[];
        identity: ISelectionId[];
    }

    export class Visual implements IVisual {

        private host: IVisualHost;
        private svg: d3.Selection<SVGElement>;
        private structureGroup: d3.Selection<SVGElement>;
        private yPadding: number = 0.1;
        private scatterGroup: d3.Selection<SVGElement>;
        private xAxisGroup: d3.Selection<SVGElement>;
        private yAxisGroup: d3.Selection<SVGElement>;

        private settings = {
            axis: {
                x: {
                    padding: 25
                },
                y: {
                    padding: 50
                }
            },
            border: {
                top: 10
            }
        }

        constructor(options: VisualConstructorOptions) {
            this.host = options.host;
            this.svg = d3.select(options.element)
                .append("svg")
                .classed("vchart", true);
            this.structureGroup = this.svg.append("g")
                .classed("structure-group", true);
            this.scatterGroup = this.svg.append("g")
                .classed("scatter-group", true);
            this.xAxisGroup = this.svg.append("g")
                .classed("x-axis", true)
            this.yAxisGroup = this.svg.append("g")
                .classed("y-axis", true)
        }

        public update(options: VisualUpdateOptions) {

            let viewModel = this.getViewModel(options)
            
            let spread = Math.max(Math.abs(viewModel.minValue),Math.abs(viewModel.maxValue))

            let width = options.viewport.width;
            let height = options.viewport.height;

            this.svg.attr({
                width: width,
                height: height,
            });

            let xScale = d3.scale.linear()
                .domain([spread*-1,spread])
                .range([this.settings.axis.x.padding, width]);
            
            let xAxis = d3.svg.axis()
                .scale(xScale)
                .orient("bottom")
                .tickSize(1);

            this.xAxisGroup.call(xAxis)
            .attr({
              transform: "translate(0, " + (height-this.settings.axis.x.padding) + ")"  
            });

            let yScale = d3.scale.linear()
                .domain([viewModel.maxGrade,viewModel.minGrade])
                .range([0 + this.settings.border.top, height - this.settings.axis.x.padding]);

            let yAxis = d3.svg.axis()
                .scale(yScale)
                .orient("left")
                .tickSize(1);

            this.yAxisGroup
            .call(yAxis)
            .attr({
                transform: "translate(" + (width + this.settings.axis.y.padding)/2 + ",0)"
            })
            .selectAll("text")
            .style({
                "text-anchor": "end",
                "font-size": "small"
            });

            var valueline = d3.svg.line<DataPoint>()
                .x(function (d) { return xScale(d.minimum); })
                .y(function (d) { return yScale(d.grade); })

            var valueline2 = d3.svg.line<DataPoint>()
                .x(function (d) { return xScale(d.maximum); })
                .y(function (d) { return yScale(d.grade); })

            let minline = this.structureGroup
                .selectAll(".minline")
                .data([viewModel.dataPoints]);

            minline
                .enter()
                .append("path")
                .attr("class", "minline");

            minline
                .attr("d", function (d) { return valueline(d); })
                .style({
                    stroke: "green",
                    fill: "none",
                    "stroke-width": "3px",
                });

            minline.exit()
                .remove();

            let maxline = this.structureGroup
                .selectAll(".maxline")
                .data([viewModel.dataPoints]);

            maxline
                .enter()
                .append("path")
                .attr("class", "maxline");

            maxline
                .attr("d", function (d) { return valueline2(d); })
                .style({
                    stroke: "green",
                    fill: "none",
                    "stroke-width": "3px",
                });

            maxline.exit()
                .remove();    
            
            let scatter = this.scatterGroup
                .selectAll(".rangePen")
                .data(viewModel.rangePenData)

            scatter
                .enter()
                .append("circle")
                .attr("class", "rangePen")
            
            scatter
                .attr("cx", d => xScale(d.rangePen))
                .attr("cy", d => yScale(d.grade))
                .attr("r", 5)
                .on("mouseover", (d) => {
                    let mouse=d3.mouse(this.svg.node());
                    let x=mouse[0];
                    let y=mouse[1];
                    this.host.tooltipService.show({
                        dataItems: d.tooltips,
                        identities: [d.identity],
                        coordinates: [x, y],
                        isTouchEvent: false
                    })
                })

            scatter.exit()
                .remove();

        }
        


        private getViewModel(options: VisualUpdateOptions): ViewModel {

            let dv = options.dataViews;

            let viewModel: ViewModel = {
                dataPoints: [],
                rangePenData: [],
                maxValue: 0,
                minValue: 0,
                maxGrade: 0,
                minGrade: 0,
                
            };

            let view1 = dv[0].table;
            let view2 = dv[0];

            for (let i = 0, len = view1.rows.length; i < len; i++) {
                viewModel.dataPoints.push({
                    grade: <number>view1.rows[i][1],
                    minimum: <number>view1.rows[i][2]/-2,
                    maximum: <number>view1.rows[i][2]/2,
                });


                viewModel.rangePenData.push({
                    grade: <number>view1.rows[i][1],
                    rangePen: <number>view1.rows[i][3],
                    employeeID: <string>view1.rows[i][0],
                    identity: this.getSelectionIds(view2, this.host),
                    tooltips: [{
                        displayName: "Employee ID:",
                        value: <string>view1.rows[i][0]
                    },
                    {
                        displayName: "Range Penetration:",
                        value: <string>view1.rows[i][3]
                    }
                ]
                });
            }

            
            viewModel.maxValue = d3.max([d3.max(viewModel.dataPoints, d => d.maximum),d3.max(viewModel.rangePenData, d => d.rangePen)]);
            viewModel.minValue = d3.min([d3.min(viewModel.dataPoints, d => d.minimum),d3.min(viewModel.rangePenData, d => d.rangePen)]); 
            viewModel.maxGrade = d3.max(viewModel.rangePenData, d => d.grade);
            viewModel.minGrade = d3.min(viewModel.rangePenData, d => d.grade);

            return viewModel;
        }

        public getSelectionIds(dataView: DataView, host: IVisualHost): ISelectionId[] {
 
            return dataView.table.identity.map((identity: DataViewScopeIdentity) => {
            const categoryColumn: DataViewCategoryColumn = {
            source: dataView.table.columns[0],
            values: null,
            identity: [identity]
            };
            return host.createSelectionIdBuilder()
            .withCategory(categoryColumn, 0)
            .createSelectionId();
            })
            };

    }
}
 

Viewing all articles
Browse latest Browse all 17878

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>