in Hands-on lab/lab-files/starter-project/NorthwindMVC/wwwroot/lib/Chart.js/chart.js [10073:10294]
fill: decodeFill(line, i, count),
chart,
axis: meta.controller.options.indexAxis,
scale: meta.vScale,
line,
};
}
meta.$filler = source;
sources.push(source);
}
for (i = 0; i < count; ++i) {
source = sources[i];
if (!source || source.fill === false) {
continue;
}
source.fill = resolveTarget(sources, i, options.propagate);
}
},
beforeDraw(chart, _args, options) {
const draw = options.drawTime === 'beforeDraw';
const metasets = chart.getSortedVisibleDatasetMetas();
const area = chart.chartArea;
for (let i = metasets.length - 1; i >= 0; --i) {
const source = metasets[i].$filler;
if (!source) {
continue;
}
source.line.updateControlPoints(area, source.axis);
if (draw) {
drawfill(chart.ctx, source, area);
}
}
},
beforeDatasetsDraw(chart, _args, options) {
if (options.drawTime !== 'beforeDatasetsDraw') {
return;
}
const metasets = chart.getSortedVisibleDatasetMetas();
for (let i = metasets.length - 1; i >= 0; --i) {
const source = metasets[i].$filler;
if (source) {
drawfill(chart.ctx, source, chart.chartArea);
}
}
},
beforeDatasetDraw(chart, args, options) {
const source = args.meta.$filler;
if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') {
return;
}
drawfill(chart.ctx, source, chart.chartArea);
},
defaults: {
propagate: true,
drawTime: 'beforeDatasetDraw'
}
};
const getBoxSize = (labelOpts, fontSize) => {
let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts;
if (labelOpts.usePointStyle) {
boxHeight = Math.min(boxHeight, fontSize);
boxWidth = Math.min(boxWidth, fontSize);
}
return {
boxWidth,
boxHeight,
itemHeight: Math.max(fontSize, boxHeight)
};
};
const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
class Legend extends Element {
constructor(config) {
super();
this._added = false;
this.legendHitBoxes = [];
this._hoveredItem = null;
this.doughnutMode = false;
this.chart = config.chart;
this.options = config.options;
this.ctx = config.ctx;
this.legendItems = undefined;
this.columnSizes = undefined;
this.lineWidths = undefined;
this.maxHeight = undefined;
this.maxWidth = undefined;
this.top = undefined;
this.bottom = undefined;
this.left = undefined;
this.right = undefined;
this.height = undefined;
this.width = undefined;
this._margins = undefined;
this.position = undefined;
this.weight = undefined;
this.fullSize = undefined;
}
update(maxWidth, maxHeight, margins) {
const me = this;
me.maxWidth = maxWidth;
me.maxHeight = maxHeight;
me._margins = margins;
me.setDimensions();
me.buildLabels();
me.fit();
}
setDimensions() {
const me = this;
if (me.isHorizontal()) {
me.width = me.maxWidth;
me.left = me._margins.left;
me.right = me.width;
} else {
me.height = me.maxHeight;
me.top = me._margins.top;
me.bottom = me.height;
}
}
buildLabels() {
const me = this;
const labelOpts = me.options.labels || {};
let legendItems = callback(labelOpts.generateLabels, [me.chart], me) || [];
if (labelOpts.filter) {
legendItems = legendItems.filter((item) => labelOpts.filter(item, me.chart.data));
}
if (labelOpts.sort) {
legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, me.chart.data));
}
if (me.options.reverse) {
legendItems.reverse();
}
me.legendItems = legendItems;
}
fit() {
const me = this;
const {options, ctx} = me;
if (!options.display) {
me.width = me.height = 0;
return;
}
const labelOpts = options.labels;
const labelFont = toFont(labelOpts.font);
const fontSize = labelFont.size;
const titleHeight = me._computeTitleHeight();
const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);
let width, height;
ctx.font = labelFont.string;
if (me.isHorizontal()) {
width = me.maxWidth;
height = me._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
} else {
height = me.maxHeight;
width = me._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
}
me.width = Math.min(width, options.maxWidth || me.maxWidth);
me.height = Math.min(height, options.maxHeight || me.maxHeight);
}
_fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
const me = this;
const {ctx, maxWidth, options: {labels: {padding}}} = me;
const hitboxes = me.legendHitBoxes = [];
const lineWidths = me.lineWidths = [0];
const lineHeight = itemHeight + padding;
let totalHeight = titleHeight;
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
let row = -1;
let top = -lineHeight;
me.legendItems.forEach((legendItem, i) => {
const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
totalHeight += lineHeight;
lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
top += lineHeight;
row++;
}
hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight};
lineWidths[lineWidths.length - 1] += itemWidth + padding;
});
return totalHeight;
}
_fitCols(titleHeight, fontSize, boxWidth, itemHeight) {
const me = this;
const {ctx, maxHeight, options: {labels: {padding}}} = me;
const hitboxes = me.legendHitBoxes = [];
const columnSizes = me.columnSizes = [];
const heightLimit = maxHeight - titleHeight;
let totalWidth = padding;
let currentColWidth = 0;
let currentColHeight = 0;
let left = 0;
let col = 0;
me.legendItems.forEach((legendItem, i) => {
const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
totalWidth += currentColWidth + padding;
columnSizes.push({width: currentColWidth, height: currentColHeight});
left += currentColWidth + padding;
col++;
currentColWidth = currentColHeight = 0;
}
hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight};
currentColWidth = Math.max(currentColWidth, itemWidth);
currentColHeight += itemHeight + padding;
});
totalWidth += currentColWidth;
columnSizes.push({width: currentColWidth, height: currentColHeight});
return totalWidth;
}
adjustHitBoxes() {
const me = this;
if (!me.options.display) {
return;
}
const titleHeight = me._computeTitleHeight();
const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = me;
const rtlHelper = getRtlAdapter(rtl, me.left, me.width);
if (this.isHorizontal()) {
let row = 0;
let left = _alignStartEnd(align, me.left + padding, me.right - me.lineWidths[row]);
for (const hitbox of hitboxes) {
if (row !== hitbox.row) {