private renderLegend()

in src/visual.ts [1565:1761]


    private renderLegend(): void {
        let layers: IColumnChart[] = this.layers,
            legendData: ILegendData = {
                title: "",
                dataPoints: []
            };

        for (let i: number = 0; i < layers.length; i++) {
            this.layerLegendData = layers[i].calculateLegend();

            if (this.layerLegendData) {
                legendData.title = i === 0
                    ? this.layerLegendData.title || ""
                    : legendData.title;

                legendData.dataPoints = legendData.dataPoints
                    .concat(this.layerLegendData.dataPoints || []);

                if (this.layerLegendData.grouped) {
                    legendData.grouped = true;
                }
            }
        }

        const legendProperties: powerbi.DataViewObject = this.legendObjectProperties;

        if (legendProperties) {
            if (!legendProperties["fontSize"]) {
                legendProperties["fontSize"] = MekkoChart.DefaultLabelFontSizeInPt;
            }

            LegendData.update(legendData, legendProperties);

            const position: string = legendProperties[legendProps.position] as string;

            if (position) {
                this.legend.changeOrientation(LegendPosition[position]);
            }
        }
        else {
            this.legend.changeOrientation(LegendPosition.Top);
        }

        if ((legendData.dataPoints.length === 1 && !legendData.grouped) || this.hideLegends()) {
            legendData.dataPoints = [];
        }

        let reducedLegends: IGrouppedLegendData[] = [];
        let legendSortSettings: MekkoLegendSortSettings = (<BaseColumnChart>this.layers[0]).getLegendSortSettings();
        if (legendSortSettings.enabled) {
            if (legendSortSettings.groupByCategory) {
                let mappedLegends = legendData.dataPoints.map((dataPoint: MekkoLegendDataPoint) => {
                    let maxVal = max(dataPoint.categoryValues as Number[]);
                    let index = dataPoint.categoryValues.indexOf(maxVal as PrimitiveValue);
                    return {
                        categoryIndex: index,
                        data: dataPoint,
                        categoryValue: 0
                    };
                });

                mappedLegends.forEach(element => {
                    reducedLegends[element.categoryIndex] =
                        reducedLegends[element.categoryIndex] || {
                            category: this.layers[0].getData().categories[element.categoryIndex],
                            index: element.categoryIndex,
                            data: [],
                            dataValues: 0,
                            categorySorting: null
                        };
                    reducedLegends[element.categoryIndex].data.push(element.data);
                });
                reducedLegends.forEach(element => {
                    element.dataValues = sum(element.data.map((d) => d.valueSum));
                });

                reducedLegends.forEach(legend => {
                    if (legend === undefined) {
                        return;
                    }
                    legend.data = legend.data.sort((a, b) => a["valueSum"] > b["valueSum"] ? 1 : -1);
                    if (legendSortSettings.groupByCategoryDirection === MekkoChart.SortDirectionDescending) {
                        legend.data = legend.data.reverse();
                    }
                });

                reducedLegends = reducedLegends.sort((a, b) => a["categorySort"] > b["categorySort"] ? 1 : -1);

                if (legendSortSettings.direction === MekkoChart.SortDirectionDescending) {
                    reducedLegends = reducedLegends.reverse();
                }

                legendData.dataPoints = [];
                reducedLegends.forEach(legend => {
                    if (legend === undefined) {
                        return;
                    }
                    legendData.dataPoints = legendData.dataPoints.concat(legend.data);
                });
            }
            else {
                legendData.dataPoints = legendData.dataPoints.sort((a, b) => a["valueSum"] > b["valueSum"] ? 1 : -1);
                if (legendSortSettings.direction === MekkoChart.SortDirectionDescending) {
                    legendData.dataPoints = legendData.dataPoints.reverse();
                }
            }
        }

        let svgHeight: number = textMeasurementService.estimateSvgTextHeight({
            fontFamily: MekkoChart.LegendBarTextFont,
            fontSize: PixelConverter.toString(+legendProperties["fontSize"] + MekkoChart.LegendBarHeightMargin),
            text: "AZ"
        });

        select(this.rootElement.node()).selectAll("div.legendParent").remove();
        this.categoryLegends = [];
        let legendParents = select(this.rootElement.node()).selectAll("div.legendParent");

        reducedLegends = reducedLegends.filter((l: IGrouppedLegendData) => l !== undefined);
        let legendParentsWithData = legendParents.data(reducedLegends);
        let legendParentsWithChilds = legendParentsWithData.enter().append("div");
        let legendParentsWithChildsAttr = legendParentsWithChilds.classed("legendParent", true)
            .style("position", "absolute")
            .style("top", (data, index) => PixelConverter.toString(svgHeight * index));

        let mekko = this;
        this.categoryLegends = this.categoryLegends || [];
        legendParentsWithChildsAttr.each(function (data, index) {
            let legendSvg = select(this);
            if (legendSvg.select("svg").node() === null) {
                let legend: ILegend = createLegend(
                    <any>this,
                    false,
                    mekko.interactivityService,
                    true);

                mekko.categoryLegends[index] = <ILegend>legend;
            }
        });

        if (reducedLegends.length) {
            this.legendMargins = this.categoryLegends[0].getMargins();
            this.legendMargins.height = this.legendMargins.height - MekkoChart.LegendBarHeightMargin;
            this.legendMargins.height = this.legendMargins.height * reducedLegends.length;
        }
        if (reducedLegends.length > 0) {
            this.categoryLegends.forEach((legend: ILegend, index: number) => {
                (<ILegendGroup>legend).position = +select((<ILegendGroup>legend).element).style("top").replace("px", "");
            });
            this.categoryLegends = this.categoryLegends.sort((a, b) => a["position"] > b["position"] ? 1 : -1).reverse();
            this.categoryLegends.forEach((legend, index) => {
                if (reducedLegends[index] === undefined) {
                    LegendData.update({
                        dataPoints: []
                    }, legendProperties);
                    legend.changeOrientation(LegendPosition.None);
                    legend.drawLegend({
                        dataPoints: []
                    }, this.currentViewport);

                    return;
                }

                let legendData: ILegendData = {
                    title: reducedLegends[index].category,
                    dataPoints: reducedLegends[index].data
                };

                LegendData.update(legendData, legendProperties);
                legend.drawLegend(legendData, this.currentViewport);

                if (index === 0) {
                    if (legendParentsWithChildsAttr.node() === null) {
                        svgHeight = +legendParents.select("svg").attr("height").replace("px", "");
                    } else {
                        svgHeight = +select(legendParentsWithChildsAttr.node()).select("svg").attr("height").replace("px", "");
                    }
                }
            });
        }
        legendParentsWithData.exit().remove();

        if (legendProperties["show"] === false) {
            legendData.dataPoints = [];
            this.categoryLegends.forEach(legend => {
                legend.changeOrientation(LegendPosition.None);
                LegendData.update(legendData, legendProperties);
                legend.drawLegend(legendData, this.currentViewport);
            });
        }

        if (reducedLegends.length > 0) {
            this.legend.changeOrientation(LegendPosition.None);
        }

        this.legend.drawLegend(legendData, this.currentViewport);
    }