ag-grid-enterprise
Version:
AG Grid Enterprise Features
873 lines • 41 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Legend = void 0;
var node_1 = require("../scene/node");
var group_1 = require("../scene/group");
var selection_1 = require("../scene/selection");
var markerLabel_1 = require("./markerLabel");
var bbox_1 = require("../scene/bbox");
var text_1 = require("../scene/shape/text");
var util_1 = require("./marker/util");
var id_1 = require("../util/id");
var hdpiCanvas_1 = require("../canvas/hdpiCanvas");
var validation_1 = require("../util/validation");
var layers_1 = require("./layers");
var chartUpdateType_1 = require("./chartUpdateType");
var gridLayout_1 = require("./gridLayout");
var pagination_1 = require("./pagination/pagination");
var tooltip_1 = require("./tooltip/tooltip");
var logger_1 = require("../util/logger");
var ORIENTATIONS = ['horizontal', 'vertical'];
var OPT_ORIENTATION = validation_1.predicateWithMessage(function (v, ctx) { return validation_1.OPTIONAL(v, ctx, function (v) { return ORIENTATIONS.includes(v); }); }, "expecting an orientation keyword such as 'horizontal' or 'vertical'");
var LegendLabel = /** @class */ (function () {
function LegendLabel() {
this.maxLength = undefined;
this.color = 'black';
this.fontStyle = undefined;
this.fontWeight = undefined;
this.fontSize = 12;
this.fontFamily = 'Verdana, sans-serif';
this.formatter = undefined;
}
__decorate([
validation_1.Validate(validation_1.OPT_NUMBER(0))
], LegendLabel.prototype, "maxLength", void 0);
__decorate([
validation_1.Validate(validation_1.COLOR_STRING)
], LegendLabel.prototype, "color", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_FONT_STYLE)
], LegendLabel.prototype, "fontStyle", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_FONT_WEIGHT)
], LegendLabel.prototype, "fontWeight", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendLabel.prototype, "fontSize", void 0);
__decorate([
validation_1.Validate(validation_1.STRING)
], LegendLabel.prototype, "fontFamily", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_FUNCTION)
], LegendLabel.prototype, "formatter", void 0);
return LegendLabel;
}());
var LegendMarker = /** @class */ (function () {
function LegendMarker() {
this.size = 15;
/**
* If the marker type is set, the legend will always use that marker type for all its items,
* regardless of the type that comes from the `data`.
*/
this._shape = undefined;
/**
* Padding between the marker and the label within each legend item.
*/
this.padding = 8;
this.strokeWidth = 1;
}
Object.defineProperty(LegendMarker.prototype, "shape", {
get: function () {
return this._shape;
},
set: function (value) {
var _a;
this._shape = value;
(_a = this.parent) === null || _a === void 0 ? void 0 : _a.onMarkerShapeChange();
},
enumerable: false,
configurable: true
});
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendMarker.prototype, "size", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendMarker.prototype, "padding", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendMarker.prototype, "strokeWidth", void 0);
return LegendMarker;
}());
var LegendItem = /** @class */ (function () {
function LegendItem() {
this.marker = new LegendMarker();
this.label = new LegendLabel();
/** Used to constrain the width of legend items. */
this.maxWidth = undefined;
/**
* The legend uses grid layout for its items, occupying as few columns as possible when positioned to left or right,
* and as few rows as possible when positioned to top or bottom. This config specifies the amount of horizontal
* padding between legend items.
*/
this.paddingX = 16;
/**
* The legend uses grid layout for its items, occupying as few columns as possible when positioned to left or right,
* and as few rows as possible when positioned to top or bottom. This config specifies the amount of vertical
* padding between legend items.
*/
this.paddingY = 8;
this.toggleSeriesVisible = true;
}
__decorate([
validation_1.Validate(validation_1.OPT_NUMBER(0))
], LegendItem.prototype, "maxWidth", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendItem.prototype, "paddingX", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], LegendItem.prototype, "paddingY", void 0);
__decorate([
validation_1.Validate(validation_1.BOOLEAN)
], LegendItem.prototype, "toggleSeriesVisible", void 0);
return LegendItem;
}());
var LegendListeners = /** @class */ (function () {
function LegendListeners() {
this.legendItemClick = undefined;
this.legendItemDoubleClick = undefined;
}
__decorate([
validation_1.Validate(validation_1.OPT_FUNCTION)
], LegendListeners.prototype, "legendItemClick", void 0);
return LegendListeners;
}());
var Legend = /** @class */ (function () {
function Legend(ctx) {
var _a;
var _this = this;
this.ctx = ctx;
this.id = id_1.createId(this);
this.group = new group_1.Group({ name: 'legend', layer: true, zIndex: layers_1.Layers.LEGEND_ZINDEX });
this.itemSelection = selection_1.Selection.select(this.group, markerLabel_1.MarkerLabel);
this.oldSize = [0, 0];
this.pages = [];
this.maxPageSize = [0, 0];
/** Item index to track on re-pagination, so current page updates appropriately. */
this.paginationTrackingIndex = 0;
this.item = new LegendItem();
this.listeners = new LegendListeners();
this.truncatedItems = new Set();
this._data = [];
this._enabled = true;
this.position = 'bottom';
/** Used to constrain the width of the legend. */
this.maxWidth = undefined;
/** Used to constrain the height of the legend. */
this.maxHeight = undefined;
/** Reverse the display order of legend items if `true`. */
this.reverseOrder = undefined;
this.destroyFns = [];
/**
* Spacing between the legend and the edge of the chart's element.
*/
this.spacing = 20;
this.characterWidths = new Map();
this.size = [0, 0];
this._visible = true;
this.item.marker.parent = this;
this.pagination = new pagination_1.Pagination(function (type) { return ctx.updateService.update(type); }, function (page) { return _this.updatePageNumber(page); }, ctx.interactionManager, ctx.cursorManager);
this.pagination.attachPagination(this.group);
this.item.marker.parent = this;
var interactionListeners = [
ctx.interactionManager.addListener('click', function (e) { return _this.checkLegendClick(e); }),
ctx.interactionManager.addListener('dblclick', function (e) { return _this.checkLegendDoubleClick(e); }),
ctx.interactionManager.addListener('hover', function (e) { return _this.handleLegendMouseMove(e); }),
];
var layoutListeners = [
ctx.layoutService.addListener('start-layout', function (e) { return _this.positionLegend(e.shrinkRect); }),
];
(_a = this.destroyFns).push.apply(_a, __spreadArray(__spreadArray(__spreadArray([], __read(interactionListeners.map(function (s) { return function () { return ctx.interactionManager.removeListener(s); }; }))), __read(layoutListeners.map(function (s) { return function () { return ctx.layoutService.removeListener(s); }; }))), [function () { return _this.detachLegend(); }]));
}
Object.defineProperty(Legend.prototype, "data", {
get: function () {
return this._data;
},
set: function (value) {
this._data = value;
this.updateGroupVisibility();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Legend.prototype, "enabled", {
get: function () {
return this._enabled;
},
set: function (value) {
this._enabled = value;
this.updateGroupVisibility();
},
enumerable: false,
configurable: true
});
Legend.prototype.getOrientation = function () {
if (this.orientation !== undefined) {
return this.orientation;
}
switch (this.position) {
case 'right':
case 'left':
return 'vertical';
case 'bottom':
case 'top':
return 'horizontal';
}
};
Legend.prototype.destroy = function () {
this.destroyFns.forEach(function (f) { return f(); });
};
Legend.prototype.onMarkerShapeChange = function () {
this.itemSelection.clear();
this.group.markDirty(this.group, node_1.RedrawType.MINOR);
};
Legend.prototype.getCharacterWidths = function (font) {
var characterWidths = this.characterWidths;
if (characterWidths.has(font)) {
return characterWidths.get(font);
}
var cw = {
'...': hdpiCanvas_1.HdpiCanvas.getTextSize('...', font).width,
};
characterWidths.set(font, cw);
return cw;
};
Object.defineProperty(Legend.prototype, "visible", {
get: function () {
return this._visible;
},
set: function (value) {
this._visible = value;
this.updateGroupVisibility();
},
enumerable: false,
configurable: true
});
Legend.prototype.updateGroupVisibility = function () {
this.group.visible = this.enabled && this.visible && this.data.length > 0;
};
Legend.prototype.attachLegend = function (node) {
node.append(this.group);
};
Legend.prototype.detachLegend = function () {
var _a;
(_a = this.group.parent) === null || _a === void 0 ? void 0 : _a.removeChild(this.group);
};
Legend.prototype.getItemLabel = function (datum) {
var callbackCache = this.ctx.callbackCache;
var formatter = this.item.label.formatter;
if (formatter) {
return callbackCache.call(formatter, {
itemId: datum.itemId,
value: datum.label.text,
seriesId: datum.seriesId,
});
}
return datum.label.text;
};
/**
* The method is given the desired size of the legend, which only serves as a hint.
* The vertically oriented legend will take as much horizontal space as needed, but will
* respect the height constraints, and the horizontal legend will take as much vertical
* space as needed in an attempt not to exceed the given width.
* After the layout is done, the {@link size} will contain the actual size of the legend.
* If the actual size is not the same as the previous actual size, the legend will fire
* the 'layoutChange' event to communicate that another layout is needed, and the above
* process should be repeated.
* @param width
* @param height
*/
Legend.prototype.performLayout = function (width, height) {
var _this = this;
var _a = this.item, paddingX = _a.paddingX, paddingY = _a.paddingY, label = _a.label, maxWidth = _a.maxWidth, _b = _a.marker, markerSize = _b.size, markerPadding = _b.padding, markerShape = _b.shape, _c = _a.label, _d = _c.maxLength, maxLength = _d === void 0 ? Infinity : _d, fontStyle = _c.fontStyle, fontWeight = _c.fontWeight, fontSize = _c.fontSize, fontFamily = _c.fontFamily;
var data = __spreadArray([], __read(this.data));
if (this.reverseOrder) {
data.reverse();
}
this.itemSelection.update(data);
// Update properties that affect the size of the legend items and measure them.
var bboxes = [];
var font = text_1.getFont(label);
var itemMaxWidthPercentage = 0.8;
var maxItemWidth = maxWidth !== null && maxWidth !== void 0 ? maxWidth : width * itemMaxWidthPercentage;
var paddedMarkerWidth = markerSize + markerPadding + paddingX;
this.itemSelection.each(function (markerLabel, datum) {
var _a;
var Marker = util_1.getMarker(markerShape !== null && markerShape !== void 0 ? markerShape : datum.marker.shape);
if (!(markerLabel.marker && markerLabel.marker instanceof Marker)) {
markerLabel.marker = new Marker();
}
markerLabel.markerSize = markerSize;
markerLabel.spacing = markerPadding;
markerLabel.fontStyle = fontStyle;
markerLabel.fontWeight = fontWeight;
markerLabel.fontSize = fontSize;
markerLabel.fontFamily = fontFamily;
var id = (_a = datum.itemId) !== null && _a !== void 0 ? _a : datum.id;
var labelText = _this.getItemLabel(datum);
var text = (labelText !== null && labelText !== void 0 ? labelText : '<unknown>').replace(/\r?\n/g, ' ');
markerLabel.text = _this.truncate(text, maxLength, maxItemWidth, paddedMarkerWidth, font, id);
bboxes.push(markerLabel.computeBBox());
});
width = Math.max(1, width);
height = Math.max(1, height);
if (!isFinite(width)) {
return false;
}
var size = this.size;
var oldSize = this.oldSize;
size[0] = width;
size[1] = height;
if (size[0] !== oldSize[0] || size[1] !== oldSize[1]) {
oldSize[0] = size[0];
oldSize[1] = size[1];
}
var _e = this.updatePagination(bboxes, width, height), pages = _e.pages, maxPageHeight = _e.maxPageHeight, maxPageWidth = _e.maxPageWidth;
this.pages = pages;
this.maxPageSize = [maxPageWidth - paddingX, maxPageHeight - paddingY];
var pageNumber = this.pagination.currentPage;
var page = this.pages[pageNumber];
if (this.pages.length < 1 || !page) {
this.visible = false;
return;
}
this.visible = true;
// Position legend items
this.updatePositions(pageNumber);
// Update legend item properties that don't affect the layout.
this.update();
};
Legend.prototype.truncate = function (text, maxCharLength, maxItemWidth, paddedMarkerWidth, font, id) {
var e_1, _a;
var ellipsis = "...";
var textChars = text.split('');
var addEllipsis = false;
if (text.length > maxCharLength) {
text = "" + text.substring(0, maxCharLength);
addEllipsis = true;
}
var labelWidth = Math.floor(paddedMarkerWidth + hdpiCanvas_1.HdpiCanvas.getTextSize(text, font).width);
if (labelWidth > maxItemWidth) {
var truncatedText = '';
var characterWidths = this.getCharacterWidths(font);
var cumulativeWidth = paddedMarkerWidth + characterWidths[ellipsis];
try {
for (var textChars_1 = __values(textChars), textChars_1_1 = textChars_1.next(); !textChars_1_1.done; textChars_1_1 = textChars_1.next()) {
var char = textChars_1_1.value;
if (!characterWidths[char]) {
characterWidths[char] = hdpiCanvas_1.HdpiCanvas.getTextSize(char, font).width;
}
cumulativeWidth += characterWidths[char];
if (cumulativeWidth > maxItemWidth) {
break;
}
truncatedText += char;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (textChars_1_1 && !textChars_1_1.done && (_a = textChars_1.return)) _a.call(textChars_1);
}
finally { if (e_1) throw e_1.error; }
}
text = truncatedText;
addEllipsis = true;
}
if (addEllipsis) {
text += ellipsis;
this.truncatedItems.add(id);
}
else {
this.truncatedItems.delete(id);
}
return text;
};
Legend.prototype.updatePagination = function (bboxes, width, height) {
var orientation = this.getOrientation();
var trackingIndex = Math.min(this.paginationTrackingIndex, bboxes.length);
this.pagination.orientation = orientation;
this.pagination.translationX = 0;
this.pagination.translationY = 0;
var _a = this.calculatePagination(bboxes, width, height), pages = _a.pages, maxPageHeight = _a.maxPageHeight, maxPageWidth = _a.maxPageWidth, paginationBBox = _a.paginationBBox, paginationVertical = _a.paginationVertical;
var newCurrentPage = pages.findIndex(function (p) { return p.endIndex >= trackingIndex; });
this.pagination.currentPage = Math.min(Math.max(newCurrentPage, 0), pages.length - 1);
var _b = this.item, itemPaddingX = _b.paddingX, itemPaddingY = _b.paddingY;
var paginationComponentPadding = 8;
var legendItemsWidth = maxPageWidth - itemPaddingX;
var legendItemsHeight = maxPageHeight - itemPaddingY;
var paginationX = 0;
var paginationY = -paginationBBox.y - this.item.marker.size / 2;
if (paginationVertical) {
paginationY += legendItemsHeight + paginationComponentPadding;
}
else {
paginationX += -paginationBBox.x + legendItemsWidth + paginationComponentPadding;
paginationY += (legendItemsHeight - paginationBBox.height) / 2;
}
this.pagination.translationX = paginationX;
this.pagination.translationY = paginationY;
this.pagination.update();
this.pagination.updateMarkers();
return {
maxPageHeight: maxPageHeight,
maxPageWidth: maxPageWidth,
pages: pages,
};
};
Legend.prototype.calculatePagination = function (bboxes, width, height) {
var _a, _b, _c;
var _d = this.item, itemPaddingX = _d.paddingX, itemPaddingY = _d.paddingY;
var orientation = this.getOrientation();
var paginationVertical = ['left', 'right'].includes(this.position);
var paginationBBox = this.pagination.computeBBox();
var lastPassPaginationBBox = new bbox_1.BBox(0, 0, 0, 0);
var pages = [];
var maxPageWidth = 0;
var maxPageHeight = 0;
var count = 0;
var stableOutput = function (lastPassPaginationBBox) {
var width = lastPassPaginationBBox.width, height = lastPassPaginationBBox.height;
return width === paginationBBox.width && height === paginationBBox.height;
};
var forceResult = this.maxWidth !== undefined || this.maxHeight !== undefined;
do {
if (count++ > 10) {
logger_1.Logger.warn('unable to find stable legend layout.');
break;
}
paginationBBox = lastPassPaginationBBox;
var maxWidth = width - (paginationVertical ? 0 : paginationBBox.width);
var maxHeight = height - (paginationVertical ? paginationBBox.height : 0);
var layout = gridLayout_1.gridLayout({
orientation: orientation,
bboxes: bboxes,
maxHeight: maxHeight,
maxWidth: maxWidth,
itemPaddingY: itemPaddingY,
itemPaddingX: itemPaddingX,
forceResult: forceResult,
});
pages = (_a = layout === null || layout === void 0 ? void 0 : layout.pages) !== null && _a !== void 0 ? _a : [];
maxPageWidth = (_b = layout === null || layout === void 0 ? void 0 : layout.maxPageWidth) !== null && _b !== void 0 ? _b : 0;
maxPageHeight = (_c = layout === null || layout === void 0 ? void 0 : layout.maxPageHeight) !== null && _c !== void 0 ? _c : 0;
var totalPages = pages.length;
this.pagination.visible = totalPages > 1;
this.pagination.totalPages = totalPages;
this.pagination.update();
lastPassPaginationBBox = this.pagination.computeBBox();
if (!this.pagination.visible) {
break;
}
} while (!stableOutput(lastPassPaginationBBox));
return { maxPageWidth: maxPageWidth, maxPageHeight: maxPageHeight, pages: pages, paginationBBox: paginationBBox, paginationVertical: paginationVertical };
};
Legend.prototype.updatePositions = function (pageNumber) {
if (pageNumber === void 0) { pageNumber = 0; }
var _a = this, paddingY = _a.item.paddingY, itemSelection = _a.itemSelection, pages = _a.pages;
if (pages.length < 1 || !pages[pageNumber]) {
return;
}
var _b = pages[pageNumber], columns = _b.columns, visibleStart = _b.startIndex, visibleEnd = _b.endIndex;
// Position legend items using the layout computed above.
var x = 0;
var y = 0;
var columnCount = columns.length;
var rowCount = columns[0].indices.length;
var horizontal = this.getOrientation() === 'horizontal';
var itemHeight = columns[0].bboxes[0].height + paddingY;
var rowSumColumnWidths = [];
itemSelection.each(function (markerLabel, _, i) {
var _a, _b;
if (i < visibleStart || i > visibleEnd) {
markerLabel.visible = false;
return;
}
var pageIndex = i - visibleStart;
var columnIndex = 0;
var rowIndex = 0;
if (horizontal) {
columnIndex = pageIndex % columnCount;
rowIndex = Math.floor(pageIndex / columnCount);
}
else {
columnIndex = Math.floor(pageIndex / rowCount);
rowIndex = pageIndex % rowCount;
}
markerLabel.visible = true;
var column = columns[columnIndex];
if (!column) {
return;
}
y = itemHeight * rowIndex;
x = (_a = rowSumColumnWidths[rowIndex]) !== null && _a !== void 0 ? _a : 0;
rowSumColumnWidths[rowIndex] = ((_b = rowSumColumnWidths[rowIndex]) !== null && _b !== void 0 ? _b : 0) + column.columnWidth;
// Round off for pixel grid alignment to work properly.
markerLabel.translationX = Math.floor(x);
markerLabel.translationY = Math.floor(y);
});
};
Legend.prototype.updatePageNumber = function (pageNumber) {
var pages = this.pages;
// Track an item on the page in re-pagination cases (e.g. resize).
var _a = pages[pageNumber], startIndex = _a.startIndex, endIndex = _a.endIndex;
if (startIndex === 0) {
// Stay on first page on pagination update.
this.paginationTrackingIndex = 0;
}
else if (pageNumber === pages.length - 1) {
// Stay on last page on pagination update.
this.paginationTrackingIndex = endIndex;
}
else {
// Track the middle item on the page).
this.paginationTrackingIndex = Math.floor((startIndex + endIndex) / 2);
}
this.pagination.update();
this.pagination.updateMarkers();
this.updatePositions(pageNumber);
this.ctx.updateService.update(chartUpdateType_1.ChartUpdateType.SCENE_RENDER);
};
Legend.prototype.update = function () {
var _a = this.item, strokeWidth = _a.marker.strokeWidth, color = _a.label.color;
this.itemSelection.each(function (markerLabel, datum) {
var marker = datum.marker;
markerLabel.markerFill = marker.fill;
markerLabel.markerStroke = marker.stroke;
markerLabel.markerStrokeWidth = strokeWidth;
markerLabel.markerFillOpacity = marker.fillOpacity;
markerLabel.markerStrokeOpacity = marker.strokeOpacity;
markerLabel.opacity = datum.enabled ? 1 : 0.5;
markerLabel.color = color;
});
};
Legend.prototype.getDatumForPoint = function (x, y) {
var e_2, _a;
var visibleChildBBoxes = [];
var closestLeftTop = { dist: Infinity, datum: undefined };
try {
for (var _b = __values(this.group.children), _c = _b.next(); !_c.done; _c = _b.next()) {
var child = _c.value;
if (!child.visible)
continue;
if (!(child instanceof markerLabel_1.MarkerLabel))
continue;
var childBBox = child.computeBBox();
childBBox.grow(this.item.paddingX / 2, 'horizontal');
childBBox.grow(this.item.paddingY / 2, 'vertical');
if (childBBox.containsPoint(x, y)) {
return child.datum;
}
var distX = x - childBBox.x - this.item.paddingX / 2;
var distY = y - childBBox.y - this.item.paddingY / 2;
var dist = Math.pow(distX, 2) + Math.pow(distY, 2);
var toTheLeftTop = distX >= 0 && distY >= 0;
if (toTheLeftTop && dist < closestLeftTop.dist) {
closestLeftTop.dist = dist;
closestLeftTop.datum = child.datum;
}
visibleChildBBoxes.push(childBBox);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
var pageBBox = bbox_1.BBox.merge(visibleChildBBoxes);
if (!pageBBox.containsPoint(x, y)) {
// We're not in-between legend items.
return undefined;
}
// Fallback to returning closest match to the left/up.
return closestLeftTop.datum;
};
Legend.prototype.computeBBox = function () {
return this.group.computeBBox();
};
Legend.prototype.computePagedBBox = function () {
var actualBBox = this.group.computeBBox();
if (this.pages.length <= 1) {
return actualBBox;
}
var _a = __read(this.maxPageSize, 2), maxPageWidth = _a[0], maxPageHeight = _a[1];
actualBBox.height = Math.max(maxPageHeight, actualBBox.height);
actualBBox.width = Math.max(maxPageWidth, actualBBox.width);
return actualBBox;
};
Legend.prototype.checkLegendClick = function (event) {
var _a = this, legendItemClick = _a.listeners.legendItemClick, _b = _a.ctx, dataService = _b.dataService, highlightManager = _b.highlightManager, toggleSeriesVisible = _a.item.toggleSeriesVisible;
var offsetX = event.offsetX, offsetY = event.offsetY;
var legendBBox = this.computeBBox();
var pointerInsideLegend = this.group.visible && legendBBox.containsPoint(offsetX, offsetY);
var datum = this.getDatumForPoint(offsetX, offsetY);
if (!pointerInsideLegend || !datum) {
return;
}
var id = datum.id, itemId = datum.itemId, enabled = datum.enabled;
var chartSeries = dataService.getSeries();
var series = chartSeries.find(function (s) { return s.id === id; });
if (!series) {
return;
}
event.consume();
var newEnabled = enabled;
if (toggleSeriesVisible) {
newEnabled = !enabled;
this.ctx.chartEventManager.legendItemClick(series, itemId, newEnabled, datum.legendItemName);
}
if (!newEnabled) {
highlightManager.updateHighlight(this.id);
}
else {
highlightManager.updateHighlight(this.id, {
series: series,
itemId: itemId,
datum: undefined,
});
}
this.ctx.updateService.update(chartUpdateType_1.ChartUpdateType.PROCESS_DATA, { forceNodeDataRefresh: true });
legendItemClick === null || legendItemClick === void 0 ? void 0 : legendItemClick({ type: 'click', enabled: newEnabled, itemId: itemId, seriesId: series.id });
};
Legend.prototype.checkLegendDoubleClick = function (event) {
var _a;
var _b = this, legendItemDoubleClick = _b.listeners.legendItemDoubleClick, dataService = _b.ctx.dataService, toggleSeriesVisible = _b.item.toggleSeriesVisible;
var offsetX = event.offsetX, offsetY = event.offsetY;
// Integrated charts do not handle double click behaviour correctly due to multiple instances of the
// chart being created. See https://ag-grid.atlassian.net/browse/RTI-1381
if (this.ctx.mode === 'integrated') {
return;
}
var legendBBox = this.computeBBox();
var pointerInsideLegend = this.group.visible && legendBBox.containsPoint(offsetX, offsetY);
var datum = this.getDatumForPoint(offsetX, offsetY);
if (!pointerInsideLegend || !datum) {
return;
}
var id = datum.id, itemId = datum.itemId, seriesId = datum.seriesId;
var chartSeries = dataService.getSeries();
var series = chartSeries.find(function (s) { return s.id === id; });
if (!series) {
return;
}
event.consume();
if (toggleSeriesVisible) {
var legendData = chartSeries.reduce(function (ls, s) { return __spreadArray(__spreadArray([], __read(ls)), __read(s.getLegendData().filter(function (d) { return d.legendType === 'category'; }))); }, []);
var numVisibleItems_1 = {};
legendData.forEach(function (d) {
var _a;
var _b;
(_a = numVisibleItems_1[_b = d.seriesId]) !== null && _a !== void 0 ? _a : (numVisibleItems_1[_b] = 0);
if (d.enabled)
numVisibleItems_1[d.seriesId]++;
});
var clickedItem = legendData.find(function (d) { return d.itemId === itemId && d.seriesId === seriesId; });
this.ctx.chartEventManager.legendItemDoubleClick(series, itemId, (_a = clickedItem === null || clickedItem === void 0 ? void 0 : clickedItem.enabled) !== null && _a !== void 0 ? _a : false, numVisibleItems_1, clickedItem === null || clickedItem === void 0 ? void 0 : clickedItem.legendItemName);
}
this.ctx.updateService.update(chartUpdateType_1.ChartUpdateType.PROCESS_DATA, { forceNodeDataRefresh: true });
legendItemDoubleClick === null || legendItemDoubleClick === void 0 ? void 0 : legendItemDoubleClick({ type: 'dblclick', enabled: true, itemId: itemId, seriesId: series.id });
};
Legend.prototype.handleLegendMouseMove = function (event) {
var _a;
var _b = this, enabled = _b.enabled, toggleSeriesVisible = _b.item.toggleSeriesVisible, listeners = _b.listeners;
if (!enabled) {
return;
}
var legendBBox = this.computeBBox();
var pageX = event.pageX, pageY = event.pageY, offsetX = event.offsetX, offsetY = event.offsetY;
var pointerInsideLegend = this.group.visible && legendBBox.containsPoint(offsetX, offsetY);
if (!pointerInsideLegend) {
this.ctx.cursorManager.updateCursor(this.id);
this.ctx.highlightManager.updateHighlight(this.id);
this.ctx.tooltipManager.removeTooltip(this.id);
return;
}
// Prevent other handlers from consuming this event if it's generated inside the legend
// boundaries.
event.consume();
var datum = this.getDatumForPoint(offsetX, offsetY);
var pointerOverLegendDatum = pointerInsideLegend && datum !== undefined;
if (!pointerOverLegendDatum) {
this.ctx.cursorManager.updateCursor(this.id);
this.ctx.highlightManager.updateHighlight(this.id);
return;
}
var series = datum ? this.ctx.dataService.getSeries().find(function (series) { return series.id === (datum === null || datum === void 0 ? void 0 : datum.id); }) : undefined;
if (datum && this.truncatedItems.has((_a = datum.itemId) !== null && _a !== void 0 ? _a : datum.id)) {
var labelText = this.getItemLabel(datum);
this.ctx.tooltipManager.updateTooltip(this.id, { pageX: pageX, pageY: pageY, offsetX: offsetX, offsetY: offsetY, event: event, showArrow: false }, tooltip_1.toTooltipHtml({ content: labelText }));
}
else {
this.ctx.tooltipManager.removeTooltip(this.id);
}
if (toggleSeriesVisible || listeners.legendItemClick != null || listeners.legendItemDoubleClick != null) {
this.ctx.cursorManager.updateCursor(this.id, 'pointer');
}
if ((datum === null || datum === void 0 ? void 0 : datum.enabled) && series) {
this.ctx.highlightManager.updateHighlight(this.id, {
series: series,
itemId: datum === null || datum === void 0 ? void 0 : datum.itemId,
datum: undefined,
});
}
else {
this.ctx.highlightManager.updateHighlight(this.id);
}
};
Legend.prototype.positionLegend = function (shrinkRect) {
var _this = this;
var newShrinkRect = shrinkRect.clone();
if (!this.enabled || !this.data.length) {
return { shrinkRect: newShrinkRect };
}
var _a = __read(this.calculateLegendDimensions(shrinkRect), 2), legendWidth = _a[0], legendHeight = _a[1];
this.group.translationX = 0;
this.group.translationY = 0;
this.performLayout(legendWidth, legendHeight);
var legendBBox = this.computePagedBBox();
var calculateTranslationPerpendicularDimension = function () {
switch (_this.position) {
case 'top':
return 0;
case 'bottom':
return shrinkRect.height - legendBBox.height;
case 'left':
return 0;
case 'right':
default:
return shrinkRect.width - legendBBox.width;
}
};
if (this.visible) {
var translationX = void 0;
var translationY = void 0;
switch (this.position) {
case 'top':
case 'bottom':
translationX = (shrinkRect.width - legendBBox.width) / 2;
translationY = calculateTranslationPerpendicularDimension();
newShrinkRect.shrink(legendBBox.height, this.position);
break;
case 'left':
case 'right':
default:
translationX = calculateTranslationPerpendicularDimension();
translationY = (shrinkRect.height - legendBBox.height) / 2;
newShrinkRect.shrink(legendBBox.width, this.position);
}
// Round off for pixel grid alignment to work properly.
this.group.translationX = Math.floor(-legendBBox.x + shrinkRect.x + translationX);
this.group.translationY = Math.floor(-legendBBox.y + shrinkRect.y + translationY);
}
if (this.visible && this.enabled && this.data.length) {
var legendPadding = this.spacing;
newShrinkRect.shrink(legendPadding, this.position);
var legendPositionedBBox = legendBBox.clone();
legendPositionedBBox.x += this.group.translationX;
legendPositionedBBox.y += this.group.translationY;
this.ctx.tooltipManager.updateExclusiveRect(this.id, legendPositionedBBox);
}
else {
this.ctx.tooltipManager.updateExclusiveRect(this.id);
}
return { shrinkRect: newShrinkRect };
};
Legend.prototype.calculateLegendDimensions = function (shrinkRect) {
var width = shrinkRect.width, height = shrinkRect.height;
var aspectRatio = width / height;
var maxCoefficient = 0.5;
var minHeightCoefficient = 0.2;
var minWidthCoefficient = 0.25;
var legendWidth = 0;
var legendHeight = 0;
switch (this.position) {
case 'top':
case 'bottom':
// A horizontal legend should take maximum between 20 to 50 percent of the chart height if height is larger than width
// and maximum 20 percent of the chart height if height is smaller than width.
var heightCoefficient = aspectRatio < 1
? Math.min(maxCoefficient, minHeightCoefficient * (1 / aspectRatio))
: minHeightCoefficient;
legendWidth = this.maxWidth ? Math.min(this.maxWidth, width) : width;
legendHeight = this.maxHeight
? Math.min(this.maxHeight, height)
: Math.round(height * heightCoefficient);
break;
case 'left':
case 'right':
default:
// A vertical legend should take maximum between 25 to 50 percent of the chart width if width is larger than height
// and maximum 25 percent of the chart width if width is smaller than height.
var widthCoefficient = aspectRatio > 1 ? Math.min(maxCoefficient, minWidthCoefficient * aspectRatio) : minWidthCoefficient;
legendWidth = this.maxWidth ? Math.min(this.maxWidth, width) : Math.round(width * widthCoefficient);
legendHeight = this.maxHeight ? Math.min(this.maxHeight, height) : height;
}
return [legendWidth, legendHeight];
};
Legend.className = 'Legend';
__decorate([
validation_1.Validate(validation_1.BOOLEAN)
], Legend.prototype, "_enabled", void 0);
__decorate([
validation_1.Validate(validation_1.POSITION)
], Legend.prototype, "position", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_NUMBER(0))
], Legend.prototype, "maxWidth", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_NUMBER(0))
], Legend.prototype, "maxHeight", void 0);
__decorate([
validation_1.Validate(validation_1.OPT_BOOLEAN)
], Legend.prototype, "reverseOrder", void 0);
__decorate([
validation_1.Validate(OPT_ORIENTATION)
], Legend.prototype, "orientation", void 0);
__decorate([
validation_1.Validate(validation_1.NUMBER(0))
], Legend.prototype, "spacing", void 0);
return Legend;
}());
exports.Legend = Legend;
//# sourceMappingURL=legend.js.map