public render()

in src/UXClient/Components/PieChart/PieChart.ts [29:249]


    public render(data: any, options: any, aggregateExpressionOptions: any) {
        super.render(data, options, aggregateExpressionOptions);

        this.chartComponentData.mergeDataToDisplayStateAndTimeArrays(this.data, this.chartOptions.timestamp, this.aggregateExpressionOptions);
        var timestamp = (options && options.timestamp != undefined) ? options.timestamp : this.chartComponentData.allTimestampsArray[0];
 
        var targetElement = d3.select(this.renderTarget)
                                .classed("tsi-pieChart", true);

        if (this.svgSelection == null) {
            
            this.svgSelection = targetElement.append("svg")
                .attr("class", "tsi-pieChartSVG tsi-chartSVG")
                .attr('title', this.getString('Pie chart'));
            var g = this.svgSelection.append("g");
            var tooltip = new Tooltip(d3.select(this.renderTarget));
            d3.select(this.renderTarget).append('div').classed('tsi-sliderWrapper', true);

            this.draw = (isFromResize = false) => {
                // Determine the number of timestamps present, add margin for slider
                if(this.chartComponentData.allTimestampsArray.length > 1)
                    this.chartMargins.bottom = 68;
                if(this.chartOptions.legend == "compact") {
                    this.chartMargins.top = 68;
                } else {
                    this.chartMargins.top = 20;
                }

                this.width = this.getWidth();
                var height = +targetElement.node().getBoundingClientRect().height;
                if (!isFromResize) {
                    this.chartWidth = this.getChartWidth();
                }
                var chartHeight = height;
                var usableHeight = height - this.chartMargins.bottom - this.chartMargins.top
                var outerRadius = (Math.min(usableHeight, this.chartWidth) - 10) / 2;
                var innerRadius = this.chartOptions.arcWidthRatio && 
                                    (this.chartOptions.arcWidthRatio < 1 && this.chartOptions.arcWidthRatio > 0) ? 
                                    outerRadius - (outerRadius * this.chartOptions.arcWidthRatio) :
                                    0;
                this.svgSelection
                    .attr("width", this.chartWidth)
                    .attr("height", chartHeight)
                this.svgSelection.select("g").attr("transform", "translate(" + (this.chartWidth / 2)  + "," + (chartHeight / 2) + ")");

                var timestamp = (this.chartOptions.timestamp != undefined) ? this.chartOptions.timestamp : this.chartComponentData.allTimestampsArray[0];
                this.chartComponentData.updateFlatValueArray(timestamp);
                super.themify(targetElement, this.chartOptions.theme);


                if (!this.chartOptions.hideChartControlPanel && this.chartControlsPanel === null) {
                    this.chartControlsPanel = Utils.createControlPanel(this.renderTarget, this.CONTROLSWIDTH, this.chartMargins.top, this.chartOptions);
                } else  if (this.chartOptions.hideChartControlPanel && this.chartControlsPanel !== null){
                    this.removeControlPanel();
                }

                if (this.ellipsisItemsExist() && !this.chartOptions.hideChartControlPanel) {
                    this.drawEllipsisMenu();
                    this.chartControlsPanel.style("top", Math.max((this.chartMargins.top - 24), 0) + 'px');
                } else {
                    this.removeControlPanel();
                }


                var labelMouseover = (aggKey: string, splitBy: string = null) => {
                    //filter out the selected timeseries/splitby
                    var selectedFilter = (d: any, j: number ) => {
                        return !(d.data.aggKey == aggKey && (splitBy == null || d.data.splitBy == splitBy))
                    }
        
                    this.svgSelection.selectAll(".tsi-pie-path")
                                .filter(selectedFilter)
                                .attr("stroke-opacity", .3)
                                .attr("fill-opacity", .3);
                }

                var labelMouseout = (aggregateKey: string, splitBy: string) => {
                    this.svgSelection.selectAll(".tsi-pie-path")
                        .attr("stroke-opacity", 1)
                        .attr("fill-opacity", 1);
                }

                function drawTooltip (d: any, mousePosition) {
                    var xPos = mousePosition[0];
                    var yPos = mousePosition[1];
                    tooltip.render(self.chartOptions.theme);
                    let color = Utils.colorSplitBy(self.chartComponentData.displayState, d.data.splitByI, d.data.aggKey, self.chartOptions.keepSplitByColor);
                    tooltip.draw(d, self.chartComponentData, xPos, yPos, {...self.chartMargins, top: 0, bottom: 0}, (text) => {
                        self.tooltipFormat(self.convertToTimeValueFormat(d.data), text, TooltipMeasureFormat.SingleValue);
                    }, null, 20, 20, color);
                }

                this.legendObject.draw(this.chartOptions.legend, this.chartComponentData, labelMouseover, 
                    this.svgSelection, this.chartOptions, labelMouseout);
                var pie = d3.pie()
                    .sort(null)
                    .value(function(d: any) { 
                        return Math.abs(d.val); 
                    });
                
                var path: any = d3.arc()
                    .outerRadius(outerRadius)
                    .innerRadius(innerRadius);
                
                var arc = g.selectAll(".tsi-pie-arc")
                    .data(pie(this.chartComponentData.flatValueArray));
                var arcEntered = arc
                    .enter().append("g")
                    .merge(arc)
                    .attr("class", "tsi-pie-arc");
                var self = this;

                var drawArc = d3.arc()
                    .innerRadius(innerRadius)
                    .outerRadius(outerRadius);

                function arcTween(a) {
                    var i = d3.interpolate(this._current, a);
                    this._current = i(0);
                    return function(t) {
                      return drawArc(i(t));
                    };
                  }

                var self = this;
                function pathMouseout (d: any) {
                    if (self.contextMenu && self.contextMenu.contextMenuVisible)
                        return;
                    tooltip.hide();
                    labelMouseout(d.data.aggKey, d.data.splitBy);
                    (<any>self.legendObject.legendElement.selectAll('.tsi-splitByLabel')).classed("inFocus", false);
                } 

                function pathMouseInteraction (d: any)  {
                    if (this.contextMenu && this.contextMenu.contextMenuVisible)
                        return;
                    pathMouseout(d); 
                    labelMouseover(d.data.aggKey, d.data.splitBy);
                    (<any>self.legendObject.legendElement.selectAll('.tsi-splitByLabel').filter(function (filteredSplitBy: string) {
                        return (d3.select(this.parentNode).datum() == d.data.aggKey) && (filteredSplitBy == d.data.splitBy);
                    })).classed("inFocus", true);
                    drawTooltip(d, d3.mouse(self.svgSelection.node()));
                }

                var mouseOutArcOnContextMenuClick = () => {
                    arcEntered.selectAll("path").each(pathMouseout);
                }

                arcEntered.each(function () {
                    var pathElem = d3.select(this).selectAll<SVGPathElement, unknown>(".tsi-pie-path").data(d => [d]);
                    var pathEntered = pathElem.enter()
                        .append("path")
                        .attr("class", "tsi-pie-path")
                        .attr("d", drawArc)
                        .on("mouseover", pathMouseInteraction)
                        .on("mousemove" , pathMouseInteraction)
                        .on("mouseout", pathMouseout)
                        .on("contextmenu", (d: any, i) => {
                            if (self.chartComponentData.displayState[d.data.aggKey].contextMenuActions && 
                                self.chartComponentData.displayState[d.data.aggKey].contextMenuActions.length) {
                                var mousePosition = d3.mouse(<any>targetElement.node());
                                d3.event.preventDefault();
                                self.contextMenu.draw(self.chartComponentData, self.renderTarget, self.chartOptions, 
                                                    mousePosition, d.data.aggKey, d.data.splitBy, mouseOutArcOnContextMenuClick,
                                                    new Date(self.chartComponentData.timestamp));
                            }
                        })
                        .each(function(d) { (<any>this)._current = d; })
                        .merge(pathElem as d3.Selection<SVGPathElement, unknown, any, unknown>)
                        .transition()
                        .duration(self.TRANSDURATION)
                        .ease(d3.easeExp)
                        .attrTween("d", arcTween)
                        .attr("fill", (d: any)  => { 
                            return Utils.colorSplitBy(self.chartComponentData.displayState, d.data.splitByI, d.data.aggKey, self.chartOptions.keepSplitByColor);
                        })
                        .attr("class", "tsi-pie-path");
                });
                arc.exit().remove();

                /******************** Temporal Slider ************************/
                if(this.chartComponentData.allTimestampsArray.length > 1){
                    d3.select(this.renderTarget).select('.tsi-sliderWrapper').classed('tsi-hidden', false);
                    slider.render(this.chartComponentData.allTimestampsArray.map(ts => {
                        var action = () => {
                            this.chartOptions.timestamp = ts;
                            this.render(this.chartComponentData.data, this.chartOptions, this.aggregateExpressionOptions);
                        }
                        return {label: Utils.timeFormat(this.chartComponentData.usesSeconds, this.chartComponentData.usesMillis, 
                            this.chartOptions.offset, this.chartOptions.is24HourTime, null, null, this.chartOptions.dateLocale)(new Date(ts)), action: action};
                    }), this.chartOptions, this.chartWidth, Utils.timeFormat(this.chartComponentData.usesSeconds, this.chartComponentData.usesMillis, 
                        this.chartOptions.offset, this.chartOptions.is24HourTime, null, null, this.chartOptions.dateLocale)(new Date(this.chartComponentData.timestamp)));
                }
                else{
                    slider.remove();
                    d3.select(this.renderTarget).select('.tsi-sliderWrapper').classed('tsi-hidden', true);
                }

            }

            this.legendObject = new Legend(this.draw, this.renderTarget, this.CONTROLSWIDTH);
            this.contextMenu = new ContextMenu(this.draw, this.renderTarget);
            
            // temporal slider
            var slider = new Slider(<any>d3.select(this.renderTarget).select('.tsi-sliderWrapper').node());
            window.addEventListener("resize", () => {
                if (!this.chartOptions.suppressResizeListener)
                    this.draw();
            });
        }
        this.draw();
        this.gatedShowGrid();

        d3.select("html").on("click." + Utils.guid(), () => {
            if (this.ellipsisContainer && d3.event.target != this.ellipsisContainer.select(".tsi-ellipsisButton").node()) {
                this.ellipsisMenu.setMenuVisibility(false);
            }
        });

        this.legendPostRenderProcess(this.chartOptions.legend, this.svgSelection, true);
    }