'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** *+------------------------------------------------------------------------+ *| Licensed Materials - Property of IBM *| IBM Cognos Products: Dashboard *| (C) Copyright IBM Corp. 2018, 2019 *| *| US Government Users Restricted Rights - Use, duplication or disclosure *| restricted by GSA ADP Schedule Contract with IBM Corp. *+------------------------------------------------------------------------+ */ define(['underscore', './AbstractTupleLocator'], function (_, AbstractTupleLocator) { var BinarySearchTupleLocator = function (_AbstractTupleLocator) { _inherits(BinarySearchTupleLocator, _AbstractTupleLocator); /** * A tuple locator which deals with tuples which the VIDA getItemsInPolygon * API returns. */ function BinarySearchTupleLocator(_ref) { var viprWidget = _ref.viprWidget; _classCallCheck(this, BinarySearchTupleLocator); var _this = _possibleConstructorReturn(this, _AbstractTupleLocator.call(this)); _this.viprWidget = viprWidget; return _this; } /* For JSDocs, see parent class */ BinarySearchTupleLocator.prototype.findTupleVisualInfo = function findTupleVisualInfo(filter, _ref2) { var _this2 = this; var includeInfo = _ref2.includeInfo, includePoints = _ref2.includePoints; var viprItems = _.flatten( //Get all items in an area this._getVisAreas().map(function (_ref3) { var x = _ref3.x, y = _ref3.y, w = _ref3.w, h = _ref3.h; return _this2._getVIDAItemsInRectangle({ x0: x, y0: y, x1: x + w, y1: y + h }) //Filter items to ones which satisfy specified filter .filter(function (item) { return _this2._itemSatisfiesFilter({ item: item, filter: filter }); }); })); return viprItems.map(function (item) { var result = {}; if (includeInfo) { result.info = _this2._getValueInfoFromItem(item); } if (includePoints) { result.point = _this2._getPoint(item); } return result; }); }; /* * Finds the areas (e.g. "visualization", "legend") and their extents which * VIPR partitions the entire visualization into. * * Motivation: It is important to know their extents, as if a * getItemsInPolygon query draws a polygon with points straddling multiple * areas, VIPR will return no items. * * @return {object[]} area information will include 'area' (name), 'x', 'y', * 'w' and 'h' */ BinarySearchTupleLocator.prototype._getVisAreas = function _getVisAreas() { var _this3 = this; var bounds = this.viprWidget.domNode.getBoundingClientRect(); var areaToExtents = {}; //Assume all areas we care about begin in one of the four corners of the //visualization. var findAreasFromCorner = function findAreasFromCorner(bx, by) { var w0 = bx ? bounds.width - 1 : 0, h0 = by ? bounds.height - 1 : 0; var getArea = function getArea(w, h) { return _this3.viprWidget.getVisCoordinate(bounds.x + w, bounds.y + h).area; }; //What area is in this corner? var area = getArea(w0, h0); //'none' is not a useful area; and if we've already found the extents of //this area, no need to scan again if (area === 'none' || areaToExtents[area]) { return; } var dx = bx ? -1 : 1, dy = by ? -1 : 1; var wt = void 0, ht = void 0; //Scan x axis to see how wide this area is for (wt = w0; 0 <= wt && wt < bounds.width; wt += dx) { if (getArea(wt, h0) !== area) { break; } } wt -= dx; //Scan y axis to see how tall this area is for (ht = h0; 0 <= ht && ht < bounds.height; ht += dy) { if (getArea(w0, ht) !== area) { break; } } ht -= dy; //Assume areas are rectangular areaToExtents[area] = { x: Math.min(w0, wt), y: Math.min(h0, ht), w: Math.abs(w0 - wt), h: Math.abs(h0 - ht) }; }; //Search for areas in all four corners findAreasFromCorner(false, false); //top-left findAreasFromCorner(true, false); //top-right findAreasFromCorner(false, true); //bottom-left findAreasFromCorner(true, true); //bottom-right //In general, the only area we use is 'visualization'. If it's not found //we won't be able to proceed if (!areaToExtents.visualization) { throw new Error('Cannot find "visualization" area of widget'); } return Object.keys(areaToExtents).map(function (area) { return { extents: areaToExtents[area], area: area }; }).map(function (_ref4) { var extents = _ref4.extents, area = _ref4.area; return _extends({}, extents, { area: area }); }); }; /* * Simplifies the VIPR getItemsInPolygon API to a rectangle - and takes care * of the mapping to VIPR coordinate space via getVisCoordinate. * @param {object} coords * @param {number} coords.x0 - top-left corner x coordinate * @param {number} coords.y0 - top-left corner y coordinate * @param {number} coords.x1 - bottom-right corner x coordinate * @param {number} coords.y1 - bottom-right corner y coordinate */ BinarySearchTupleLocator.prototype._getVIDAItemsInRectangle = function _getVIDAItemsInRectangle(_ref5) { var _this4 = this; var x0 = _ref5.x0, y0 = _ref5.y0, x1 = _ref5.x1, y1 = _ref5.y1; var origin = this.viprWidget.domNode.getBoundingClientRect(); //Make a 'rectangle' polygon: // - top-left corner // - top-right corner // - bottom-right corner // - bottom-left corner var points = [[x0, y0], [x1, y0], [x1, y1], [x0, y1]].map(function (_ref6) { var x = _ref6[0], y = _ref6[1]; return [x + origin.x, y + origin.y]; }).map(function (_ref7) { var x = _ref7[0], y = _ref7[1]; return _this4.viprWidget.getVisCoordinate(x, y); }); return this.viprWidget.getItemsInPolygon(points); }; /* * Finds a single clickable point which will click an item * @param {object} item */ BinarySearchTupleLocator.prototype._getPoint = function _getPoint(item) { var _this5 = this; //Find which area this item is contained in and extract its extents var extent = this._getVisAreas().find(function (_ref8) { var x = _ref8.x, y = _ref8.y, w = _ref8.w, h = _ref8.h; return _this5._isItemContainedIn(item, { x0: x, y0: y, x1: x + w, y1: y + h }); }); if (!extent) { throw new Error('Item not found at any position within visualization'); } var x0 = extent.x, y0 = extent.y, x1 = x0 + extent.w, y1 = y0 + extent.h; //Find the boundary between where this item does and does not exist in the x axis var x = this._binarySearch(x1, x0, function (x) { return _this5._isItemContainedIn(item, { x0: x0, y0: y0, x1: x, y1: y1 }); }); //Find the boundary between where this item does and does not exist along the strip of x axis found above var y = this._binarySearch(y1, y0, function (y) { return _this5._isItemContainedIn(item, { x0: x - 1, y0: y0, x1: x, y1: y }); }); return { selectedNode: this.viprWidget.domNode, xOffset: x, yOffset: y }; }; /* * Perform a binary search for the boundary between a condition succeeding and failing * @param {number} maxPass - the maximum value where the condition is known to pass * @param {number} maxFail - the maximum value where the condition is known to fail * @param {function} test - condition */ BinarySearchTupleLocator.prototype._binarySearch = function _binarySearch(maxPass, maxFail, test) { while (Math.abs(maxPass - maxFail) > 1) { var candidate = Math.round((maxPass + maxFail) / 2); if (test(candidate)) { maxPass = candidate; } else { maxFail = candidate; } } return maxPass; }; /* * Determines whether the item exists inside a particular rectangle in the visualization * @param {object} item * @param {object} extents - rectangle */ BinarySearchTupleLocator.prototype._isItemContainedIn = function _isItemContainedIn(item, _ref9) { var x0 = _ref9.x0, y0 = _ref9.y0, x1 = _ref9.x1, y1 = _ref9.y1; return this._getVIDAItemsInRectangle({ x0: x0, y0: y0, x1: x1, y1: y1 }).some(function (foundItem) { return item.key === foundItem.key; }); }; return BinarySearchTupleLocator; }(AbstractTupleLocator); return BinarySearchTupleLocator; }); //# sourceMappingURL=BinarySearchTupleLocator.js.map