UNPKG

ag-charts-community

Version:

Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue

1,104 lines 46.9 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; 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 __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 }); var scene_1 = require("../scene/scene"); var group_1 = require("../scene/group"); var padding_1 = require("../util/padding"); var shape_1 = require("../scene/shape/shape"); var rect_1 = require("../scene/shape/rect"); var legend_1 = require("./legend"); var bbox_1 = require("../scene/bbox"); var array_1 = require("../util/array"); var sizeMonitor_1 = require("../util/sizeMonitor"); var observable_1 = require("../util/observable"); var id_1 = require("../util/id"); var labelPlacement_1 = require("../util/labelPlacement"); var defaultTooltipCss = "\n.ag-chart-tooltip {\n display: table;\n position: absolute;\n user-select: none;\n pointer-events: none;\n white-space: nowrap;\n z-index: 99999;\n font: 12px Verdana, sans-serif;\n color: black;\n background: rgb(244, 244, 244);\n border-radius: 5px;\n box-shadow: 0 0 1px rgba(3, 3, 3, 0.7), 0.5vh 0.5vh 1vh rgba(3, 3, 3, 0.25);\n}\n\n.ag-chart-tooltip-hidden {\n top: -10000px !important;\n}\n\n.ag-chart-tooltip-title {\n font-weight: bold;\n padding: 7px;\n border-top-left-radius: 5px;\n border-top-right-radius: 5px;\n color: white;\n background-color: #888888;\n border-top-left-radius: 5px;\n border-top-right-radius: 5px;\n}\n\n.ag-chart-tooltip-content {\n padding: 7px;\n line-height: 1.7em;\n border-bottom-left-radius: 5px;\n border-bottom-right-radius: 5px;\n overflow: hidden;\n}\n\n.ag-chart-tooltip-content:empty {\n padding: 0;\n height: 7px;\n}\n\n.ag-chart-tooltip-arrow::before {\n content: \"\";\n\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n\n border: 6px solid #989898;\n\n border-left-color: transparent;\n border-right-color: transparent;\n border-top-color: #989898;\n border-bottom-color: transparent;\n\n width: 0;\n height: 0;\n\n margin: 0 auto;\n}\n\n.ag-chart-tooltip-arrow::after {\n content: \"\";\n\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n\n border: 5px solid black;\n\n border-left-color: transparent;\n border-right-color: transparent;\n border-top-color: rgb(244, 244, 244);\n border-bottom-color: transparent;\n\n width: 0;\n height: 0;\n\n margin: 0 auto;\n}\n\n.ag-chart-wrapper {\n box-sizing: border-box;\n overflow: hidden;\n}\n"; function toTooltipHtml(input, defaults) { if (typeof input === 'string') { return input; } defaults = defaults || {}; var _a = input.content, content = _a === void 0 ? defaults.content || '' : _a, _b = input.title, title = _b === void 0 ? defaults.title || undefined : _b, _c = input.color, color = _c === void 0 ? defaults.color || 'white' : _c, _d = input.backgroundColor, backgroundColor = _d === void 0 ? defaults.backgroundColor || '#888' : _d; var titleHtml = title ? "<div class=\"" + Chart.defaultTooltipClass + "-title\"\n style=\"color: " + color + "; background-color: " + backgroundColor + "\">" + title + "</div>" : ''; return titleHtml + "<div class=\"" + Chart.defaultTooltipClass + "-content\">" + content + "</div>"; } exports.toTooltipHtml = toTooltipHtml; var ChartTooltip = /** @class */ (function (_super) { __extends(ChartTooltip, _super); function ChartTooltip(chart, document) { var _this = _super.call(this) || this; _this.enabled = true; _this.class = Chart.defaultTooltipClass; _this.delay = 0; /** * If `true`, the tooltip will be shown for the marker closest to the mouse cursor. * Only has effect on series with markers. */ _this.tracking = true; _this.showTimeout = 0; _this.constrained = false; _this.chart = chart; _this.class = ''; var tooltipRoot = document.body; var element = document.createElement('div'); _this.element = tooltipRoot.appendChild(element); // Detect when the chart becomes invisible and hide the tooltip as well. if (window.IntersectionObserver) { var target_1 = _this.chart.scene.canvas.element; var observer = new IntersectionObserver(function (entries) { var e_1, _a; try { for (var entries_1 = __values(entries), entries_1_1 = entries_1.next(); !entries_1_1.done; entries_1_1 = entries_1.next()) { var entry = entries_1_1.value; if (entry.target === target_1 && entry.intersectionRatio === 0) { _this.toggle(false); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1); } finally { if (e_1) throw e_1.error; } } }, { root: tooltipRoot }); observer.observe(target_1); _this.observer = observer; } return _this; } ChartTooltip.prototype.destroy = function () { var parentNode = this.element.parentNode; if (parentNode) { parentNode.removeChild(this.element); } if (this.observer) { this.observer.unobserve(this.chart.scene.canvas.element); } }; ChartTooltip.prototype.isVisible = function () { var element = this.element; if (element.classList) { // if not IE11 return !element.classList.contains(Chart.defaultTooltipClass + '-hidden'); } // IE11 part. var classes = element.getAttribute('class'); if (classes) { return classes.split(' ').indexOf(Chart.defaultTooltipClass + '-hidden') < 0; } return false; }; ChartTooltip.prototype.updateClass = function (visible, constrained) { var classList = [Chart.defaultTooltipClass, this.class]; if (visible !== true) { classList.push(Chart.defaultTooltipClass + "-hidden"); } if (constrained !== true) { classList.push(Chart.defaultTooltipClass + "-arrow"); } this.element.setAttribute('class', classList.join(' ')); }; /** * Shows tooltip at the given event's coordinates. * If the `html` parameter is missing, moves the existing tooltip to the new position. */ ChartTooltip.prototype.show = function (meta, html, instantly) { var _this = this; if (instantly === void 0) { instantly = false; } var el = this.element; if (html !== undefined) { el.innerHTML = html; } else if (!el.innerHTML) { return; } var left = meta.pageX - el.clientWidth / 2; var top = meta.pageY - el.clientHeight - 8; this.constrained = false; if (this.chart.container) { var tooltipRect = el.getBoundingClientRect(); var minLeft = 0; var maxLeft = window.innerWidth - tooltipRect.width - 1; if (left < minLeft) { left = minLeft; this.updateClass(true, this.constrained = true); } else if (left > maxLeft) { left = maxLeft; this.updateClass(true, this.constrained = true); } if (top < window.pageYOffset) { top = meta.pageY + 20; this.updateClass(true, this.constrained = true); } } el.style.left = Math.round(left) + "px"; el.style.top = Math.round(top) + "px"; if (this.delay > 0 && !instantly) { this.toggle(false); this.showTimeout = window.setTimeout(function () { _this.toggle(true); }, this.delay); return; } this.toggle(true); }; ChartTooltip.prototype.toggle = function (visible) { if (!visible) { window.clearTimeout(this.showTimeout); if (this.chart.lastPick && !this.delay) { this.chart.dehighlightDatum(); this.chart.lastPick = undefined; } } this.updateClass(visible, this.constrained); }; __decorate([ observable_1.reactive() ], ChartTooltip.prototype, "enabled", void 0); __decorate([ observable_1.reactive() ], ChartTooltip.prototype, "class", void 0); __decorate([ observable_1.reactive() ], ChartTooltip.prototype, "delay", void 0); __decorate([ observable_1.reactive() ], ChartTooltip.prototype, "tracking", void 0); return ChartTooltip; }(observable_1.Observable)); exports.ChartTooltip = ChartTooltip; var Chart = /** @class */ (function (_super) { __extends(Chart, _super); function Chart(document) { if (document === void 0) { document = window.document; } var _this = _super.call(this) || this; _this.id = id_1.createId(_this); _this.background = new rect_1.Rect(); _this.legend = new legend_1.Legend(); _this.legendAutoPadding = new padding_1.Padding(); _this.captionAutoPadding = 0; // top padding only _this._container = undefined; _this._data = []; _this._autoSize = false; _this.padding = new padding_1.Padding(20); _this._axes = []; _this._series = []; _this._axesChanged = false; _this._seriesChanged = false; _this.layoutCallbackId = 0; _this._performLayout = function () { _this.layoutCallbackId = 0; _this.background.width = _this.width; _this.background.height = _this.height; _this.performLayout(); if (!_this.layoutPending) { _this.fireEvent({ type: 'layoutDone' }); } }; _this.dataCallbackId = 0; _this.nodeData = new Map(); _this.updateCallbackId = 0; _this.legendBBox = new bbox_1.BBox(0, 0, 0, 0); _this._onMouseDown = _this.onMouseDown.bind(_this); _this._onMouseMove = _this.onMouseMove.bind(_this); _this._onMouseUp = _this.onMouseUp.bind(_this); _this._onMouseOut = _this.onMouseOut.bind(_this); _this._onClick = _this.onClick.bind(_this); _this.pointerInsideLegend = false; var root = new group_1.Group(); var background = _this.background; background.fill = 'white'; root.appendChild(background); var element = _this._element = document.createElement('div'); element.setAttribute('class', 'ag-chart-wrapper'); var scene = new scene_1.Scene(document); _this.scene = scene; scene.root = root; scene.container = element; _this.autoSize = true; _this.padding.addEventListener('layoutChange', _this.scheduleLayout, _this); var legend = _this.legend; legend.addEventListener('layoutChange', _this.scheduleLayout, _this); legend.item.label.addPropertyListener('formatter', _this.updateLegend, _this); legend.addPropertyListener('position', _this.onLegendPositionChange, _this); _this.tooltip = new ChartTooltip(_this, document); _this.tooltip.addPropertyListener('class', function () { return _this.tooltip.toggle(); }); if (Chart.tooltipDocuments.indexOf(document) < 0) { var styleElement = document.createElement('style'); styleElement.innerHTML = defaultTooltipCss; // Make sure the default tooltip style goes before other styles so it can be overridden. document.head.insertBefore(styleElement, document.head.querySelector('style')); Chart.tooltipDocuments.push(document); } _this.setupDomListeners(scene.canvas.element); _this.addPropertyListener('title', _this.onCaptionChange); _this.addPropertyListener('subtitle', _this.onCaptionChange); _this.addEventListener('layoutChange', _this.scheduleLayout); return _this; } Object.defineProperty(Chart.prototype, "container", { get: function () { return this._container; }, set: function (value) { if (this._container !== value) { var parentNode = this.element.parentNode; if (parentNode != null) { parentNode.removeChild(this.element); } if (value) { value.appendChild(this.element); } this._container = value; } }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "data", { get: function () { return this._data; }, set: function (data) { this._data = data; this.series.forEach(function (series) { return series.data = data; }); }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "width", { get: function () { return this.scene.width; }, set: function (value) { this.autoSize = false; if (this.width !== value) { this.scene.resize(value, this.height); this.fireEvent({ type: 'layoutChange' }); } }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "height", { get: function () { return this.scene.height; }, set: function (value) { this.autoSize = false; if (this.height !== value) { this.scene.resize(this.width, value); this.fireEvent({ type: 'layoutChange' }); } }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "autoSize", { get: function () { return this._autoSize; }, set: function (value) { if (this._autoSize !== value) { this._autoSize = value; var style = this.element.style; if (value) { var chart_1 = this; // capture `this` for IE11 sizeMonitor_1.SizeMonitor.observe(this.element, function (size) { if (size.width !== chart_1.width || size.height !== chart_1.height) { chart_1.scene.resize(size.width, size.height); chart_1.fireEvent({ type: 'layoutChange' }); } }); style.display = 'block'; style.width = '100%'; style.height = '100%'; } else { sizeMonitor_1.SizeMonitor.unobserve(this.element); style.display = 'inline-block'; style.width = 'auto'; style.height = 'auto'; } } }, enumerable: true, configurable: true }); Chart.prototype.download = function (fileName) { this.scene.download(fileName); }; Chart.prototype.destroy = function () { this.tooltip.destroy(); sizeMonitor_1.SizeMonitor.unobserve(this.element); this.container = undefined; this.cleanupDomListeners(this.scene.canvas.element); this.scene.container = undefined; }; Chart.prototype.onLegendPositionChange = function () { this.legendAutoPadding.clear(); this.layoutPending = true; }; Chart.prototype.onCaptionChange = function (event) { var value = event.value, oldValue = event.oldValue; if (oldValue) { oldValue.removeEventListener('change', this.scheduleLayout, this); this.scene.root.removeChild(oldValue.node); } if (value) { value.addEventListener('change', this.scheduleLayout, this); this.scene.root.appendChild(value.node); } }; Object.defineProperty(Chart.prototype, "element", { get: function () { return this._element; }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "axes", { get: function () { return this._axes; }, set: function (values) { var _this = this; this._axes.forEach(function (axis) { return _this.detachAxis(axis); }); // make linked axes go after the regular ones (simulates stable sort by `linkedTo` property) this._axes = values.filter(function (a) { return !a.linkedTo; }).concat(values.filter(function (a) { return a.linkedTo; })); this._axes.forEach(function (axis) { return _this.attachAxis(axis); }); this.axesChanged = true; }, enumerable: true, configurable: true }); Chart.prototype.attachAxis = function (axis) { this.scene.root.insertBefore(axis.group, this.seriesRoot); }; Chart.prototype.detachAxis = function (axis) { this.scene.root.removeChild(axis.group); }; Object.defineProperty(Chart.prototype, "series", { get: function () { return this._series; }, set: function (values) { var _this = this; this.removeAllSeries(); values.forEach(function (series) { return _this.addSeries(series); }); }, enumerable: true, configurable: true }); Chart.prototype.scheduleLayout = function () { this.layoutPending = true; }; Chart.prototype.scheduleData = function () { // To prevent the chart from thinking the cursor is over the same node // after a change to data (the nodes are reused on data changes). this.dehighlightDatum(); this.dataPending = true; }; Chart.prototype.addSeries = function (series, before) { var _a = this, allSeries = _a.series, seriesRoot = _a.seriesRoot; var canAdd = allSeries.indexOf(series) < 0; if (canAdd) { var beforeIndex = before ? allSeries.indexOf(before) : -1; if (beforeIndex >= 0) { allSeries.splice(beforeIndex, 0, series); seriesRoot.insertBefore(series.group, before.group); } else { allSeries.push(series); seriesRoot.append(series.group); } this.initSeries(series); this.seriesChanged = true; this.axesChanged = true; return true; } return false; }; Chart.prototype.initSeries = function (series) { series.chart = this; if (!series.data) { series.data = this.data; } series.addEventListener('layoutChange', this.scheduleLayout, this); series.addEventListener('dataChange', this.scheduleData, this); series.addEventListener('legendChange', this.updateLegend, this); series.addEventListener('nodeClick', this.onSeriesNodeClick, this); }; Chart.prototype.freeSeries = function (series) { series.chart = undefined; series.removeEventListener('layoutChange', this.scheduleLayout, this); series.removeEventListener('dataChange', this.scheduleData, this); series.removeEventListener('legendChange', this.updateLegend, this); series.removeEventListener('nodeClick', this.onSeriesNodeClick, this); }; Chart.prototype.addSeriesAfter = function (series, after) { var _a = this, allSeries = _a.series, seriesRoot = _a.seriesRoot; var canAdd = allSeries.indexOf(series) < 0; if (canAdd) { var afterIndex = after ? this.series.indexOf(after) : -1; if (afterIndex >= 0) { if (afterIndex + 1 < allSeries.length) { seriesRoot.insertBefore(series.group, allSeries[afterIndex + 1].group); } else { seriesRoot.append(series.group); } this.initSeries(series); allSeries.splice(afterIndex + 1, 0, series); } else { if (allSeries.length > 0) { seriesRoot.insertBefore(series.group, allSeries[0].group); } else { seriesRoot.append(series.group); } this.initSeries(series); allSeries.unshift(series); } this.seriesChanged = true; this.axesChanged = true; } return false; }; Chart.prototype.removeSeries = function (series) { var index = this.series.indexOf(series); if (index >= 0) { this.series.splice(index, 1); this.freeSeries(series); this.seriesRoot.removeChild(series.group); this.seriesChanged = true; return true; } return false; }; Chart.prototype.removeAllSeries = function () { var _this = this; this.series.forEach(function (series) { _this.freeSeries(series); _this.seriesRoot.removeChild(series.group); }); this._series = []; // using `_series` instead of `series` to prevent infinite recursion this.seriesChanged = true; }; Chart.prototype.assignSeriesToAxes = function () { var _this = this; this.axes.forEach(function (axis) { var axisName = axis.direction + 'Axis'; var boundSeries = []; _this.series.forEach(function (series) { if (series[axisName] === axis) { boundSeries.push(series); } }); axis.boundSeries = boundSeries; }); this.seriesChanged = false; }; Chart.prototype.assignAxesToSeries = function (force) { var _this = this; if (force === void 0) { force = false; } // This method has to run before `assignSeriesToAxes`. var directionToAxesMap = {}; this.axes.forEach(function (axis) { var direction = axis.direction; var directionAxes = directionToAxesMap[direction] || (directionToAxesMap[direction] = []); directionAxes.push(axis); }); this.series.forEach(function (series) { series.directions.forEach(function (direction) { var axisName = direction + 'Axis'; if (!series[axisName] || force) { var directionAxes = directionToAxesMap[direction]; if (directionAxes) { var axis = _this.findMatchingAxis(directionAxes, series.getKeys(direction)); if (axis) { series[axisName] = axis; } } } }); }); this.axesChanged = false; }; Chart.prototype.findMatchingAxis = function (directionAxes, directionKeys) { for (var i = 0; i < directionAxes.length; i++) { var axis = directionAxes[i]; var axisKeys = axis.keys; if (!axisKeys.length) { return axis; } else if (directionKeys) { for (var j = 0; j < directionKeys.length; j++) { if (axisKeys.indexOf(directionKeys[j]) >= 0) { return axis; } } } } }; Object.defineProperty(Chart.prototype, "axesChanged", { get: function () { return this._axesChanged; }, set: function (value) { this._axesChanged = value; }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "seriesChanged", { get: function () { return this._seriesChanged; }, set: function (value) { this._seriesChanged = value; if (value) { this.dataPending = true; } }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "layoutPending", { /** * Only `true` while we are waiting for the layout to start. * This will be `false` if the layout has already started and is ongoing. */ get: function () { return !!this.layoutCallbackId; }, set: function (value) { if (value) { if (!(this.layoutCallbackId || this.dataPending)) { this.layoutCallbackId = requestAnimationFrame(this._performLayout); this.series.forEach(function (s) { return s.nodeDataPending = true; }); } } else if (this.layoutCallbackId) { cancelAnimationFrame(this.layoutCallbackId); this.layoutCallbackId = 0; } }, enumerable: true, configurable: true }); Object.defineProperty(Chart.prototype, "dataPending", { get: function () { return !!this.dataCallbackId; }, set: function (value) { var _this = this; if (this.dataCallbackId) { clearTimeout(this.dataCallbackId); this.dataCallbackId = 0; } if (value) { this.dataCallbackId = window.setTimeout(function () { _this.dataPending = false; _this.processData(); }, 0); } }, enumerable: true, configurable: true }); Chart.prototype.processData = function () { this.layoutPending = false; if (this.axesChanged) { this.assignAxesToSeries(true); this.assignSeriesToAxes(); } if (this.seriesChanged) { this.assignSeriesToAxes(); } this.series.forEach(function (s) { return s.processData(); }); this.updateLegend(); // sets legend data which schedules a layout this.layoutPending = true; }; Chart.prototype.createNodeData = function () { var _this = this; this.nodeData.clear(); this.series.forEach(function (s) { var data = s.visible ? s.createNodeData() : []; _this.nodeData.set(s, data); }); }; Chart.prototype.placeLabels = function () { var series = []; var data = []; this.nodeData.forEach(function (d, s) { if (s.visible && s.label.enabled) { series.push(s); data.push(s.getLabelData()); } }); var seriesRect = this.seriesRect; var labels = seriesRect ? labelPlacement_1.placeLabels(data, { x: 0, y: 0, width: seriesRect.width, height: seriesRect.height }) : []; return new Map(labels.map(function (l, i) { return [series[i], l]; })); }; Chart.prototype.updateLegend = function () { var legendData = []; this.series.filter(function (s) { return s.showInLegend; }).forEach(function (series) { return series.listSeriesItems(legendData); }); var formatter = this.legend.item.label.formatter; if (formatter) { legendData.forEach(function (datum) { return datum.label.text = formatter({ id: datum.id, itemId: datum.itemId, value: datum.label.text }); }); } this.legend.data = legendData; }; Object.defineProperty(Chart.prototype, "updatePending", { get: function () { return !!this.updateCallbackId; }, set: function (value) { var _this = this; if (this.updateCallbackId) { clearTimeout(this.updateCallbackId); this.updateCallbackId = 0; } if (value && !this.layoutPending) { this.updateCallbackId = window.setTimeout(function () { _this.update(); }, 0); } }, enumerable: true, configurable: true }); Chart.prototype.update = function () { this.updatePending = false; this.series.forEach(function (series) { if (series.updatePending) { series.update(); } }); }; Chart.prototype.positionCaptions = function () { var _a = this, title = _a.title, subtitle = _a.subtitle; var titleVisible = false; var subtitleVisible = false; var spacing = 10; var paddingTop = spacing; if (title && title.enabled) { title.node.x = this.width / 2; title.node.y = paddingTop; titleVisible = true; var titleBBox = title.node.computeBBox(); // make sure to set node's x/y, then computeBBox if (titleBBox) { paddingTop = titleBBox.y + titleBBox.height; } if (subtitle && subtitle.enabled) { subtitle.node.x = this.width / 2; subtitle.node.y = paddingTop + spacing; subtitleVisible = true; var subtitleBBox = subtitle.node.computeBBox(); if (subtitleBBox) { paddingTop = subtitleBBox.y + subtitleBBox.height; } } } if (title) { title.node.visible = titleVisible; } if (subtitle) { subtitle.node.visible = subtitleVisible; } this.captionAutoPadding = Math.floor(paddingTop); }; Chart.prototype.positionLegend = function () { if (!this.legend.enabled || !this.legend.data.length) { return; } var _a = this, legend = _a.legend, captionAutoPadding = _a.captionAutoPadding, legendAutoPadding = _a.legendAutoPadding; var width = this.width; var height = this.height - captionAutoPadding; var legendGroup = legend.group; var legendSpacing = legend.spacing; var translationX = 0; var translationY = 0; var legendBBox; switch (legend.position) { case 'bottom': legend.performLayout(width - legendSpacing * 2, 0); legendBBox = legendGroup.computeBBox(); legendGroup.visible = legendBBox.height < Math.floor((height * 0.5)); // Remove legend if it takes up more than 50% of the chart height. if (legendGroup.visible) { translationX = (width - legendBBox.width) / 2 - legendBBox.x; translationY = captionAutoPadding + height - legendBBox.height - legendBBox.y - legendSpacing; legendAutoPadding.bottom = legendBBox.height; } else { legendAutoPadding.bottom = 0; } break; case 'top': legend.performLayout(width - legendSpacing * 2, 0); legendBBox = legendGroup.computeBBox(); legendGroup.visible = legendBBox.height < Math.floor((height * 0.5)); if (legendGroup.visible) { translationX = (width - legendBBox.width) / 2 - legendBBox.x; translationY = captionAutoPadding + legendSpacing - legendBBox.y; legendAutoPadding.top = legendBBox.height; } else { legendAutoPadding.top = 0; } break; case 'left': legend.performLayout(0, height - legendSpacing * 2); legendBBox = legendGroup.computeBBox(); legendGroup.visible = legendBBox.width < Math.floor((width * 0.5)); // Remove legend if it takes up more than 50% of the chart width. if (legendGroup.visible) { translationX = legendSpacing - legendBBox.x; translationY = captionAutoPadding + (height - legendBBox.height) / 2 - legendBBox.y; legendAutoPadding.left = legendBBox.width; } else { legendAutoPadding.left = 0; } break; default: // case 'right': legend.performLayout(0, height - legendSpacing * 2); legendBBox = legendGroup.computeBBox(); legendGroup.visible = legendBBox.width < Math.floor((width * 0.5)); if (legendGroup.visible) { translationX = width - legendBBox.width - legendBBox.x - legendSpacing; translationY = captionAutoPadding + (height - legendBBox.height) / 2 - legendBBox.y; legendAutoPadding.right = legendBBox.width; } else { legendAutoPadding.right = 0; } break; } if (legendGroup.visible) { // Round off for pixel grid alignment to work properly. legendGroup.translationX = Math.floor(translationX + legendGroup.translationX); legendGroup.translationY = Math.floor(translationY + legendGroup.translationY); this.legendBBox = legendGroup.computeBBox(); } }; Chart.prototype.setupDomListeners = function (chartElement) { chartElement.addEventListener('mousedown', this._onMouseDown); chartElement.addEventListener('mousemove', this._onMouseMove); chartElement.addEventListener('mouseup', this._onMouseUp); chartElement.addEventListener('mouseout', this._onMouseOut); chartElement.addEventListener('click', this._onClick); }; Chart.prototype.cleanupDomListeners = function (chartElement) { chartElement.removeEventListener('mousedown', this._onMouseDown); chartElement.removeEventListener('mousemove', this._onMouseMove); chartElement.removeEventListener('mouseup', this._onMouseUp); chartElement.removeEventListener('mouseout', this._onMouseOut); chartElement.removeEventListener('click', this._onClick); }; Chart.prototype.getSeriesRect = function () { return this.seriesRect; }; // x/y are local canvas coordinates in CSS pixels, not actual pixels Chart.prototype.pickSeriesNode = function (x, y) { if (!(this.seriesRect && this.seriesRect.containsPoint(x, y))) { return undefined; } var allSeries = this.series; var node = undefined; for (var i = allSeries.length - 1; i >= 0; i--) { var series = allSeries[i]; if (!series.visible) { continue; } node = series.pickGroup.pickNode(x, y); if (node) { return { series: series, node: node }; } } }; // Provided x/y are in canvas coordinates. Chart.prototype.pickClosestSeriesNodeDatum = function (x, y) { if (!this.seriesRect || !this.seriesRect.containsPoint(x, y)) { return undefined; } var allSeries = this.series; function getDistance(p1, p2) { return Math.sqrt(Math.pow((p1.x - p2.x), 2) + Math.pow((p1.y - p2.y), 2)); } var minDistance = Infinity; var closestDatum; var _loop_1 = function (i) { var series = allSeries[i]; if (!series.visible) { return "continue"; } var hitPoint = series.group.transformPoint(x, y); series.getNodeData().forEach(function (datum) { if (!datum.point) { return; } var distance = getDistance(hitPoint, datum.point); if (distance < minDistance) { minDistance = distance; closestDatum = datum; } }); }; for (var i = allSeries.length - 1; i >= 0; i--) { _loop_1(i); } return closestDatum; }; Chart.prototype.onMouseMove = function (event) { this.handleLegendMouseMove(event); if (this.tooltip.enabled) { if (this.tooltip.delay > 0) { this.tooltip.toggle(false); } this.handleTooltip(event); } }; Chart.prototype.handleTooltip = function (event) { var _a = this, lastPick = _a.lastPick, tooltipTracking = _a.tooltip.tracking; var offsetX = event.offsetX, offsetY = event.offsetY; var pick = this.pickSeriesNode(offsetX, offsetY); var nodeDatum; if (pick && pick.node instanceof shape_1.Shape) { var node = pick.node; nodeDatum = node.datum; if (lastPick && lastPick.datum === nodeDatum) { lastPick.node = node; lastPick.event = event; } // Marker nodes will have the `point` info in their datums. // Highlight if not a marker node or, if not in the tracking mode, highlight markers too. if ((!node.datum.point || !tooltipTracking)) { if (!lastPick // cursor moved from empty space to a node || lastPick.node !== node) { // cursor moved from one node to another this.onSeriesDatumPick(event, node.datum, node, event); } else if (pick.series.tooltip.enabled) { // cursor moved within the same node this.tooltip.show(event); } // A non-marker node (takes precedence over marker nodes) was highlighted. // Or we are not in the tracking mode. // Either way, we are done at this point. return; } } var hideTooltip = false; // In tracking mode a tooltip is shown for the closest rendered datum. // This makes it easier to show tooltips when markers are small and/or plentiful // and also gives the ability to show tooltips even when the series were configured // to not render markers. if (tooltipTracking) { var closestDatum = this.pickClosestSeriesNodeDatum(offsetX, offsetY); if (closestDatum && closestDatum.point) { var _b = closestDatum.point, x = _b.x, y = _b.y; var canvas = this.scene.canvas; var point = closestDatum.series.group.inverseTransformPoint(x, y); var canvasRect = canvas.element.getBoundingClientRect(); this.onSeriesDatumPick({ pageX: Math.round(canvasRect.left + window.pageXOffset + point.x), pageY: Math.round(canvasRect.top + window.pageYOffset + point.y) }, closestDatum, nodeDatum === closestDatum && pick ? pick.node : undefined, event); } else { hideTooltip = true; } } if (lastPick && (hideTooltip || !tooltipTracking)) { // Cursor moved from a non-marker node to empty space. this.dehighlightDatum(); this.tooltip.toggle(false); this.lastPick = undefined; } }; Chart.prototype.onMouseDown = function (event) { }; Chart.prototype.onMouseUp = function (event) { }; Chart.prototype.onMouseOut = function (event) { this.tooltip.toggle(false); }; Chart.prototype.onClick = function (event) { if (this.checkSeriesNodeClick()) { return; } if (this.checkLegendClick(event)) { return; } this.fireEvent({ type: 'click', event: event }); }; Chart.prototype.checkSeriesNodeClick = function () { var lastPick = this.lastPick; if (lastPick && lastPick.event && lastPick.node) { var event_1 = lastPick.event, datum = lastPick.datum; datum.series.fireNodeClickEvent(event_1, datum); return true; } return false; }; Chart.prototype.onSeriesNodeClick = function (event) { this.fireEvent(__assign(__assign({}, event), { type: 'seriesNodeClick' })); }; Chart.prototype.checkLegendClick = function (event) { var datum = this.legend.getDatumForPoint(event.offsetX, event.offsetY); if (datum) { var id_2 = datum.id, itemId = datum.itemId, enabled = datum.enabled; var series = array_1.find(this.series, function (series) { return series.id === id_2; }); if (series) { series.toggleSeriesItem(itemId, !enabled); if (enabled) { this.tooltip.toggle(false); } this.legend.fireEvent({ type: 'click', event: event, itemId: itemId, enabled: !enabled }); return true; } } return false; }; Chart.prototype.handleLegendMouseMove = function (event) { if (!this.legend.enabled) { return; } var offsetX = event.offsetX, offsetY = event.offsetY; var datum = this.legend.getDatumForPoint(offsetX, offsetY); var pointerInsideLegend = this.legendBBox.containsPoint(offsetX, offsetY); if (pointerInsideLegend) { if (!this.pointerInsideLegend) { this.pointerInsideLegend = true; } } else if (this.pointerInsideLegend) { this.pointerInsideLegend = false; // Dehighlight if the pointer was inside the legend and is now leaving it. if (this.highlightedDatum) { this.highlightedDatum = undefined; this.series.forEach(function (s) { return s.updatePending = true; }); } return; } var oldHighlightedDatum = this.highlightedDatum; if (datum) { var id_3 = datum.id, itemId = datum.itemId, enabled = datum.enabled; if (enabled) { var series = array_1.find(this.series, function (series) { return series.id === id_3; }); if (series) { this.highlightedDatum = { series: series, itemId: itemId, datum: undefined }; } } } // Careful to only schedule updates when necessary. if ((this.highlightedDatum && !oldHighlightedDatum) || (this.highlightedDatum && oldHighlightedDatum && (this.highlightedDatum.series !== oldHighlightedDatum.series || this.highlightedDatum.itemId !== oldHighlightedDatum.itemId))) { this.series.forEach(function (s) { return s.updatePending = true; }); } }; Chart.prototype.onSeriesDatumPick = function (meta, datum, node, event) { var lastPick = this.lastPick; if (lastPick) { if (lastPick.datum === datum) { return; } this.dehighlightDatum(); } this.lastPick = { datum: datum, node: node, event: event }; this.highlightDatum(datum); var html = datum.series.tooltip.enabled && datum.series.getTooltipHtml(datum); if (html) { this.tooltip.show(meta, html); } }; Chart.prototype.highlightDatum = function (datum) { this.scene.canvas.element.style.cursor = datum.series.cursor; this.highlightedDatum = datum; this.series.forEach(function (s) { return s.updatePending = true; }); }; Chart.prototype.dehighlightDatum = function () { this.scene.canvas.element.style.cursor = 'default'; this.highlightedDatum = undefined; this.series.forEach(function (s) { return s.updatePending = true; }); }; Chart.defaultTooltipClass = 'ag-chart-tooltip'; Chart.tooltipDocuments = []; __decorate([ observable_1.reactive('layoutChange') ], Chart.prototype, "title", void 0); __decorate([ observable_1.reactive('layoutChange') ], Chart.prototype, "subtitle", void 0); return Chart; }(observable_1.Observable)); exports.Chart = Chart; //# sourceMappingURL=chart.js.map