VisEventHandler.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924
  1. 'use strict';
  2. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. /**
  5. *+------------------------------------------------------------------------+
  6. *| Licensed Materials - Property of IBM
  7. *| IBM Cognos Products: Dashboard
  8. *| (C) Copyright IBM Corp. 2017, 2020
  9. *|
  10. *| US Government Users Restricted Rights - Use, duplication or disclosure
  11. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  12. *+------------------------------------------------------------------------+
  13. */
  14. define(['jquery', 'underscore', '../../lib/@waca/dashboard-common/dist/utils/EventChainLocal', '../../apiHelpers/SlotAPIHelper', './VisSelectionInfo', './VisTooltipInfo', '../../util/DashboardFormatter', '../interactions/lassoSelect/LassoController', '../../features/content/visualizationGesture/api/VisualizationGestureAPI', '../../lib/@waca/dashboard-common/dist/core/APIFactory'], function ($, _, EventChainLocal, SlotAPIHelper, VisSelectionInfo, VisTooltipInfo, Formatter, LassoController, VisualizationGestureAPI, APIFactory) {
  15. 'use strict';
  16. /////////////////////
  17. // VisEventHandler
  18. //
  19. // options : {
  20. // target: {
  21. // getTargetElement(): (JQuery element of the target view which the events will be handled.),
  22. // getEventTargets(event): (Retrieve a list of event target objects. See EventTarget.),
  23. // getTargetsByCords(cords, summarize) (Retrieve an array of targets base on the specified co-ordintates),
  24. // decorateTarget(targets, name): (Decorate the given target.),
  25. // getDecoration(target, name): (Obtain the decoration value of the given target),
  26. // completeDecorations: (End of decorations.)
  27. // applyCustomDataSelection(target): Apply custom data selection to target.
  28. // getCustomDataSelections(items): Get the list of custom selections
  29. // canZoom(): Determines whether the target supports zoom.
  30. // zoom(event): Apply zoom to the target with the given event.
  31. // zoomStart(event): Begin the zooming session
  32. // zoomEnd(event): End the zooming session
  33. // pan(event): Apply pan movements to the target
  34. // panStart(event): Begin the panning session
  35. // panEnd(event): End the panning session
  36. // },
  37. // visAPI: (Instance of VisAPI)
  38. // }
  39. //
  40. // EventTarget: {
  41. // key: (A unique key representing a target.)
  42. // type: (Target type. datapoint | item | itemclass)
  43. // source: (original source object of the target.)
  44. // values[]: (values of the target in mapped order.)
  45. // datasetId: (dataset id of origainl source object)
  46. // }
  47. //
  48. var VisEventHandler = function () {
  49. function VisEventHandler(options) {
  50. _classCallCheck(this, VisEventHandler);
  51. this._init(options);
  52. }
  53. VisEventHandler.prototype._init = function _init(options) {
  54. this._oTimerOut = null;
  55. this._lastSelected = null;
  56. this._lastHighlighted = null;
  57. this._lastImpliedSelection = [];
  58. this.dashboard = options.dashboard;
  59. this.logger = options.logger;
  60. this._target = options.target;
  61. this._targetElement = this._target.getTargetElement();
  62. this._ownerWidget = options.ownerWidget;
  63. this.content = this._ownerWidget.content;
  64. this.state = this.content.getFeature('state');
  65. this.visualization = this.content.getFeature('Visualization');
  66. this._visAPI = options.visAPI;
  67. this._visController = this.content.getFeature('InteractivityController.deprecated');
  68. this._selector = this.content.getFeature('DataPointSelections');
  69. this._transaction = options.transaction;
  70. this._visActionHelper = this._visController ? this._visController.getActionHelper() : null;
  71. // use jQuery touchstart, touchend and touchmove to handle panning to avoid issues with hammerjs drag/start/end
  72. var panAndZoomEvents = [{
  73. 'key': 'mousedown',
  74. 'callback': this.onMouseDown.bind(this)
  75. }, {
  76. 'key': 'mouseup',
  77. 'callback': this.onMouseUp.bind(this)
  78. }, {
  79. 'key': 'mousewheel wheel',
  80. 'callback': this.onMouseWheel.bind(this)
  81. }, {
  82. 'key': 'touchstart',
  83. 'callback': this.onClickTapPanStart.bind(this)
  84. }, {
  85. 'key': 'touchend',
  86. 'callback': this.onPanEnd.bind(this)
  87. }, {
  88. 'key': 'touchmove',
  89. 'callback': this.onPanMove.bind(this)
  90. }, {
  91. 'key': 'transformstart',
  92. 'callback': this.onPinchStart.bind(this),
  93. 'hammer': true
  94. }, {
  95. 'key': 'transform',
  96. 'callback': this.onPinch.bind(this),
  97. 'hammer': true
  98. }, {
  99. 'key': 'transformend',
  100. 'callback': this.onPinchEnd.bind(this),
  101. 'hammer': true
  102. }];
  103. var hoverEvents = [{
  104. 'key': 'mousemove touchmove',
  105. 'callback': this.onHover.bind(this)
  106. }, {
  107. 'key': 'mouseleave touchend',
  108. 'callback': this.onMouseLeave.bind(this)
  109. }];
  110. var clickEvents = [{
  111. 'key': 'contextmenu',
  112. 'callback': this.onClick.bind(this)
  113. }, {
  114. 'key': 'clicktap',
  115. 'callback': this.onClickTapPanStart.bind(this),
  116. 'data': { allowPropagationDefaultAction: true }
  117. }, {
  118. 'key': 'hold',
  119. 'callback': this.onHold.bind(this),
  120. 'hammer': true
  121. }];
  122. var keyEvents = [{
  123. 'key': 'keydown',
  124. 'callback': this.onKeyDown.bind(this)
  125. }];
  126. this._visControlEvents = [];
  127. var interactivitySettings = this._visAPI.getInteractivitySettings();
  128. if (!interactivitySettings.isClickDisabled) {
  129. this._visControlEvents.push.apply(this._visControlEvents, clickEvents);
  130. this._visControlEvents.push.apply(this._visControlEvents, keyEvents);
  131. }
  132. if (!interactivitySettings.isPanAndZoomDisabled) {
  133. this._visControlEvents.push.apply(this._visControlEvents, panAndZoomEvents);
  134. }
  135. if (!interactivitySettings.isHoverDisabled) {
  136. this._visControlEvents.push.apply(this._visControlEvents, hoverEvents);
  137. }
  138. this.serializeInteractivity = !!interactivitySettings.serialize;
  139. this._edgeSelection = !!options.edgeSelection;
  140. this._registerEvents();
  141. this.lassoCtrl = new LassoController({
  142. targetElement: this._targetElement,
  143. cordinateResolver: this._resolveCoordinates,
  144. isDragging: this._isDragging.bind(this),
  145. dashboard: this.dashboard
  146. });
  147. // TODO: Remove this check after contentFeatureLoader is available
  148. // in live widgets in conversationalPanel
  149. if (this._ownerWidget.contentFeatureLoader) {
  150. // Add VisualizationGesture feature
  151. this._ownerWidget.contentFeatureLoader.registerFeature(this._ownerWidget.id, 'VisualizationGesture', this);
  152. }
  153. };
  154. VisEventHandler.prototype.getAPI = function getAPI() {
  155. if (!this.api) {
  156. this.api = APIFactory.createAPI(this, [VisualizationGestureAPI]);
  157. }
  158. return this.api;
  159. };
  160. /**
  161. * Handle the app configuration for serialized interactions.
  162. * Applications may configure the interactivity of the livewidget
  163. * from the perspective file with the following configuration
  164. *
  165. * config: {
  166. * interactions: {
  167. * serialize: true
  168. * }
  169. * }
  170. */
  171. VisEventHandler.prototype.isReadyToInteract = function isReadyToInteract() {
  172. if (this.serializeInteractivity) {
  173. return this.state.getStatus() === this.state.STATUS.RENDERED;
  174. }
  175. // default: interactivity is always ready
  176. return true;
  177. };
  178. /**
  179. * Restore the interactive state (ie. zoom, pan) to the visualization
  180. */
  181. VisEventHandler.prototype.restoreState = function restoreState() {
  182. if (this._target.canRestore()) {
  183. this._target.restore(this._visAPI.getPropertyValue('interactivityState'));
  184. }
  185. };
  186. /**
  187. * Remove the handler from target
  188. */
  189. VisEventHandler.prototype.remove = function remove() {
  190. var _this = this;
  191. $(document).off('mouseup', this._onMouseUpHandler);
  192. $(document).off('touchend', this._onTouchEndHandler);
  193. //Release events from the RAVE control.
  194. if (this._targetElement) {
  195. this._visControlEvents.forEach(function (eventInfo) {
  196. if (eventInfo.hammer) {
  197. _this._targetElement.hammer().off(eventInfo.key, eventInfo.callback);
  198. } else {
  199. _this._targetElement.off(eventInfo.key, null, eventInfo.callback);
  200. }
  201. });
  202. }
  203. //prevent from memory leak
  204. if (this._target) {
  205. this._target.remove();
  206. this._target = null;
  207. }
  208. this._lastHoverEvent = null;
  209. this._tooltipItems = null;
  210. this._lastHighlighted = null;
  211. this.content = null;
  212. if (this.lassoCtrl) {
  213. this._endLassoSelection();
  214. this.lassoCtrl.remove();
  215. this.lassoCtrl = null;
  216. }
  217. };
  218. /**
  219. * Register the events to the target
  220. */
  221. VisEventHandler.prototype._registerEvents = function _registerEvents() {
  222. var _this2 = this;
  223. this._onMouseUpHandler = this._onDocumentMouseUp.bind(this);
  224. $(document).on('mouseup', this._onMouseUpHandler);
  225. this._onTouchEndHandler = this._onDocumentTouchEnd.bind(this);
  226. $(document).on('touchend', this._onTouchEndHandler);
  227. if (this._targetElement) {
  228. this._visControlEvents.forEach(function (eventInfo) {
  229. if (eventInfo.hammer) {
  230. _this2._targetElement.hammer(eventInfo.hammerOption).on(eventInfo.key, eventInfo.callback);
  231. } else {
  232. if (eventInfo.data) {
  233. _this2._targetElement.on(eventInfo.key, null, eventInfo.data, eventInfo.callback);
  234. } else {
  235. _this2._targetElement.on(eventInfo.key, null, eventInfo.callback);
  236. }
  237. }
  238. });
  239. }
  240. };
  241. /**
  242. * Handle mouse hover on Desktop and touchmove event on Mobile
  243. * If hover and pan are both enabled, on Mobile touchmove is binded both two event handlers
  244. * Both handlers will run and will execute in the order in which they were bound.
  245. * For example, in Explore crosshair and pan are both enabled.
  246. * For charts whose pan direction is left/right and crosshair is top/bottom, touching move along the diagonal of the chart results
  247. * a) pan the chart at left/right direction
  248. * b) move the crosshair at top/bottom direction
  249. * and vice versa.
  250. *
  251. * @param event Event Object
  252. */
  253. VisEventHandler.prototype.onHover = function onHover(event) {
  254. if (!event.clientX) {
  255. this._resolveCoordinates(event);
  256. }
  257. // pan and zoom takes priority
  258. if (this._isDragging(event) && !this.lassoCtrl.isLassoMode()) {
  259. if (this._target.canZoom() && this._target.pan) {
  260. this._target.pan(event);
  261. }
  262. // This flag is used to detect if we moved the mouse while the mouse is down so that we can ignore the vis selection
  263. // Without this, if we pan while we are on top of an element, then the pan is done after the mouse is up, the click is invoked and we select the element
  264. this._skipSelection = true;
  265. } else {
  266. this._skipSelection = !this.isReadyToInteract();
  267. this._skipHoverover = this._skipSelection;
  268. }
  269. var items = this._target && this._target.getEventTargets ? this._target.getEventTargets(event) : [];
  270. if (this._stopHoverover) {
  271. // only apply pointer cursor, no tooltips
  272. if (this._targetElement) {
  273. if (items && items.length > 0) {
  274. this._targetElement.addClass('cursor-pointer');
  275. } else {
  276. this._targetElement.removeClass('cursor-pointer');
  277. }
  278. }
  279. return;
  280. }
  281. // If the mouse is down while it's moving we should never show the tooltip or toolbar actions
  282. if (this._mouseDown) {
  283. this._clearHoverTimer();
  284. this._visActionHelper.hideToolbarActions();
  285. }
  286. this._handleImpliedSelections(items, event.ctrlKey || event.metaKey, false);
  287. this._handleHighlights(items);
  288. this._handleTooltips(event, items);
  289. this._triggerWidgetEvent('visevent:onmove', event, this._target, items, { mouseDown: this._mouseDown, onHold: this._onHold });
  290. };
  291. /**
  292. * Handle mouseleave on Desktop and touchmove event on Mobile
  293. *
  294. * @param event Event object
  295. */
  296. VisEventHandler.prototype.onMouseLeave = function onMouseLeave(event) {
  297. if (!event.clientX) {
  298. this._resolveCoordinates(event);
  299. }
  300. var items = this._target && this._target.getEventTargets ? this._target.getEventTargets(event) : [];
  301. this._lastHoverEvent = event;
  302. this._tooltipItems = items;
  303. if (this._tooltipItems && this._tooltipItems.length > 0) {
  304. this._clearHoverTimer();
  305. } else if (this._lastTooltip) {
  306. this._lastTooltip = null;
  307. this._clearHoverTimer();
  308. this._oTimerOut = setTimeout(this._handleMouseleaveTimeout.bind(this), 500);
  309. }
  310. };
  311. VisEventHandler.prototype._handleMouseleaveTimeout = function _handleMouseleaveTimeout() {
  312. if (!this._stopHoverover) {
  313. this._visActionHelper.hideToolbarActions();
  314. }
  315. };
  316. /**
  317. * Handle either click or tap event
  318. *
  319. * @param event Event object
  320. */
  321. VisEventHandler.prototype.onClickTap = function onClickTap(event) {
  322. return event && event.type === 'tap' ? this.onTap(event) : this.onClick(event);
  323. };
  324. /**
  325. * Handle mouse click event
  326. *
  327. * @param event Event object
  328. */
  329. VisEventHandler.prototype.onClick = function onClick(event) {
  330. if (this._skipSelection) {
  331. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  332. } else {
  333. var _getOnClickData2 = this._getOnClickData(event),
  334. shouldHandle = _getOnClickData2.shouldHandle,
  335. items = _getOnClickData2.items,
  336. isMultiSelect = _getOnClickData2.isMultiSelect;
  337. if (shouldHandle) {
  338. if (items) {
  339. if (items.length > 0) {
  340. this._handleSelections(event, items, { isMultiSelect: isMultiSelect });
  341. event.preventDefault();
  342. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  343. } else {
  344. //prevent tooltip showing so it does not win over ODT
  345. this._clearHoverTimer();
  346. this._clearAll(event);
  347. }
  348. }
  349. }
  350. }
  351. };
  352. /**
  353. * We do not need to check for this._skipSelection because it is only used onHover.
  354. * We do not need to close the toolbar because we can only open a new one after closing the current one
  355. * when using the keyboard.
  356. */
  357. VisEventHandler.prototype.onKeyDown = function onKeyDown(event) {
  358. if (this._target) {
  359. var result = this._target.processKeyDown(event);
  360. if (result) {
  361. var items = this._target.getEventTargets(event);
  362. if (items && items.length > 0) {
  363. this._handleSelections(event, items, { forceRightClick: true });
  364. event.preventDefault();
  365. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  366. }
  367. }
  368. }
  369. };
  370. /**
  371. * Returns the onClick data
  372. *
  373. * 1. Left Click + isLassoActive : Ignore
  374. * 2. Left Click + !isLassoActive: Return the clicked item only
  375. * 3. Right Click + isLassoActive: Return selectedItemCache
  376. * 4. Right Click + !isLassoActive
  377. * a. User clicked on an already selected item : Return the selectedItemCache
  378. * b. User clicked on a non-selected item : Return event targets
  379. *
  380. * @param event Event object
  381. */
  382. VisEventHandler.prototype._getOnClickData = function _getOnClickData(event) {
  383. var items = this._target && this._target.getEventTargets ? this._target.getEventTargets(event) : [];
  384. var isRightClick = event.type === 'contextmenu';
  385. var ignoreCase = !isRightClick && this.lassoCtrl.isLassoMode();
  386. var isMultiSelect = !ignoreCase && items && items.length > 1;
  387. return { shouldHandle: !ignoreCase, items: items, isMultiSelect: isMultiSelect };
  388. };
  389. /**
  390. * Handle mobile tap event
  391. *
  392. * @param event Event object
  393. */
  394. VisEventHandler.prototype.onTap = function onTap(event) {
  395. this._resolveCoordinates(event);
  396. if (this._skipSelection) {
  397. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  398. } else {
  399. var items = this._target && this._target.getEventTargets ? this._target.getEventTargets(event) : [];
  400. if (items) {
  401. if (items.length > 0) {
  402. var bSelected = this._isItemsSelected(items);
  403. var bHighlighted = this._isItemsHighlighed(items);
  404. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  405. // if the target items are either highlighted or selected then toggle the selection
  406. // Otherwise highlight and force a tooltip.
  407. if (bSelected || bHighlighted) {
  408. // force to toggle / append selections (aka. CTRL + left-click)
  409. this._handleSelections(event, items, { forceCtrlClick: true });
  410. } else {
  411. this._handleHighlights(items);
  412. // force to show the tooltips
  413. this._handleTooltips(event, items, true);
  414. }
  415. } else {
  416. this._clearAll(event);
  417. }
  418. }
  419. }
  420. };
  421. /**
  422. * Handle mobile hold (long press) event
  423. */
  424. VisEventHandler.prototype.onHold = function onHold(event) {
  425. this._resolveCoordinates(event);
  426. var isMultiSelect = false;
  427. this._onHold = true;
  428. var items = void 0;
  429. if (this.lassoCtrl.isLassoMode()) {
  430. items = this._target && this._target.getTargetsByCords ? this._target.getTargetsByCords(this.lassoCtrl.getCoordinates(), false) : [];
  431. isMultiSelect = true;
  432. } else {
  433. items = this._target && this._target.getEventTargets ? this._target.getEventTargets(event) : [];
  434. }
  435. // treat it like an right-click
  436. this._handleSelections(event, items, { forceRightClick: true, isMultiSelect: isMultiSelect });
  437. };
  438. /**
  439. * Store the visualization Interactivity state
  440. */
  441. VisEventHandler.prototype._storeInteractivityState = function _storeInteractivityState(state) {
  442. // store the state as a visualization property
  443. this._ownerWidget.updateVisProperties({
  444. id: 'interactivityState',
  445. value: state
  446. }, {
  447. silent: true
  448. });
  449. };
  450. /**
  451. * Handle mouse wheel scroll event
  452. *
  453. * @param event Event object
  454. */
  455. VisEventHandler.prototype.onMouseWheel = function onMouseWheel(event) {
  456. if (this._target.canZoom() && this._target.zoom) {
  457. this._target.zoomStart(event);
  458. this._target.zoom(event);
  459. var state = this._target.zoomEnd(event);
  460. if (state) {
  461. this._storeInteractivityState(state);
  462. }
  463. event.preventDefault();
  464. }
  465. };
  466. /**
  467. * Handle transformstart to handle beginning of zoom-in/out
  468. */
  469. VisEventHandler.prototype.onPinchStart = function onPinchStart(event) {
  470. if (this._target.canZoom() && this._target.zoom) {
  471. this._resolveCoordinates(event);
  472. // Pan gesture starts due to the touch event that occurs before the pinch
  473. // explicitly cancel the pan gesture before starting the zoom gesture
  474. this._target.panEnd(event);
  475. this._target.zoomStart(event);
  476. }
  477. };
  478. /**
  479. * Handle transform gesture to zoom-in/out
  480. */
  481. VisEventHandler.prototype.onPinch = function onPinch(event) {
  482. if (this._target.canZoom() && this._target.zoom) {
  483. this._resolveCoordinates(event);
  484. this._target.zoom(event);
  485. // Prevent synthetic events now that a touch gesture is guaranteed
  486. (event.gesture || event.originalEvent || event).preventDefault();
  487. }
  488. };
  489. /**
  490. * Handle transformend to handle the end of zoom-in/out
  491. */
  492. VisEventHandler.prototype.onPinchEnd = function onPinchEnd(event) {
  493. if (this._target.canZoom() && this._target.zoom) {
  494. this._resolveCoordinates(event);
  495. var state = this._target.zoomEnd(event);
  496. if (state) {
  497. this._storeInteractivityState(state);
  498. }
  499. }
  500. };
  501. /**
  502. * Handle either the tap or touchstart
  503. */
  504. VisEventHandler.prototype.onClickTapPanStart = function onClickTapPanStart(event) {
  505. // avoid clicktap being cancelled out by touchstart
  506. return event.type === 'touchstart' ? this.onPanStart(event) : this.onClickTap(event);
  507. };
  508. /**
  509. * Handle dragstart to handle beginning of pan
  510. */
  511. VisEventHandler.prototype.onPanStart = function onPanStart(event) {
  512. if (this._canPan(event)) {
  513. this._resolveCoordinates(event);
  514. this._target.panStart(event);
  515. // Do not prevent synthetic events on touchstart/touchend as some visualizations use click events with no touch fallback
  516. }
  517. };
  518. /**
  519. * Handle dragend to handle the end of pan
  520. */
  521. VisEventHandler.prototype.onPanEnd = function onPanEnd(event) {
  522. this._resolveCoordinates(event);
  523. var state = this._target.panEnd(event);
  524. if (state) {
  525. this._storeInteractivityState(state);
  526. }
  527. // Do not prevent synthetic events on touchstart/touchend as some visualizations use click events with no touch fallback
  528. };
  529. /**
  530. * Handle touchmove to handle pan
  531. */
  532. VisEventHandler.prototype.onPanMove = function onPanMove(event) {
  533. var originalEvent = event.gesture || event.originalEvent || event;
  534. var isZoom = originalEvent.touches && event.originalEvent.touches.length === 2;
  535. if (this._canPan(event)) {
  536. this._resolveCoordinates(event);
  537. this._target.pan(event);
  538. // Prevent synthetic events now that a touch gesture is guaranteed
  539. originalEvent.preventDefault();
  540. } else if (isZoom) {
  541. // When user pinches with two touches, both 'transform' and 'touchmove' events are fired.
  542. // In order to prevent the entire page from zooming in and out,
  543. // Prevent default for all double touch gestures which are considered as zoom
  544. originalEvent.preventDefault();
  545. }
  546. };
  547. /**
  548. * Handle mouse down event, fired before click
  549. *
  550. * @param event Event object
  551. */
  552. VisEventHandler.prototype.onMouseDown = function onMouseDown(event) {
  553. var _getOnClickData3 = this._getOnClickData(event),
  554. shouldHandle = _getOnClickData3.shouldHandle,
  555. items = _getOnClickData3.items;
  556. if (shouldHandle && !!items && items.length > 0) {
  557. // Multiselect (Defect #219253): If there are items under the point,
  558. // set key on eventChain to tell dashboard-core to not deselect
  559. this.setEventLocalProperty(event, 'preventWidgetDeselect', true);
  560. }
  561. this._skipSelection = false;
  562. this._mouseDown = {
  563. X: event.pageX,
  564. Y: event.pageY
  565. };
  566. if (!this.lassoCtrl.isLassoMode() && this._target.canZoom && this._target.canZoom() && this._target.panStart) {
  567. this._target.panStart(event);
  568. }
  569. };
  570. /**
  571. * Handle mouse up event
  572. */
  573. VisEventHandler.prototype.onMouseUp = function onMouseUp(event) {
  574. if (this._target.canZoom && this._target.canZoom() && this._target.panEnd) {
  575. var state = this._target.panEnd(event);
  576. if (state) {
  577. this._storeInteractivityState(state);
  578. }
  579. }
  580. };
  581. VisEventHandler.prototype.getEdgeSelection = function getEdgeSelection() {
  582. return this._edgeSelection;
  583. };
  584. /**
  585. * Handle mouse up event
  586. */
  587. VisEventHandler.prototype._onDocumentMouseUp = function _onDocumentMouseUp() {
  588. this._mouseDown = false;
  589. };
  590. /**
  591. * Handle touch end event on mobile
  592. */
  593. VisEventHandler.prototype._onDocumentTouchEnd = function _onDocumentTouchEnd() {
  594. if (this._onHold) {
  595. this._onHold = false;
  596. }
  597. };
  598. /**
  599. * Determine whether the target can pan
  600. *
  601. * @param event Event object
  602. * @return true if the target can pan with the given event, otherwise false
  603. */
  604. VisEventHandler.prototype._canPan = function _canPan(event) {
  605. return this._target.canZoom && this._target.canZoom() && event.originalEvent.touches.length === 1 && !this.lassoCtrl.isLassoMode();
  606. };
  607. /**
  608. * Resolve the coordinates from the given event
  609. *
  610. * @param event Event object
  611. * @return object containing the resolved x / y coordinates
  612. */
  613. VisEventHandler.prototype._resolveCoordinates = function _resolveCoordinates(event) {
  614. var touches = null;
  615. if (event.targetTouches) {
  616. touches = event.targetTouches;
  617. } else if (event.originalEvent && event.originalEvent.targetTouches) {
  618. touches = event.originalEvent.targetTouches;
  619. } else if (event.gesture) {
  620. touches = event.gesture.touches;
  621. }
  622. var isTouch = touches && touches.length;
  623. if (isTouch) {
  624. var coords = touches && touches.length ? touches[0] : null;
  625. // touchend does not have coordinates
  626. if (coords && coords.clientX !== undefined) {
  627. event.isTouch = true;
  628. event.clientX = coords.clientX;
  629. event.clientY = coords.clientY;
  630. event.pageX = coords.pageX;
  631. event.pageY = coords.pageY;
  632. }
  633. } else {
  634. if (event.gesture && event.gesture.center) {
  635. event.clientX = event.clientX || event.gesture.center.clientX;
  636. event.clientY = event.clientY || event.gesture.center.clientY;
  637. event.pageX = event.pageX || event.gesture.center.pageX;
  638. event.pageY = event.pageY || event.gesture.center.pageY;
  639. } else if (event.originalEvent) {
  640. event.clientX = event.clientX || event.originalEvent.clientX || event.originalEvent.pageX;
  641. event.clientY = event.clientY || event.originalEvent.clientY || event.originalEvent.pageY;
  642. event.pageX = event.pageX || event.originalEvent.pageX;
  643. event.pageY = event.pageY || event.originalEvent.pageY;
  644. }
  645. }
  646. };
  647. /**
  648. * Get the tooltip bound (coordinates) based on the given event
  649. *
  650. * @param event Event object
  651. */
  652. VisEventHandler.prototype._getBoundsInfoFromEvent = function _getBoundsInfoFromEvent(event) {
  653. return {
  654. top: event.clientY,
  655. height: 1,
  656. left: event.clientX - 10, // Want the tooltip to show a little to the left of the mouse
  657. width: 20,
  658. parent: document.body
  659. };
  660. };
  661. /**
  662. * Set the event local property
  663. *
  664. * @param event Event object
  665. * @param name Property name
  666. * @param value Property value
  667. */
  668. VisEventHandler.prototype.setEventLocalProperty = function setEventLocalProperty(event, name, value) {
  669. var eventChainLocal = new EventChainLocal(event);
  670. eventChainLocal.setProperty(name, value);
  671. };
  672. /**
  673. * Determine whether the mouse is dragging
  674. *
  675. * @param event Event object
  676. */
  677. VisEventHandler.prototype._isDragging = function _isDragging(event) {
  678. if (event.type === 'touchmove' && this.lassoCtrl.isLassoMode()) {
  679. return event.originalEvent.touches.length === 1;
  680. }
  681. return this._mouseDown && (Math.abs(this._mouseDown.X - event.pageX) > 5 || Math.abs(this._mouseDown.Y - event.pageY) > 5);
  682. };
  683. /**
  684. * Clear the hover timer
  685. */
  686. VisEventHandler.prototype._clearHoverTimer = function _clearHoverTimer() {
  687. if (this._oTimerOut !== null) {
  688. clearTimeout(this._oTimerOut);
  689. this._oTimerOut = null;
  690. }
  691. };
  692. /**
  693. * Clear the last highlight
  694. */
  695. VisEventHandler.prototype._clearLastHighlight = function _clearLastHighlight() {
  696. if (this._lastHighlighted) {
  697. // clear previous highlighted item decorations
  698. this._clearDecorations(this._lastHighlighted, 'highlight');
  699. }
  700. this._lastHighlighted = undefined;
  701. this._skipHoverover = false;
  702. };
  703. /**
  704. * Clear deocrations
  705. *
  706. * @param items Event target items
  707. * @param name Decoration name, Clears all decorations if name is undefined
  708. */
  709. VisEventHandler.prototype._clearDecorations = function _clearDecorations(items, name) {
  710. if (this._target && this._target.decorateTarget) {
  711. this._target.decorateTarget(items, name, false);
  712. }
  713. };
  714. /**
  715. * Compare two event targets
  716. *
  717. * @param items1 event targets 1
  718. * @param items2 event targets 2
  719. * @return true if two targets are the same, otherwise false
  720. */
  721. VisEventHandler.prototype._compareItems = function _compareItems(items1, items2) {
  722. var keys1 = _.pluck(items1, 'key');
  723. var keys2 = _.pluck(items2, 'key');
  724. return _.difference(keys1, keys2).length === 0 && _.difference(keys2, keys1).length === 0;
  725. };
  726. /**
  727. * Determines whether the given target items are currently highlighted
  728. *
  729. * @param items event target items
  730. * @return true if the target items are highlighted, otherwise false
  731. */
  732. VisEventHandler.prototype._isItemsHighlighed = function _isItemsHighlighed(items) {
  733. return this._compareItems(this._lastHighlighted, items);
  734. };
  735. /**
  736. * Determines whether the given target items are currently implicitly selected
  737. *
  738. * @param items event target items
  739. * @return true if the target items are implicitly selected, otherwise false
  740. */
  741. VisEventHandler.prototype._isItemsImpliedSelected = function _isItemsImpliedSelected(items) {
  742. return _.find(this._lastImpliedSelection, function (impliedSelection) {
  743. return impliedSelection === items;
  744. });
  745. };
  746. /**
  747. * Handle hover tooltip event.
  748. * Show a delayed (500ms) tooltip on chart elements
  749. *
  750. * @param event Event object
  751. * @param items Event target items
  752. */
  753. VisEventHandler.prototype._handleTooltips = function _handleTooltips(event, items, forceTooltips) {
  754. var _this3 = this;
  755. var prevTooltip = this._lastTooltip ? this._lastTooltip : [];
  756. this._lastHoverEvent = event;
  757. this._tooltipItems = items;
  758. if (this._tooltipItems && this._tooltipItems.length > 0) {
  759. // keep track of the selected item
  760. this._targetElement.addClass('cursor-pointer');
  761. if (!this._compareItems(prevTooltip, this._tooltipItems)) {
  762. this._clearHoverTimer();
  763. this._oTimerOut = setTimeout(function () {
  764. _this3._clearHoverTimer();
  765. var itemExist = _this3._tooltipItems && _this3._tooltipItems.length > 0;
  766. var allowHover = !_this3._stopHoverover && !_this3._skipHoverover;
  767. var force = forceTooltips;
  768. if (itemExist && (allowHover || force)) {
  769. var aSelectionInfo = _this3._getDataPayload(_this3._tooltipItems, VisTooltipInfo);
  770. if (aSelectionInfo) {
  771. var infoShown = _this3._showSelectionInfo(aSelectionInfo, _this3._lastHoverEvent, false, true, _this3._drillOnly, /*noDrillthrough*/false, {
  772. isHover: true
  773. });
  774. if (infoShown) {
  775. _this3._lastTooltip = _this3._tooltipItems;
  776. }
  777. _this3._lastHoverEvent = null;
  778. _this3._tooltipItems = null;
  779. }
  780. }
  781. }, 500);
  782. }
  783. } else {
  784. this._targetElement.removeClass('cursor-pointer');
  785. if (this._lastTooltip) {
  786. this._lastTooltip = null;
  787. this._clearHoverTimer();
  788. this._oTimerOut = setTimeout(function () {
  789. _this3._clearHoverTimer();
  790. if (!_this3._stopHoverover) {
  791. _this3._visActionHelper.hideToolbarActions();
  792. }
  793. }, 500);
  794. }
  795. }
  796. };
  797. /**
  798. * Handle hightlight event.
  799. * Highlight the chart element upon hover.
  800. *
  801. * @param items Event target items
  802. * @param bAppend Append items in this._lastHighlighted to items if true
  803. */
  804. VisEventHandler.prototype._handleHighlights = function _handleHighlights(items, bAppend) {
  805. var prevHighlight = this._lastHighlighted ? this._lastHighlighted : [];
  806. if (bAppend) {
  807. var nonSelected = _.filter(this._lastHighlighted, function (obj) {
  808. return obj.source && obj.source.getDecoration && !obj.source.getDecoration('selected');
  809. });
  810. items.push.apply(items, nonSelected);
  811. }
  812. if (items && items.length > 0) {
  813. if (!this._isItemsHighlighed(items)) {
  814. if (this._target && this._target.decorateTarget) {
  815. // clear previous highlights
  816. this._clearLastHighlight();
  817. if (this._target.decorateTarget(items, 'highlight')) {
  818. //Keep track of the newly highlighted items
  819. this._lastHighlighted = items;
  820. }
  821. }
  822. }
  823. } else if (prevHighlight.length > 0) {
  824. // clear the previous selection
  825. this._clearLastHighlight();
  826. }
  827. // re-render with the new highlight
  828. if (!this._compareItems(prevHighlight, this._lastHighlighted) && this._target.completeDecorations) {
  829. this._target.completeDecorations();
  830. }
  831. };
  832. /**
  833. * Handle selection event.
  834. * Selection highlight the chart element upon click.
  835. *
  836. * @param items Event target items
  837. * @param {boolean} [options.forceCtrlClick=fasle] - True forces a control + click selection
  838. * @param {boolean} [options.forceRightClick=fasle] - True forces a right click selection
  839. * @param {boolean} [options.isMultiSelect=false] - True indicates multiple datapoints are selected.
  840. */
  841. VisEventHandler.prototype._handleSelections = function _handleSelections(event, items, options) {
  842. var bCtrlClick = options.forceCtrlClick || event.ctrlKey || event.metaKey;
  843. var bRightClick = options.forceRightClick || event.type === 'contextmenu';
  844. this._skipHoverover = false;
  845. var resolved = null;
  846. if (bRightClick) {
  847. // Skip the hover to avoid tooltips winning over contextmenu
  848. this._skipHoverover = true;
  849. // handle right click
  850. var oNewSelection = this._getDataPayload(items, VisTooltipInfo);
  851. resolved = this._resolveItems(items);
  852. if (resolved.length > 0) {
  853. var _options = items[0].selectionContext ? {
  854. slots: items[0].selectionContext.slots,
  855. mapIndex: items[0].selectionContext.mapIndex,
  856. actions: items[0].selectionContext.actions
  857. } : {};
  858. _options.area = items[0].area;
  859. _options.isAreaSelected = items[0].isAreaSelected;
  860. var includeApplyFilter = void 0,
  861. noFilters = void 0,
  862. noDrillthrough = void 0;
  863. if (items[0].onlyGlobalActions) {
  864. // Only want to show actions applicable to the full visualization, e.g. TextAction
  865. includeApplyFilter = false;
  866. noFilters = true;
  867. noDrillthrough = true;
  868. } else {
  869. includeApplyFilter = bRightClick;
  870. noFilters = false;
  871. noDrillthrough = false;
  872. }
  873. this._showSelectionInfo(oNewSelection, event, includeApplyFilter, noFilters, undefined, noDrillthrough, _options);
  874. this._triggerWidgetEvent('visevent:select', event, this._target, items, { selectionInfo: oNewSelection, append: bCtrlClick, lasso: options.isMultiSelect });
  875. this._handleHighlights(items, bCtrlClick);
  876. return this._select(resolved, /*select*/true, bCtrlClick, /*pending*/true, items[0].isEdgeSelect, options.isMultiSelect);
  877. } else {
  878. // show title actions on right-click
  879. this._titleActions(event, items);
  880. }
  881. } else {
  882. resolved = this._resolveItems(items);
  883. this._handleHighlights(items);
  884. if (resolved.length > 0) {
  885. var isSelected = this._isSelected(resolved, items[0].isEdgeSelect);
  886. // When the's select is IDENTICAL to the existing selection, cancel selection (doSelect=false)
  887. // otherwise, set selection to match what the user clicked - even if what the user clicked contains or is contained by existing selection
  888. var doSelect = !isSelected;
  889. var doAppend = bCtrlClick || this.lassoCtrl.isLassoMode() && isSelected;
  890. var oSelectionInfo = this._getDataPayload(items);
  891. this._triggerWidgetEvent('visevent:select', event, this._target, items, { selectionInfo: oSelectionInfo, append: doAppend, lasso: options.isMultiSelect });
  892. return this._select(resolved, doSelect, doAppend, /*pending*/false, items[0].isEdgeSelect, options.isMultiSelect);
  893. } else if (items && items.length >= 1) {
  894. var type = items[0].type;
  895. switch (type) {
  896. case 'customdata':
  897. return this._handleCustomDataSelections(items, event);
  898. case 'itemclass':
  899. return this._handleImpliedSelections(items, bCtrlClick, true);
  900. case 'summary':
  901. return this._handleImpliedSelections(items, bCtrlClick, true);
  902. default:
  903. break;
  904. }
  905. }
  906. }
  907. };
  908. VisEventHandler.prototype._isSelectionsWithCustomData = function _isSelectionsWithCustomData(itemsArray) {
  909. var aResult = _.filter(itemsArray, function (item) {
  910. return item.type !== 'customdata';
  911. });
  912. return itemsArray.length > 0 && (!aResult || aResult.length === 0); //Means all selections are custom data selections
  913. };
  914. /**
  915. * Handle implied selection event. (Similar to _handleHighlights; used to decorate
  916. * target with implied_selection instead of highlight). On hover, if it's not a multi-select,
  917. * remove the implied_selection styling on the previous implied selections.
  918. *
  919. * @param items Event target items
  920. * @param isMultiSelect {Boolean} True if multiselect action is occuring (ctrl + click)
  921. * @param apply {Boolean} True if the decoration should be applied
  922. */
  923. VisEventHandler.prototype._handleImpliedSelections = function _handleImpliedSelections(items, isMultiSelect, apply) {
  924. var prevImpliedSelection = this._lastImpliedSelection ? this._lastImpliedSelection : [];
  925. if (apply && items && items.length > 0) {
  926. if (!this._isItemsImpliedSelected(items)) {
  927. // Add target items to array of implied selections
  928. this._lastImpliedSelection.push(items);
  929. this._target.decorateTarget(items, 'implied_selection', apply, isMultiSelect);
  930. }
  931. } else if (prevImpliedSelection.length > 0 && !isMultiSelect) {
  932. // Clear the previous implied selections
  933. this._lastImpliedSelection = [];
  934. this._clearDecorations(items, 'implied_selection');
  935. }
  936. };
  937. VisEventHandler.prototype._handleCustomDataSelections = function _handleCustomDataSelections(items, event) {
  938. this._triggerWidgetEvent('visevent:customdataselection', event, this._target, items);
  939. if (this._target && this._target.applyCustomDataSelection) {
  940. var currentSelectedIds = _.pluck(this._visAPI.getDecoratedCustomData('selected'), 'id');
  941. this._target.applyCustomDataSelection(_.filter(items, function (item) {
  942. return !_.contains(currentSelectedIds, item.key);
  943. }));
  944. }
  945. };
  946. /**
  947. * Resolve the event target items to data item ids and tuples items
  948. *
  949. * @param items Event target items
  950. * @return resolved array of object containing the data item ids and tuple items
  951. */
  952. VisEventHandler.prototype._resolveItems = function _resolveItems(items) {
  953. var _this4 = this;
  954. var resolved = [];
  955. //The value index corresponds to the slot index
  956. _.each(items, function (item) {
  957. if (item.type === 'datapoint') {
  958. resolved = resolved.concat(_this4._resolveDataPointItem(item));
  959. } else if (item.type === 'item') {
  960. resolved = resolved.concat(_this4._resolveEdgeItem(item));
  961. }
  962. });
  963. return resolved;
  964. };
  965. /**
  966. * Add the event target item to the selections info object
  967. *
  968. * @param selections Selection info object
  969. * @param item Event target item
  970. */
  971. VisEventHandler.prototype._processDataPointSelection = function _processDataPointSelection(selections, item) {
  972. var _this5 = this;
  973. var slots = this._getMappedSlotListByItem(item);
  974. _.each(item.values, function (rowdata, valueIndex) {
  975. var slot = item.slotAPIs ? item.slotAPIs[valueIndex] : slots[valueIndex];
  976. if (slot) {
  977. var valueSpans = 0;
  978. _.each(rowdata, function (value, itemInSlotIndex) {
  979. if (value === null) {
  980. value = Formatter.format(null);
  981. }
  982. var slotDataItem = _this5._getSlotDataItem(slot, item, itemInSlotIndex + valueSpans);
  983. if (value.span) {
  984. //Any parts of a value that span multiple levels are considered "unbalanced".
  985. //values in the tuple beyond the span should be associated with items beyond the span
  986. valueSpans += value.span - 1;
  987. }
  988. if (slotDataItem && ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object' || !SlotAPIHelper.isMultiMeasuresSeriesOrValueDataItem(slotDataItem))) {
  989. selections.addSelection(slot, slotDataItem, value, item.isEdgeSelect);
  990. }
  991. });
  992. }
  993. });
  994. };
  995. VisEventHandler.prototype._resolveDataPointItem = function _resolveDataPointItem(item) {
  996. var slots = this._getMappedSlotListByItem(item);
  997. var resolved = [];
  998. _.each(item.values, function (value, valueIndex) {
  999. var slot = item.slotAPIs ? item.slotAPIs[valueIndex] : slots[valueIndex];
  1000. if (slot) {
  1001. var dataItems = slot.getDataItemList();
  1002. _.each(value, function (v, itemInSlotIndex) {
  1003. var dataItem = dataItems[itemInSlotIndex];
  1004. if (dataItem && dataItem.getType() === 'attribute' && !SlotAPIHelper.isMultiMeasuresSeriesOrValueDataItem(dataItem)) {
  1005. resolved.push({
  1006. dataItemId: dataItem.getId(),
  1007. itemId: dataItem.getColumnId(),
  1008. tupleItem: v
  1009. });
  1010. }
  1011. });
  1012. }
  1013. });
  1014. return [resolved];
  1015. };
  1016. /**
  1017. * Expand categories assigned of an edge to include dataItem information.
  1018. */
  1019. VisEventHandler.prototype._resolveEdgeItem = function _resolveEdgeItem(item) {
  1020. var slots = this._getMappedSlotListByItem(item);
  1021. var resolved = [];
  1022. //The values array within each item should be length 2 for edge items (first item is category, second is measure value)
  1023. _.each(item.values, function (value, valueIndex) {
  1024. var slot = slots[valueIndex];
  1025. if (slot) {
  1026. var dataItems = slot.getDataItemList();
  1027. _.each(value, function (v, itemIndex) {
  1028. var dataItem = dataItems[itemIndex];
  1029. if (!SlotAPIHelper.isMultiMeasuresSeriesOrValueDataItem(dataItem) && dataItem.getType() === 'attribute') {
  1030. resolved.push({
  1031. dataItemId: dataItem.getId(),
  1032. itemId: dataItem.getColumnId(),
  1033. tupleItem: v
  1034. });
  1035. }
  1036. });
  1037. }
  1038. });
  1039. return resolved;
  1040. };
  1041. /**
  1042. * Add the event target item to the selections info object
  1043. *
  1044. * @param selections Selection info object
  1045. * @param item Event target item
  1046. */
  1047. VisEventHandler.prototype._processEdgeSelection = function _processEdgeSelection(selections, item) {
  1048. var _this6 = this;
  1049. var slots = this._getMappedSlotListByItem(item);
  1050. if (item.values) {
  1051. _.each(item.values, function (value, valueIndex, values) {
  1052. if (value) {
  1053. for (var i = 0; i < value.length; i++) {
  1054. if (typeof value[i] !== 'undefined') {
  1055. var slot = slots[valueIndex];
  1056. //Current selection items could have undefined/unset dataItem in the payload
  1057. var slotDataItem = void 0;
  1058. if (slot.getDefinition().getProperty('multiMeasure') && slot.getDataItemList().length > 0) {
  1059. (function () {
  1060. // This is for a specific case where a multi measures value is not in the correct index
  1061. // The multiMeasuresSeriesSlot data item id is compared to the id's of this slot's data items to find the correct one
  1062. var dataset = slot.getDefinition().getDatasetIdList()[0];
  1063. var multiMeasuresSeriesSlot = _.find(slots, function (slot) {
  1064. return SlotAPIHelper.isMultiMeasuresSeriesSlot(slot) && slot.getDefinition().getDatasetIdList()[0] === dataset;
  1065. });
  1066. if (!multiMeasuresSeriesSlot) {
  1067. multiMeasuresSeriesSlot = SlotAPIHelper.getMultiMeasureSeriesSlot(_this6.visualization, dataset);
  1068. }
  1069. var multiMeasuresSlotIndex = _.indexOf(_.map(slots, function (slot) {
  1070. return slot.getId();
  1071. }), multiMeasuresSeriesSlot.getId());
  1072. var multiMeasuresDataItemIndex = _.indexOf(_.map(multiMeasuresSeriesSlot.getDataItemList(), function (dataItemApi) {
  1073. return dataItemApi.getColumnId();
  1074. }), SlotAPIHelper.MULTI_MEASURES_SERIES);
  1075. if (multiMeasuresSlotIndex >= 0 && multiMeasuresDataItemIndex >= 0 && values[multiMeasuresSlotIndex] && values[multiMeasuresSlotIndex][multiMeasuresDataItemIndex] && values[multiMeasuresSlotIndex][multiMeasuresDataItemIndex].u) {
  1076. var dataItemUId = values[multiMeasuresSlotIndex][multiMeasuresDataItemIndex].u;
  1077. slotDataItem = _.find(slot.getDataItemList(), function (dataItem) {
  1078. return dataItem.getId() === dataItemUId;
  1079. });
  1080. // The data item id should be in the form '_multiMeasuresSeries(SHEET1.Income)'
  1081. // The value within parentheses is parsed to find the data item sharing that id
  1082. }
  1083. })();
  1084. }
  1085. if (slotDataItem === undefined) {
  1086. slotDataItem = slot.getDataItemList()[i];
  1087. }
  1088. if (slotDataItem) {
  1089. selections.addSelection(slot, slotDataItem, value[i], item.isEdgeSelect);
  1090. }
  1091. }
  1092. }
  1093. }
  1094. });
  1095. }
  1096. };
  1097. /**
  1098. * Add the event target item to the selection as a custom tooltip
  1099. * @param selections Selection info object
  1100. * @param item Event target item
  1101. * @example
  1102. * a custom data selection allows exposing tooltips for customdata
  1103. * custom data tooltips can be provided in 2 different forms, titles and labels(name/value pairs).
  1104. * {
  1105. * value: 'Example of a tooltip title'
  1106. * },
  1107. * {
  1108. * label: 'Predictive strength',
  1109. * value: '98%'
  1110. * },
  1111. * {
  1112. * label: 'Example of a label without a value'
  1113. * }
  1114. */
  1115. VisEventHandler.prototype._processCustomDataSelection = function _processCustomDataSelection(selections, item) {
  1116. if (this._target && this._target.getCustomDataSelections && selections.addCustomSelection) {
  1117. var customSelections = this._target.getCustomDataSelections(item);
  1118. _.each(customSelections, function (s) {
  1119. return selections.addCustomSelection((typeof s === 'undefined' ? 'undefined' : _typeof(s)) === 'object' ? s.label : s, (typeof s === 'undefined' ? 'undefined' : _typeof(s)) === 'object' ? s.value : undefined);
  1120. });
  1121. }
  1122. };
  1123. /**
  1124. * Add the event target item tooltip decoration as a custom tooltip
  1125. * @param selections Selection info object
  1126. * @param items Event target items
  1127. */
  1128. VisEventHandler.prototype._processDecorationTooltips = function _processDecorationTooltips(selections, items) {
  1129. try {
  1130. // Used by SA and forecast only currently. Only display annotation decos if one datapoint is selected
  1131. if (items && items.length === 1) {
  1132. if (this._target && this._target.getDecoration && selections.addCustomSelection) {
  1133. var tooltip = this._target.getDecoration(items[0], VisEventHandler.DECORATIONS.TOOLTIP);
  1134. if (tooltip && typeof tooltip === 'string') {
  1135. selections.addCustomSelection(tooltip);
  1136. } else if (tooltip && Array.isArray(tooltip)) {
  1137. // Each element of tooltip is Array of length 2.
  1138. tooltip.forEach(function (tip) {
  1139. if (Array.isArray(tip) && tip.length === 2) {
  1140. selections.addCustomSelection(tip[0], tip[1]);
  1141. }
  1142. });
  1143. }
  1144. }
  1145. }
  1146. } catch (e) {
  1147. this.logger.error(e);
  1148. }
  1149. };
  1150. /**
  1151. * Identify a data item from a slot by index.
  1152. * Usually this is straight forward as slot.getDataItemList()[index].
  1153. * However when measures are nested, the measure is give a series,
  1154. * the series needs to be backtraced to the original measure data item
  1155. *
  1156. * example:
  1157. * Each measures are added to a series data item as a tuple items as below:
  1158. * {
  1159. * itemClass: {
  1160. * id: '_multiMeasuresSeries'
  1161. * h: [{
  1162. * u: '_multiMeasuresSeries',
  1163. * d: 'Measures'
  1164. * }, {
  1165. * u: 'uploadfile.csv.Year',
  1166. * d: 'Year'
  1167. * }]
  1168. * },
  1169. * items:[{
  1170. * t: [{
  1171. * u: 'id_uploadfile.csv.Revenue'
  1172. * d: 'Revenue'
  1173. * }, {
  1174. * u: 'uploadfile.csv.Year->[2016]',
  1175. * d: '2017'
  1176. * }]
  1177. * }, {
  1178. * t:[{
  1179. * u: 'id_uploadfile.csv.Planned_Revenue'
  1180. * d: 'Planned Revenue'
  1181. * }, {
  1182. * u: 'uploadfile.csv.Year->[2017]',
  1183. * d: '2017'
  1184. * }]
  1185. * }, {
  1186. * t: [{
  1187. * u: 'id_uploadfile.csv.Revenue'
  1188. * d: 'Revenue'
  1189. * }, {
  1190. * u: 'uploadfile.csv.Year->[2016]',
  1191. * d: '2017'
  1192. * }]
  1193. * }, {
  1194. * t:[{
  1195. * u: 'id_uploadfile.csv.Planned_Revenue'
  1196. * d: 'Planned Revenue'
  1197. * }, {
  1198. * u: 'uploadfile.csv.Year->[2017]',
  1199. * d: '2017'
  1200. * }]
  1201. * }]
  1202. * }
  1203. *
  1204. * @param slot The target slot of the data item
  1205. * @param item Event target item
  1206. * @param index data item index within the slot
  1207. */
  1208. VisEventHandler.prototype._getSlotDataItem = function _getSlotDataItem(slot, item, index) {
  1209. var dataItemList = slot.getDataItemList();
  1210. // nested measures?
  1211. if (SlotAPIHelper.isMultiMeasuresValueSlot(slot)) {
  1212. var slots = this._getMappedSlotListByItem(item);
  1213. var slotIndex = void 0,
  1214. dataItemIndex = void 0;
  1215. // find the multimeasures slot index
  1216. _.find(slots, function (slot, index) {
  1217. if (SlotAPIHelper.isMultiMeasuresSeriesSlot(slot)) {
  1218. slotIndex = index;
  1219. return true;
  1220. }
  1221. return false;
  1222. });
  1223. // find the multimeasures series dataitem index
  1224. if (slotIndex) {
  1225. _.find(slots[slotIndex].getDataItemList(), function (dataItem, index) {
  1226. if (SlotAPIHelper.isMultiMeasuresSeriesOrValueDataItem(dataItem)) {
  1227. dataItemIndex = index;
  1228. return true;
  1229. }
  1230. return false;
  1231. });
  1232. var multiMeasuresSeries = item.values[slotIndex][dataItemIndex];
  1233. var measureId = multiMeasuresSeries.u;
  1234. // return the measure data item
  1235. return _.find(slot.getDataItemList(), function (dataItem) {
  1236. return dataItem.getId() === measureId;
  1237. });
  1238. } else {
  1239. return slot.getDataItemList()[index];
  1240. }
  1241. } else {
  1242. return dataItemList[index];
  1243. }
  1244. };
  1245. /**
  1246. * Check whether the given resolved items are selected
  1247. *
  1248. * @param resolvedItems Array of resolved items
  1249. */
  1250. VisEventHandler.prototype._isSelected = function _isSelected(resolvedItems, isEdgeSelect) {
  1251. var payload = this._getSelectionPayload(resolvedItems, false, isEdgeSelect);
  1252. return this._selector.isSelected(payload, this._edgeSelection || isEdgeSelect);
  1253. };
  1254. /**
  1255. * Determines whether the given target items are custom data
  1256. * @param items event target items
  1257. * @return true if the target items are custom data, otherwise false
  1258. */
  1259. VisEventHandler.prototype._isCustomDataItems = function _isCustomDataItems(items) {
  1260. return _.chain(items).pluck('type').contains('customdata').value();
  1261. };
  1262. VisEventHandler.prototype._isCustomDataSelected = function _isCustomDataSelected(items) {
  1263. var currentSelectionIds = _.pluck(this._visAPI.getDecoratedCustomData('selected'), 'id');
  1264. // check if there is something currently selected
  1265. if (currentSelectionIds.length > 0) {
  1266. var customItemIds = _.chain(items).pluck('values').flatten().pluck('payload').pluck('id').value();
  1267. if (customItemIds.length > 0) {
  1268. return _.intersection(currentSelectionIds, customItemIds).length === customItemIds.length;
  1269. }
  1270. }
  1271. return false;
  1272. };
  1273. /**
  1274. * Determines whether the given target items are currently selected
  1275. *
  1276. * @param items event target items
  1277. * @return true if the target items are highlighted, otherwise false
  1278. */
  1279. VisEventHandler.prototype._isItemsSelected = function _isItemsSelected(items) {
  1280. var isSelected = false;
  1281. if (this._isCustomDataItems(items)) {
  1282. isSelected = this._isCustomDataSelected(items);
  1283. } else {
  1284. var resolved = this._resolveItems(items);
  1285. isSelected = resolved.length > 0 ? this._isSelected(resolved, items[0].isEdgeSelect) : false;
  1286. }
  1287. return isSelected;
  1288. };
  1289. /**
  1290. * Add/Remove the selected items to the selection controller
  1291. *
  1292. * @param resolved Array of resolved items
  1293. * @param doSelect boolean flag indicating whether to add or remove selection
  1294. * @param append boolean flag indicating whether to append to the existing selections
  1295. * @param pending boolean indicating that the selection should be deferred (applied on keep/exclude/filter later on).
  1296. * @param multiTuple boolean indicating multiple tuples are selected
  1297. */
  1298. VisEventHandler.prototype._select = function _select(resolved, doSelect, append, pending, isEdgeSelect, multiTuple) {
  1299. var transactionToken = this._transaction.startTransaction();
  1300. var selections = pending ? this.content.getFeature('DataPointSelections.pending') : this.content.getFeature('DataPointSelections');
  1301. var payload = this._getSelectionPayload(resolved, multiTuple, isEdgeSelect);
  1302. if (!append) {
  1303. selections.clearAll(transactionToken);
  1304. }
  1305. if (doSelect) {
  1306. selections.select(payload, transactionToken);
  1307. } else {
  1308. selections.deselect(payload, transactionToken);
  1309. }
  1310. this._transaction.endTransaction(transactionToken);
  1311. };
  1312. VisEventHandler.prototype._getSelectionPayload = function _getSelectionPayload(selections, multiTuple) {
  1313. var edgeSelect = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  1314. if (multiTuple) {
  1315. if (edgeSelect) {
  1316. return _.map(_.flatten(selections), function (s) {
  1317. return {
  1318. categories: [{
  1319. dataItemId: s.dataItemId,
  1320. columnId: s.itemId,
  1321. label: s.tupleItem && s.tupleItem.d,
  1322. parentId: s.tupleItem && s.tupleItem.p && s.tupleItem.p.u,
  1323. value: s.tupleItem && s.tupleItem.u
  1324. }],
  1325. edgeSelect: edgeSelect
  1326. };
  1327. });
  1328. } else {
  1329. return _.map(selections, function (datapoint) {
  1330. return {
  1331. categories: _.map(datapoint, function (s) {
  1332. return {
  1333. dataItemId: s.dataItemId,
  1334. columnId: s.itemId,
  1335. label: s.tupleItem && s.tupleItem.d,
  1336. parentId: s.tupleItem && s.tupleItem.p && s.tupleItem.p.u,
  1337. value: s.tupleItem && s.tupleItem.u
  1338. };
  1339. }),
  1340. edgeSelect: edgeSelect
  1341. };
  1342. });
  1343. }
  1344. } else {
  1345. return [{
  1346. categories: _.chain(selections).flatten().map(function (s) {
  1347. return {
  1348. dataItemId: s.dataItemId,
  1349. columnId: s.itemId,
  1350. label: s.tupleItem && s.tupleItem.d,
  1351. parentId: s.tupleItem && s.tupleItem.p && s.tupleItem.p.u,
  1352. value: s.tupleItem && s.tupleItem.u
  1353. };
  1354. }).value(),
  1355. edgeSelect: edgeSelect
  1356. }];
  1357. }
  1358. };
  1359. /**
  1360. * Reduce items to itemIds and tuples
  1361. *
  1362. * @param resolved Array of resolved items
  1363. */
  1364. VisEventHandler.prototype.reduceItems = function reduceItems(resolved) {
  1365. var selection = {
  1366. itemIds: [],
  1367. tuple: []
  1368. };
  1369. resolved.reduce(function (accumulator, item) {
  1370. var _itemsId = void 0;
  1371. var _tuple = void 0;
  1372. if (Array.isArray(item)) {
  1373. //datapoint selection
  1374. _itemsId = _.map(item, function (o) {
  1375. return o.itemId;
  1376. });
  1377. _tuple = _.map(item, function (o) {
  1378. if (_.isUndefined(o.tupleItem && o.tupleItem.u)) {
  1379. return { u: o.tupleItem, d: o.tupleItem };
  1380. }
  1381. return o.tupleItem;
  1382. });
  1383. } else {
  1384. //edge selection
  1385. _itemsId = [item.itemId];
  1386. _tuple = item.tupleItem;
  1387. }
  1388. accumulator.itemIds = _.uniq(accumulator.itemIds.concat(_itemsId));
  1389. accumulator.tuple.push(Array.isArray(_tuple) ? _.uniq(_tuple, false, function (t) {
  1390. return t && t.u || t;
  1391. }) : _tuple);
  1392. return accumulator;
  1393. }, selection);
  1394. return selection;
  1395. };
  1396. /**
  1397. * Show the title action toolbar for the given items
  1398. */
  1399. VisEventHandler.prototype._titleActions = function _titleActions(event, items) {
  1400. var _this7 = this;
  1401. var aSlots = [];
  1402. var itemsArea = items && items[0] ? items[0].area : undefined;
  1403. if (items && items.length) {
  1404. for (var i = 0; i < items.length; i++) {
  1405. var item = items[i];
  1406. if (item.type !== 'customdata') {
  1407. (function () {
  1408. var slots = _this7.visualization.getSlots().getMappedSlotList();
  1409. item.values.forEach(function (value, index) {
  1410. if (!aSlots.find(function (slot) {
  1411. return slot.getId() === slots[index].getId();
  1412. })) {
  1413. aSlots.push(slots[index]);
  1414. }
  1415. });
  1416. })();
  1417. }
  1418. }
  1419. var mapIndex = items[0].selectionContext ? items[0].selectionContext.mapIndex : undefined;
  1420. var actions = items[0].selectionContext && items[0].selectionContext.actions || [];
  1421. // Array for when there are multiple data items selected within a slot
  1422. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  1423. this._visActionHelper.showTitleActions(aSlots, { 'bounds': this._getBoundsInfoFromEvent(event) }, null, // selected slot items are null for non-focus mode actions
  1424. mapIndex, itemsArea, actions);
  1425. }
  1426. };
  1427. /**
  1428. * Clear all selections from the selection controller
  1429. */
  1430. VisEventHandler.prototype._clearAll = function _clearAll(event) {
  1431. var _this8 = this;
  1432. this._triggerWidgetEvent('visevent:clearselection', event);
  1433. // clear selection controller
  1434. return this.content.getFeature('DataPointSelections').clearAll().then(function () {
  1435. return _this8.content.getFeature('DataPointSelections.pending').clearAll();
  1436. }).then(function () {
  1437. // clear custom data selection
  1438. return _this8.clearCustomDataSelection();
  1439. });
  1440. };
  1441. VisEventHandler.prototype.clearCustomDataSelection = function clearCustomDataSelection(options) {
  1442. this._target.applyCustomDataSelection([], options);
  1443. };
  1444. /**
  1445. * Obtain the selection info object based on the event.
  1446. *
  1447. * @param {Object} event - Event object
  1448. * @param {Class} InfoClass - VisSelectionInfo (default) or VisTooltipInfo
  1449. */
  1450. VisEventHandler.prototype._getDataPayload = function _getDataPayload(items, InfoClass) {
  1451. var _this9 = this;
  1452. var VisInfoClass = InfoClass || VisSelectionInfo;
  1453. var selections = new VisInfoClass();
  1454. _.each(items, function (item, itemIdx) {
  1455. switch (item.type) {
  1456. case 'datapoint':
  1457. return _this9._processDataPointSelection(selections, item);
  1458. case 'item':
  1459. return _this9._processEdgeSelection(selections, item, itemIdx);
  1460. case 'customdata':
  1461. return _this9._processCustomDataSelection(selections, item);
  1462. default:
  1463. return;
  1464. }
  1465. });
  1466. this._processDecorationTooltips(selections, items);
  1467. return selections;
  1468. };
  1469. /**
  1470. * Display the selection tooltip.
  1471. */
  1472. VisEventHandler.prototype._showSelectionInfo = function _showSelectionInfo(oSelectionObj, event, includeApplyFilter, noFilters, drillOnly, noDrillthrough, options) {
  1473. var infoShown = false;
  1474. if (oSelectionObj && oSelectionObj.getCategorySelections()) {
  1475. this._visActionHelper.showDataPointActions(oSelectionObj, {
  1476. // Create fake bound information so that the tooltip shows up where the mouse is
  1477. 'bounds': this._getBoundsInfoFromEvent(event),
  1478. 'targetNode': event.currentTarget
  1479. }, includeApplyFilter, noFilters, drillOnly, noDrillthrough, options);
  1480. infoShown = true;
  1481. this.setEventLocalProperty(event, 'preventDefaultContextBar', true);
  1482. }
  1483. return infoShown;
  1484. };
  1485. /**
  1486. * Api method wrapper for #toggleLassoSelect
  1487. * @param {boolean} state
  1488. * @param {string} viewId
  1489. */
  1490. VisEventHandler.prototype.setLassoSelectState = function setLassoSelectState(state) {
  1491. var viewId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : LassoController.DEFAULT_VIEW_ID;
  1492. if (this.lassoCtrl.getCurrentViewId() && this.lassoCtrl.getCurrentViewId() !== viewId) {
  1493. this._endLassoSelection();
  1494. state = true;
  1495. }
  1496. return this.toggleLassoSelect(state, viewId);
  1497. };
  1498. /**
  1499. * Toggle the state of lasso mode
  1500. * @param {boolean} [state] - The final state of lasso mode for the Vis. True means
  1501. * switch on, false means switch off. When not provided, the current state is inverted.
  1502. */
  1503. VisEventHandler.prototype.toggleLassoSelect = function toggleLassoSelect(state, viewId) {
  1504. var enabled = arguments.length === 0 ? !this.lassoCtrl.isLassoMode() : !!state;
  1505. if (this.lassoCtrl.isLassoMode() !== enabled) {
  1506. if (enabled) {
  1507. this.lassoCtrl.activateLassoMode(true, viewId);
  1508. this.lassoCtrl.on('lassoSelect:done', this._handleLassoSelection, this);
  1509. this.lassoCtrl.on('lassoSelect:cordsChange', this._handleLassoCordChange, this);
  1510. this.lassoCtrl.on('lassoSelect:cancel', this._endLassoSelection, this);
  1511. } else {
  1512. this._endLassoSelection();
  1513. }
  1514. }
  1515. return enabled;
  1516. };
  1517. VisEventHandler.prototype.getLassoViewId = function getLassoViewId() {
  1518. return this.lassoCtrl.getCurrentViewId();
  1519. };
  1520. VisEventHandler.prototype._handleLassoSelection = function _handleLassoSelection(payload) {
  1521. try {
  1522. var items = [];
  1523. if (!_.isUndefined(payload.radius)) {
  1524. items = this._target && this._target.getEventTargets ? this._target.getEventTargets(payload.event, payload.radius) : [];
  1525. } else {
  1526. items = this._target && this._target.getTargetsByCords ? this._target.getTargetsByCords(payload.cords, /*sumarize*/false) : [];
  1527. }
  1528. if (items) {
  1529. var options = {
  1530. isMultiSelect: true
  1531. };
  1532. // iPad has no ctrl click, default is append always by design
  1533. // force ctrl click if selection was triggered by mobile end touch event
  1534. // https://github.ibm.com/BusinessAnalytics/WACA-UXDR/issues/2656
  1535. if (payload.event.type === 'touchend') {
  1536. options.forceCtrlClick = true;
  1537. }
  1538. this._handleHighlights(items);
  1539. this._handleSelections(payload.event, items, options);
  1540. }
  1541. } catch (e) {
  1542. this.logger.error(e);
  1543. }
  1544. };
  1545. VisEventHandler.prototype._handleLassoCordChange = function _handleLassoCordChange(payload) {
  1546. try {
  1547. var items = [];
  1548. if (!_.isUndefined(payload.radius)) {
  1549. items = this._target && this._target.getEventTargets ? this._target.getEventTargets(payload.event, payload.radius) : [];
  1550. } else {
  1551. items = this._target && this._target.getTargetsByCords ? this._target.getTargetsByCords(payload.cords, /*sumarize*/false) : [];
  1552. }
  1553. if (items) {
  1554. this._handleHighlights(items);
  1555. }
  1556. } catch (e) {
  1557. this.logger.error(e);
  1558. }
  1559. };
  1560. VisEventHandler.prototype._endLassoSelection = function _endLassoSelection() {
  1561. this.lassoCtrl.off('lassoSelect:done', this._handleLassoSelection, this);
  1562. this.lassoCtrl.off('lassoSelect:cordsChange', this._handleLassoCordChange, this);
  1563. this.lassoCtrl.off('lassoSelect:cancel', this._endLassoSelection, this);
  1564. this.lassoCtrl.activateLassoMode(false);
  1565. };
  1566. VisEventHandler.prototype.isLassoSelectActive = function isLassoSelectActive() {
  1567. return this.lassoCtrl.isLassoMode();
  1568. };
  1569. /**
  1570. * Api method wrapper for #isLassoSelectActive
  1571. */
  1572. VisEventHandler.prototype.getLassoSelectState = function getLassoSelectState() {
  1573. return this.isLassoSelectActive();
  1574. };
  1575. //Send a "visevent" to notify listeners (features etc.) that a visualization-specific event has occurred
  1576. //Eg: Supply information when the user is moving over the visualization or selecting a visualization element.
  1577. VisEventHandler.prototype._triggerWidgetEvent = function _triggerWidgetEvent(name, event, target, items, additionalPayloadItems) {
  1578. var payload = {
  1579. sender: this._widgetApi,
  1580. event: event,
  1581. target: target,
  1582. items: items
  1583. };
  1584. _.each(additionalPayloadItems, function (additionalPayloadItems, key) {
  1585. payload[key] = additionalPayloadItems;
  1586. });
  1587. this._ownerWidget.trigger(name, payload);
  1588. };
  1589. /**
  1590. * Set _stopHoverover flag.
  1591. * @param {Object} payload - indicate if the event is triggered by hover. e.g. {isHover: true}.
  1592. */
  1593. VisEventHandler.prototype.setPopoverClosed = function setPopoverClosed(payload) {
  1594. this._isHoverFlyoutShowing = false;
  1595. if (!payload || !payload.isHover) {
  1596. this._stopHoverover = false;
  1597. }
  1598. };
  1599. /**
  1600. * Set _stopHoverover flag. Stop hover when the close event is not triggered by hover.
  1601. * @param {Object} payload - indicate if the event is triggered by hover or widget ODT. e.g. {isHover: true}.
  1602. */
  1603. VisEventHandler.prototype.setPopoverOpened = function setPopoverOpened(payload) {
  1604. if (!payload || !payload.isHover) {
  1605. this._stopHoverover = true;
  1606. if (payload && payload.isWidgetOdt) {
  1607. this._stopHoverover = false;
  1608. }
  1609. }
  1610. };
  1611. VisEventHandler.prototype._getMappedSlotListByItem = function _getMappedSlotListByItem(item) {
  1612. if (item && item.datasetId) {
  1613. return SlotAPIHelper.getMappedSlotListByDataset(this.visualization, item.datasetId);
  1614. } else {
  1615. return this.visualization.getSlots().getMappedSlotList();
  1616. }
  1617. };
  1618. return VisEventHandler;
  1619. }();
  1620. /**
  1621. * Decorations supported by VisEventHandler
  1622. */
  1623. VisEventHandler.DECORATIONS = {
  1624. HIGHLIGHT: 'highlight',
  1625. SELECT: 'select',
  1626. TOOLTIP: 'tooltip'
  1627. };
  1628. return VisEventHandler;
  1629. });
  1630. //# sourceMappingURL=VisEventHandler.js.map