public drawLegendInternal()

in src/legend/svgLegend.ts [272:448]


    public drawLegendInternal(data: LegendData, viewport: powerbi.IViewport, autoWidth: boolean): void {
        this.parentViewport = viewport;
        this.data = data;

        if (this.interactivityService)
            this.interactivityService.applySelectionStateToData(data.dataPoints);

        if (data.dataPoints.length === 0) {
            this.changeOrientation(LegendPosition.None);
        }

        if (this.getOrientation() === LegendPosition.None) {
            data.dataPoints = [];
        }

        // Adding back the workaround for Legend Left/Right position for Map
        let mapControls = this.element.getElementsByClassName("mapControl");
        if (mapControls.length > 0 && !this.isTopOrBottom(this.orientation)) {
            for (let i = 0; i < mapControls.length; ++i) {
                let element = <HTMLElement>mapControls[i];
                element.style.display = "inline-block";
            }
        }

        this.calculateViewport();

        let layout = this.calculateLayout(data, autoWidth);
        let titleLayout = layout.title;
        let titleData = titleLayout ? [titleLayout] : [];
        let hasSelection = this.interactivityService && dataHasSelection(data.dataPoints);

        let group = this.group;

        // transform the wrapping group if position is centered
        if (this.isCentered(this.orientation)) {
            let centerOffset = 0;
            if (this.isTopOrBottom(this.orientation)) {
                centerOffset = Math.max(0, (this.parentViewport.width - this.visibleLegendWidth) / 2);
                group.attr("transform", svgManipulation.translate(centerOffset, 0));
            }
            else {
                centerOffset = Math.max((this.parentViewport.height - this.visibleLegendHeight) / 2);
                group.attr("transform", svgManipulation.translate(0, centerOffset));
            }
        }
        else {
            group.attr("transform", null);
        }

        let legendTitle = group
            .selectAll(SVGLegend.LegendTitle.selectorName);

        let legendTitleData = legendTitle.data(titleData);

        let enteredLegendTitle = legendTitleData
            .enter()
            .append("text")
            .classed(SVGLegend.LegendTitle.className, true);

        legendTitleData
            .merge(enteredLegendTitle)
            .style("fill", data.labelColor)
            .style("font-size", PixelConverter.fromPoint(data.fontSize))
            .style("font-family", data.fontFamily)
            .text((d: TitleLayout) => d.text)
            .attr("x", (d: TitleLayout) => d.x)
            .attr("y", (d: TitleLayout) => d.y)
            .append("title")
            .text(data.title);

        legendTitleData
            .exit()
            .remove();

        let virtualizedDataPoints = data.dataPoints.slice(
            this.legendDataStartIndex,
            this.legendDataStartIndex + layout.numberOfItems);

        let legendItems = group
            .selectAll(SVGLegend.LegendItem.selectorName)
            .data(virtualizedDataPoints, (d: LegendDataPoint) => {
                return (d.identity as ISelectionId).getKey() + (d.layerNumber != null ? d.layerNumber : "");
            });

        let itemsEnter = legendItems.enter()
            .append("g")
            .classed(SVGLegend.LegendItem.className, true);

        itemsEnter
            .append("path")
            .classed(SVGLegend.LegendIcon.className, true);

        itemsEnter
            .append("text")
            .classed(SVGLegend.LegendText.className, true);

        itemsEnter
            .append("title")
            .text((d: LegendDataPoint) => d.tooltip);

        let mergedLegendIcons = legendItems
            .merge(itemsEnter)
            .select(SVGLegend.LegendIcon.selectorName)
            .attr("transform", (dataPoint: LegendDataPoint) => {
                return svgManipulation.translateAndScale(
                    dataPoint.glyphPosition.x,
                    dataPoint.glyphPosition.y,
                    this.getIconScale(dataPoint.markerShape)
                );
            })
            .attr("d", (dataPoint: LegendDataPoint) => {
                return Markers.getPath(dataPoint.markerShape || MarkerShape.circle);
            })
            .attr("stroke-width", (dataPoint: LegendDataPoint) => {
                if (dataPoint.lineStyle) {
                    return 2;
                }

                return Markers.getStrokeWidth(dataPoint.markerShape || MarkerShape.circle);
            })
            .style("fill", (dataPoint: LegendDataPoint) => {
                if (dataPoint.lineStyle) {
                    return null;
                }

                return dataPoint.color;
            })
            .style("stroke", (dataPoint: LegendDataPoint) => dataPoint.color)
            .style("stroke-dasharray", (dataPoint: LegendDataPoint) => {
                if (dataPoint.lineStyle) {
                    return SVGLegend.getStrokeDashArrayForLegend(dataPoint.lineStyle);
                }

                return null;
            })
            .style("stroke-linejoin", "round");

        legendItems
            .merge(itemsEnter)
            .select("title")
            .text((dataPoint: LegendDataPoint) => dataPoint.tooltip);

        const mergedLegendItems = legendItems.merge(itemsEnter);

        mergedLegendItems
            .select(SVGLegend.LegendText.selectorName)
            .attr("x", (dataPoint: LegendDataPoint) => dataPoint.textPosition.x)
            .attr("y", (dataPoint: LegendDataPoint) => dataPoint.textPosition.y)
            .text((d: LegendDataPoint) => d.label)
            .style("fill", data.labelColor)
            .style("font-size", PixelConverter.fromPoint(data.fontSize))
            .style("font-family", data.fontFamily);

        if (this.interactivityService) {
            let behaviorOptions: LegendBehaviorOptions = {
                legendItems: mergedLegendItems,
                legendIcons: mergedLegendIcons,
                clearCatcher: this.clearCatcher,
                dataPoints: data.dataPoints,
                behavior: this.interactiveBehavior,
                interactivityServiceOptions: {
                    isLegend: true
                }
            };

            this.interactivityService.bind(behaviorOptions);
            this.interactiveBehavior.renderSelection(hasSelection);
        }

        legendItems
            .exit()
            .remove();

        this.drawNavigationArrows(layout.navigationArrows);

        this.updateLayout();
    }