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();
}