in src/UXClient/Components/Legend/Legend.ts [375:548]
public draw(legendState: string, chartComponentData, labelMouseover, svgSelection, options, labelMouseoutAction = null, stickySeriesAction = null) {
this.chartOptions.setOptions(options);
this.chartComponentData = chartComponentData;
this.legendState = legendState;
this.stickySeriesAction = stickySeriesAction;
this.labelMouseover = labelMouseover;
this.labelMouseout = this.labelMouseoutWrapper(labelMouseoutAction, svgSelection);
this.svgSelection = svgSelection;
var legend = this.legendElement;
var self = this;
super.themify(this.legendElement, this.chartOptions.theme);
legend.style('visibility', this.legendState != 'hidden')
.classed('compact', this.legendState == 'compact')
.classed('hidden', this.legendState == 'hidden');
let seriesNames = Object.keys(this.chartComponentData.displayState);
var seriesLabels: any = legend.selectAll(".tsi-seriesLabel")
.data(seriesNames, d => d);
var seriesLabelsEntered = seriesLabels.enter()
.append("div")
.merge(seriesLabels)
.attr("class", (d, i) => {
return "tsi-seriesLabel " + (this.chartComponentData.displayState[d]["visible"] ? " shown" : "");
})
.style("min-width", () => {
return Math.min(124, this.legendElement.node().clientWidth / seriesNames.length) + 'px';
})
.style("border-color", function (d, i) {
if (d3.select(this).classed("shown"))
return self.chartComponentData.displayState[d].color;
return "lightgray";
});
var self = this;
const heightPerNameLabel: number = 25;
const verticalPaddingPerSeriesLabel: number = 16;
const usableLegendHeight: number = legend.node().clientHeight;
var prospectiveAggregateHeight = Math.ceil(Math.max(201, (usableLegendHeight / seriesLabelsEntered.size())));
var contentHeight = 0;
seriesLabelsEntered.each(function (aggKey: string, i: number) {
let heightPerSplitBy = self.getHeightPerSplitBy(aggKey);
var splitByLabelData = Object.keys(self.chartComponentData.timeArrays[aggKey]);
var noSplitBys: boolean = splitByLabelData.length == 1 && splitByLabelData[0] == "";
var seriesNameLabel = d3.select(this).selectAll(".tsi-seriesNameLabel").data([aggKey]);
d3.select(this).classed('tsi-nsb', noSplitBys);
var enteredSeriesNameLabel = seriesNameLabel.enter().append("button")
.merge(seriesNameLabel as d3.Selection<HTMLButtonElement, string, any, unknown>)
.attr("class", (agg: string, i) => {
return "tsi-seriesNameLabel" + (self.chartComponentData.displayState[agg].visible ? " shown" : "");
})
.attr("aria-label", (agg: string) => {
let showOrHide = self.chartComponentData.displayState[agg].visible ? self.getString('hide group') : self.getString('show group');
return `${showOrHide} ${self.getString('group')} ${Utils.stripNullGuid(self.chartComponentData.displayState[agg].name)}`;
})
.on("click", function (d: string, i: number) {
var newState = !self.chartComponentData.displayState[d].visible;
self.chartComponentData.displayState[d].visible = newState;
//turn off sticky if making invisible
if (newState == false && (self.chartComponentData.stickiedKey != null &&
self.chartComponentData.stickiedKey.aggregateKey == d)) {
self.chartComponentData.stickiedKey = null;
}
self.drawChart();
})
.on("mouseover", (d) => {
labelMouseover(d);
})
.on("mouseout", (d) => {
self.labelMouseout(svgSelection, d);
});
let dataType = self.chartComponentData.displayState[aggKey].dataType;
if (dataType === DataTypes.Categorical || dataType === DataTypes.Events) {
enteredSeriesNameLabel.classed('tsi-nonCompactNonNumeric', true);
let colorKey = enteredSeriesNameLabel.selectAll('.tsi-colorKey').data(['']);
let colorKeyEntered = colorKey.enter()
.append("div")
.attr("class", 'tsi-colorKey')
.merge(colorKey as d3.Selection<HTMLDivElement,string,HTMLButtonElement,string>);
self.createNonNumericColorKey(dataType, colorKeyEntered, aggKey);
colorKey.exit().remove();
}
var seriesNameLabelText = enteredSeriesNameLabel.selectAll("h4").data([aggKey]);
seriesNameLabelText.enter()
.append("h4")
.merge(seriesNameLabelText as d3.Selection<HTMLHeadingElement,string,HTMLButtonElement,string>)
.attr("title", (d: string) => Utils.stripNullGuid(self.chartComponentData.displayState[d].name))
.each(function() {
Utils.appendFormattedElementsFromString(d3.select(this), self.chartComponentData.displayState[aggKey].name);
});
seriesNameLabelText.exit().remove();
seriesNameLabel.exit().remove();
var splitByContainerHeight;
if (splitByLabelData.length > (prospectiveAggregateHeight / heightPerSplitBy)) {
splitByContainerHeight = prospectiveAggregateHeight - heightPerNameLabel;
contentHeight += splitByContainerHeight + heightPerNameLabel;
} else if (splitByLabelData.length > 1 || (splitByLabelData.length === 1 && splitByLabelData[0] !== "")) {
splitByContainerHeight = splitByLabelData.length * heightPerSplitBy + heightPerNameLabel;
contentHeight += splitByContainerHeight + heightPerNameLabel;
} else {
splitByContainerHeight = heightPerSplitBy;
contentHeight += splitByContainerHeight;
}
if (self.chartOptions.legend == "shown") {
d3.select(this).style("height", splitByContainerHeight + "px");
} else {
d3.select(this).style("height", "unset");
}
var splitByContainer = d3.select(this).selectAll(".tsi-splitByContainer").data([aggKey]);
var splitByContainerEntered = splitByContainer.enter().append("div")
.merge(splitByContainer as d3.Selection<HTMLDivElement,string,any,unknown>)
.classed("tsi-splitByContainer", true);
let aggSelection = d3.select(this);
var sBs = self.renderSplitBys(aggKey, aggSelection, dataType, noSplitBys);
splitByContainerEntered.on("scroll", function () {
if (self.chartOptions.legend == "shown") {
if ((<any>this).scrollTop + (<any>this).clientHeight + 40 > (<any>this).scrollHeight) {
const oldShownSplitBys = self.chartComponentData.displayState[aggKey].shownSplitBys;
self.chartComponentData.displayState[aggKey].shownSplitBys = Math.min(oldShownSplitBys + 20, splitByLabelData.length);
if (oldShownSplitBys != self.chartComponentData.displayState[aggKey].shownSplitBys) {
self.renderSplitBys(aggKey, aggSelection, dataType, noSplitBys);
}
}
}
});
d3.select(this).on('scroll', function () {
if (self.chartOptions.legend == "compact") {
if ((<any>this).scrollLeft + (<any>this).clientWidth + 40 > (<any>this).scrollWidth) {
const oldShownSplitBys = self.chartComponentData.displayState[aggKey].shownSplitBys;
self.chartComponentData.displayState[aggKey].shownSplitBys = Math.min(oldShownSplitBys + 20, splitByLabelData.length);
if (oldShownSplitBys != self.chartComponentData.displayState[aggKey].shownSplitBys) {
this.renderSplitBys(dataType);
}
}
}
});
splitByContainer.exit().remove();
});
if (this.chartOptions.legend == 'shown') {
var legendHeight = legend.node().clientHeight;
//minSplitBysForFlexGrow: the minimum number of split bys for flex-grow to be triggered
if (contentHeight < usableLegendHeight) {
this.legendElement.classed("tsi-flexLegend", true);
seriesLabelsEntered.each(function (d) {
let heightPerSplitBy = self.getHeightPerSplitBy(d);
var minSplitByForFlexGrow = (prospectiveAggregateHeight - heightPerNameLabel) / heightPerSplitBy;
var splitBysCount = Object.keys(self.chartComponentData.displayState[String(d3.select(this).data()[0])].splitBys).length;
if (splitBysCount > minSplitByForFlexGrow) {
d3.select(this).style("flex-grow", 1);
}
});
} else {
this.legendElement.classed("tsi-flexLegend", false);
}
}
seriesLabels.exit().remove();
}