VIPRView.js 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934
  1. 'use strict';
  2. /**
  3. *+------------------------------------------------------------------------+
  4. *| Licensed Materials - Property of IBM
  5. *| IBM Cognos Products: Dashboard
  6. *| (C) Copyright IBM Corp. 2017, 2022
  7. *|
  8. *| US Government Users Restricted Rights - Use, duplication or disclosure
  9. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  10. *+------------------------------------------------------------------------+
  11. */
  12. /* global Blob FileReader */
  13. define(['jquery', 'underscore', './VIPREventTarget', '../VisView', '../VisEventHandler', 'dashboard-analytics/visualizations/vipr/VIPR', 'dashboard-analytics/visualizations/vipr/VIPRUtils', 'dashboard-analytics/visualizations/vipr/VIPRDataRequestHandler', 'dashboard-analytics/visualizations/vipr/VIPRCachedDataRequestHandler', 'dashboard-analytics/visualizations/vipr/properties/VIPRProperties', 'dashboard-analytics/visualizations/vipr/properties/ColorPropertiesCreator', 'dashboard-analytics/visualizations/vipr/VIPRConfig', '../../../lib/@waca/core-client/js/core-client/utils/BrowserUtils', '../../../widgets/livewidget/nls/StringResources', 'dashboard-analytics/visualizations/interactions/BinningActionsUtils', '../../../lib/@waca/core-client/js/core-client/utils/PerfUtils', '../../../widgets/livewidget/SdkShowError', 'react-dom', 'react', './components/CustomVisPreviewMessage', '../../../util/ContentUtil', 'dashboard-analytics/widgets/livewidget/util/VisUtil'], function ($, _, VIPREventTarget, VisView, VisEventHandler, VIPR, VIPRUtils, VIPRDataRequestHandler, VIPRCachedDataRequestHandler, VIPRProperties, ColorPropertiesCreator, VIPRConfig, BrowserUtils, stringResources, BinningActionsUtils, PerfUtils, SdkShowError, ReactDOM, React, CustomVisPreviewMessage, ContentUtil, VisUtil) {
  14. 'use strict';
  15. var DEFAULT_THUMBNAIL_PROPERTIES = {
  16. 'optimizeSize': true,
  17. 'gridLines.visible': false,
  18. 'markers.visible': false,
  19. 'widget.legend.size': 0,
  20. 'labels.visible': false,
  21. 'itemAxis.line.visible': false,
  22. 'valueAxis.line.visible': false,
  23. 'valueAxis.ticks.visible': false,
  24. 'itemAxis.ticks.visible': false,
  25. 'itemAxis.gridLines.visible': false,
  26. 'valueAxis.gridLines.visible': false
  27. };
  28. /**
  29. * List of ignored decorations when generating a thumbnails
  30. * @type {string[]}
  31. */
  32. var IGNORED_THUMBNAIL_DECORATIONS = [
  33. // TODO: right now livewidget does not know what vis-crosshairs is
  34. // we should probably contribute this list of decorations to be ignored from outside
  35. 'compareLine', // old vis-crosshairs - to be removed when the new crosshair feature flag is removed
  36. 'lines' // new vis-crosshairs
  37. ];
  38. var VIPRView = VisView.extend({
  39. initVizPromise: null,
  40. init: function init(options) {
  41. VIPRView.inherited('init', this, arguments);
  42. this.logger = options.logger;
  43. this.$el.attr('id', this.viewId);
  44. this.$el.addClass('dataview vipr-view');
  45. this.dashboard = options.dashboardApi;
  46. this.colorsService = this.dashboard.getFeature('Colors');
  47. this.visAPI = options.visModel;
  48. this.predictHandler = this._createPredictHandler(VIPRDataRequestHandler);
  49. this.highContrastEnabled = $(document.body).hasClass('highcontrast');
  50. this.content = options.content;
  51. this.visualization = this.content.getFeature('Visualization');
  52. this.internalVisDefinitions = this.dashboard.getFeature('VisDefinitions.internal');
  53. //Initialize members choosing which title to show (name/titleHtml vs annotation)
  54. if (this.visModel.getShowTitle()) {
  55. this._hasUserTitle = true;
  56. this._hasAnnotationTitle = false;
  57. }
  58. this.visController = {};
  59. this.viprDecorations = {};
  60. this.dataItemDecorations = {};
  61. //A list of widgets marked to be destroyed after the current viprWidget control render completes (part of a reRender)
  62. this._deferredDestroyViprWidgetsList = [];
  63. this.viprControlRenderInProgress = false;
  64. },
  65. /**
  66. * Setup the view and events based on the model
  67. * @override
  68. */
  69. createView: function createView() {
  70. VIPRView.inherited('createView', this, arguments);
  71. // Listen for theme changes
  72. this.visModel.on('change:theme', this.onChangeTheme, this);
  73. if (this._isSmartTitleEnabled()) {
  74. this.visModel.on('change:titleMode', this.onShowTitle, this);
  75. } else {
  76. this.visModel.on('change:showTitle', this.onShowTitle, this);
  77. }
  78. this.visModel.on('change:customData', this.onChangeCustomData, this);
  79. this._createVisTabs();
  80. },
  81. /**
  82. * Create a predict handler
  83. *
  84. * @param {Function} Class - class to use for the predict handler
  85. * @param {[type]} [handler] - original predict handler, if any; This is used for thumbnails for caching API requests
  86. *
  87. * @return {object} predict handler instance
  88. */
  89. _createPredictHandler: function _createPredictHandler(Class, handler) {
  90. var options = {
  91. visAPI: this.visAPI,
  92. visView: this,
  93. logger: this.logger
  94. };
  95. if (handler) {
  96. options.handler = handler;
  97. }
  98. return new Class(options);
  99. },
  100. /**
  101. *
  102. * @param event - payload for a customData model change event
  103. * event.prevValue - previous selections of custom data
  104. * event.value - current selections of custom data
  105. */
  106. onChangeCustomData: function onChangeCustomData(event) {
  107. var prevSelections = event.prevValue && event.prevValue.selected || [];
  108. var prevIds = prevSelections.map(function (decoration) {
  109. return decoration.id;
  110. });
  111. var prevSelectedCustomData = this.visAPI.getCustomData(prevIds);
  112. //clear decorations for previous selections;
  113. prevSelectedCustomData.forEach(function (item) {
  114. item.setDecoration && item.setDecoration('selected', false);
  115. });
  116. var curSelectedCustomData = this.visAPI.getDecoratedCustomData('selected');
  117. // set decorations for current selections;
  118. curSelectedCustomData.forEach(function (item) {
  119. item.setDecoration && item.setDecoration('selected', true);
  120. });
  121. return this.renderVIPRControl({ callRenderComplete: true });
  122. },
  123. /**
  124. * Create the visualization tabs if the definition require the tabs
  125. * The tabs definition consists with the following:
  126. * tabs : {
  127. * entries:[{
  128. * id: <unique identifier of the tab>,
  129. * resource: <resource key of the tab display label>
  130. * }]
  131. * default: <identifier of the default select tab entry>
  132. * }
  133. */
  134. _createVisTabs: function _createVisTabs() {
  135. var _this = this;
  136. if (this._tabs) {
  137. // ensure we start from scratch
  138. this._tabs.reset();
  139. // check the tabs definitions
  140. var definition = this.visModel.getDefinition();
  141. if (definition.tabs) {
  142. // create the tabs
  143. this._tabs.createTabs(_.map(definition.tabs.entries, function (tab) {
  144. return {
  145. id: tab.id,
  146. label: stringResources.get(tab.resource),
  147. onChange: function (tabId) {
  148. this.visModel.ownerWidget.updateVisProperties({
  149. id: 'actions',
  150. value: tabId
  151. });
  152. }.bind(_this)
  153. };
  154. }), this.visModel.getPropertyValue('actions') || definition.tabs.default);
  155. }
  156. // hide the tabs until necessary to show
  157. this._tabs.hide();
  158. }
  159. },
  160. /**
  161. * return a public API to a decorator for the nth vipr dataset (default dataset=0)
  162. * the decorator implements:
  163. * - decorate (decorate the dataset),
  164. * - decorateItem (decorate an item),
  165. * - decoratePoint(decorate a point)
  166. * - clearItemDecoration (clear a given item decoration)
  167. * All decoratorAPIs implement the same updateDecorations method to render the decorations.
  168. * Most visualizations have only 1 decoratorAPI (ie: 1 vipr dataset). Maps, for example have 3.
  169. * @param n - the nth decorator (dataset)....default 0
  170. * @returns a decoratorAPI for the whole decorator, items or points
  171. */
  172. getDecoratorAPI: function getDecoratorAPI(n) {
  173. var _this2 = this;
  174. var setDecorateItem = function setDecorateItem(itemIndex, decoration, value) {
  175. // Save the decoration so that they are applied when the decoration is refreshed
  176. // We are only saving the dataitem decorations
  177. // TODO: Do we need to save datapoints and dataset decorations ??
  178. if (!_this2.dataItemDecorations[n]) {
  179. _this2.dataItemDecorations[n] = {};
  180. }
  181. if (!_this2.dataItemDecorations[n][itemIndex]) {
  182. _this2.dataItemDecorations[n][itemIndex] = {};
  183. }
  184. var dataItemN = oDataSet.getDataItem(itemIndex);
  185. /**
  186. * decorationValue from viprData is usually the same as the value passed in EXCEPT FOR the 'lines' decoration.
  187. * The lines decoration returns an array of VIDA decoration instances that are the elements of the line that correspond to the value spec passed in . eg: { baseLine: {}, grabber: {}}
  188. */
  189. var decorationValue = dataItemN && dataItemN.decorate(decoration, value);
  190. _this2.dataItemDecorations[n][itemIndex][decoration] = decorationValue;
  191. return;
  192. };
  193. n = n || 0;
  194. if (!this.viprData || n > this.viprData.getDataSetCount() || !this._isViprWidgetValid()) {
  195. return null;
  196. }
  197. var oDataSet = this.viprData.getDataSetAt(n);
  198. if (oDataSet) {
  199. var datapoints = oDataSet.getDataPointIterator() && oDataSet.getDataPointIterator().datapoints;
  200. return {
  201. decorateItem: setDecorateItem,
  202. decoratePoint: function decoratePoint(row, decoration, value) {
  203. return datapoints && datapoints[row] && datapoints[row].decorate && datapoints[row].decorate(decoration, value);
  204. },
  205. decorate: function decorate(decoration, value) {
  206. return oDataSet.decorate(decoration, value);
  207. },
  208. clearItemDecoration: function clearItemDecoration(decoration) {
  209. if (_this2.dataItemDecorations[n]) {
  210. var dataItemIndex = void 0;
  211. for (dataItemIndex in _this2.dataItemDecorations[n]) {
  212. var dataItemN = oDataSet.getDataItem(dataItemIndex);
  213. if (dataItemN) {
  214. dataItemN.decorate(decoration, '');
  215. }
  216. delete _this2.dataItemDecorations[n][dataItemIndex][decoration];
  217. }
  218. }
  219. },
  220. updateDecorations: function updateDecorations() {
  221. return _this2.renderVIPRControl();
  222. }
  223. };
  224. }
  225. return null;
  226. },
  227. /**
  228. * return a public interface to all decorators in the visualization
  229. * (ie: one decoratorAPI per dataset as an array)
  230. * @returns an array of 0 or more getDecoratorAPIs
  231. */
  232. getDecoratorAPIs: function getDecoratorAPIs() {
  233. var decoratorAPIs = [];
  234. if (this.viprData && this.viprData.getDataSetCount) {
  235. for (var i = 0; i < this.viprData.getDataSetCount(); ++i) {
  236. var decoratorAPI = this.getDecoratorAPI(i);
  237. if (decoratorAPI) {
  238. decoratorAPIs.push(decoratorAPI);
  239. }
  240. }
  241. }
  242. return decoratorAPIs;
  243. },
  244. /**
  245. * @returns {boolean} true iff and only if this view supports annotations
  246. * The base view always returns false, the child view shoud override if different
  247. */
  248. supportsAnnotations: function supportsAnnotations() {
  249. return !this.doesVisPropertyMatchExpected('doesNotSupportAnnotations', true);
  250. },
  251. supportsForecasts: function supportsForecasts() {
  252. var forecastFeature = this.content && this.content.getFeature('Forecast');
  253. return forecastFeature && forecastFeature.supportsForecasts();
  254. },
  255. /**
  256. * Handle visualization definition change
  257. */
  258. onChangeDefinition: function onChangeDefinition() {
  259. this.initVizPromise = null;
  260. VIPRView.inherited('onChangeDefinition', this, arguments);
  261. //Clean Info Indicator and we update the indicator after Data Query is executed
  262. //for the new view.
  263. if (this.infoIndicator) {
  264. this.infoIndicator.reset();
  265. }
  266. //clean listener flag for vida prop changes
  267. if (this.propChangeslistener) {
  268. this.propChangeslistener = undefined;
  269. }
  270. // recreate the tabs for the new vistype
  271. this._createVisTabs();
  272. },
  273. /**
  274. * Handle removal of the View and/or its embedded viprWidget control.
  275. * @param finalRemove - (default) remove is 'final', the embedded viprWidget control is destroyed immediately
  276. * remove can also be called as part of a reRender (final=false). In this case, the embedded viprWidget is marked
  277. * to be destroyed after the current control render.
  278. * (the embedded control render is async and can't be destroyed mid-render)
  279. */
  280. remove: function remove() {
  281. var finalRemove = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  282. this.visModel.off('change:theme', this.onChangeTheme, this);
  283. if (this._isSmartTitleEnabled()) {
  284. this.visModel.off('change:titleMode', this.onShowTitle, this);
  285. } else {
  286. this.visModel.off('change:showTitle', this.onShowTitle, this);
  287. }
  288. this.visModel.off('change:customData', this.onChangeCustomData, this);
  289. this._cleanupVIPRWidget(finalRemove);
  290. // The super.destroy will clear all members of this class.
  291. // this is why we do it at the end
  292. VIPRView.inherited('remove', this, arguments);
  293. },
  294. /**
  295. * Clean up the VIPR widget and event handler
  296. * @param finalRemove - (default) remove is 'final', false - part of reRender (see remove)
  297. */
  298. _cleanupVIPRWidget: function _cleanupVIPRWidget() {
  299. var finalRemove = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  300. if (this.eventHandler) {
  301. this.eventHandler.remove();
  302. }
  303. if (this.$customVisPreviewMessage) {
  304. ReactDOM.unmountComponentAtNode(this.$customVisPreviewMessage[0]);
  305. this.$customVisPreviewMessage.remove();
  306. this.$customVisPreviewMessage = null;
  307. }
  308. this._destroyCustomVisShowError();
  309. if (this.viprWidget) {
  310. if (finalRemove && !this.viprControlRenderInProgress) {
  311. //Destroy immmediately
  312. this.viprWidget.destroy();
  313. this.viprWidget = null;
  314. } else if (this._deferredDestroyViprWidgetsList.indexOf(this.viprWidget) === -1) {
  315. //Set the viprWidget control to be destroyed at the end of control's async render.
  316. this._deferredDestroyViprWidgetsList.push(this.viprWidget);
  317. }
  318. }
  319. },
  320. _destroyCustomVisShowError: function _destroyCustomVisShowError() {
  321. if (this.sdkShowError) {
  322. this.sdkShowError.destroy();
  323. this.sdkShowError = null;
  324. }
  325. },
  326. /**
  327. * This function is called after the viprWidget render to destroy any viprWidget controls that were marked to be destroyed.
  328. */
  329. _deferredDestroyVIPRWidgets: function _deferredDestroyVIPRWidgets() {
  330. _.each(this._deferredDestroyViprWidgetsList, function (viprWidgetToDestroy) {
  331. viprWidgetToDestroy.destroy();
  332. });
  333. this._deferredDestroyViprWidgetsList = [];
  334. },
  335. /**
  336. * Create a VIPRWidget instance and event handler
  337. */
  338. _createVIPRWidget: function _createVIPRWidget() {
  339. var _this3 = this;
  340. if (!this.viprWidget) {
  341. // Create a VIPR container.
  342. // NOTE. VIPR will literally owns this container and will remove on viprWidget.destroy()
  343. var containerId = 'VIPR_' + this.viewId;
  344. this.$el.append($('<div id="' + containerId + '" style="width:100%; height:100%" role="application"></div>'));
  345. var cursors = VIPRUtils.getCursor(this.visAPI.getVisId());
  346. // The last supported cursor wins. For example, only -webkit-grab works
  347. // on chrome. This means that if cursors = ['-webkit-grab', 'grab', '-moz-grab'],
  348. // the style.cursor of the element will be set to '-webkit-grab'.
  349. if (cursors) {
  350. _.forEach(cursors, function (cursor) {
  351. _this3.$el.get(0).style.cursor = cursor;
  352. });
  353. }
  354. //If there is a passed in predictData during initilization, we will create a VIPRCachedDataRequestHandler that caches the predictData
  355. if (this.predictData) {
  356. this.predictHandler.setLastRequestData('Catalyst', this.predictData);
  357. this.predictHandler = this._createPredictHandler(VIPRCachedDataRequestHandler, this.predictHandler);
  358. }
  359. this.viprWidget = VIPR.createWidget(containerId, this.predictHandler);
  360. var userProfileService = this.dashboard.getGlassCoreSvc('.UserProfile');
  361. if (userProfileService) {
  362. this.viprWidget.formatLocale = userProfileService.preferences.contentLocale;
  363. }
  364. this.eventHandler = new VisEventHandler({
  365. target: new VIPREventTarget({
  366. $el: this.$el,
  367. viprWidget: this.viprWidget,
  368. visAPI: this.visAPI,
  369. visualization: this.visualization,
  370. content: this.content
  371. }),
  372. transaction: this.transactionApi,
  373. ownerWidget: this.ownerWidget,
  374. visAPI: this.visAPI,
  375. logger: this.logger,
  376. dashboard: this.dashboard
  377. });
  378. }
  379. },
  380. /**
  381. * Handle when visualization is ready
  382. */
  383. whenVisControlReady: function whenVisControlReady() {
  384. var _this4 = this;
  385. if (!this.initVizPromise) {
  386. this._createVIPRWidget();
  387. this.initVizPromise = this.viprWidget.newViz(this.visAPI.getVisId(), 'client').then(function (vizBundle) {
  388. // force to create a new vipr data
  389. _this4.viprData = null;
  390. _this4.vizBundle = vizBundle;
  391. return _this4.visController;
  392. }).catch(function (error) {
  393. //Remove this checking in R5 for Custom Vis, this is no longer needed
  394. if (_this4.visAPI.getVisId() === 'visualizationPreview') {
  395. _this4.logger.error(error, _this4);
  396. return _this4.visController;
  397. } else {
  398. throw error;
  399. }
  400. });
  401. }
  402. return this.initVizPromise;
  403. },
  404. /**
  405. * Create an instance of VIPR data from query data
  406. *
  407. * @param {object} data - query data
  408. *
  409. * @return {object} VIPR data
  410. */
  411. createViprData: function createViprData(data) {
  412. var viprData = data.getQueryResults ? VIPRUtils.createData(data.getQueryResults(), this.visualization, this.content) : VIPRUtils.createQueryResultData(data, this.visualization, this.content);
  413. viprData.hasMoreData = data.hasMoreData;
  414. viprData.queryThreshold = data.queryThreshold;
  415. return viprData;
  416. },
  417. /**
  418. * When there is a connection error we should not deal with preparing data anymore.
  419. */
  420. canRender: function canRender() {
  421. return this._hasMappedSlots() && this.isMappingComplete();
  422. },
  423. /**
  424. * Handle when data is ready
  425. */
  426. whenDataReady: function whenDataReady() {
  427. var _this5 = this;
  428. return VIPRView.inherited('whenDataReady', this, arguments).then(function (_ref) {
  429. var data = _ref.data,
  430. sameQueryData = _ref.sameQueryData;
  431. var result = void 0;
  432. if (_this5.canRender() && !_this5.hasUnavailableMetadataColumns() && !_this5.hasMissingFilters()) {
  433. // preserve the query results
  434. _this5._dataObject = data;
  435. if (sameQueryData) {
  436. result = {
  437. data: data,
  438. sameQueryData: sameQueryData
  439. };
  440. } else {
  441. _this5.predictHandler.resetCustomData();
  442. _this5._viprSlotMapping = VIPRUtils.createSlotMapping(_this5.visualization);
  443. result = {
  444. data: data
  445. };
  446. }
  447. } else {
  448. result = {
  449. data: {}
  450. };
  451. }
  452. return result;
  453. });
  454. },
  455. /**
  456. * Set a model property if its valid.
  457. * @param {String} propertyName - name of the property of interest.
  458. * @param {String} visId - id of the visualization of interest.
  459. */
  460. _setModelProperty: function _setModelProperty(propertyName, visId) {
  461. if (this._shouldPropertyBeApplied(propertyName)) {
  462. var val = this._getPropValueWhenSaving(visId, propertyName);
  463. var propInfo = {
  464. id: propertyName,
  465. value: val
  466. };
  467. this.setProperty(propInfo);
  468. }
  469. },
  470. /**
  471. * set properties needed before data is set.
  472. */
  473. _setPreDataProperties: function _setPreDataProperties() {
  474. var _this6 = this;
  475. // Check for such properties in the vipr config
  476. var visId = this.visAPI.getVisId();
  477. var config = VIPRConfig.getConfig(visId);
  478. if (config && config.propertiesToSetBeforeData && config.propertiesToSetBeforeData.length > 0) {
  479. config.propertiesToSetBeforeData.forEach(function (propertyName) {
  480. _this6._setModelProperty(propertyName, visId);
  481. });
  482. }
  483. },
  484. /**
  485. * handles when data is ready before setting
  486. * @param {Object} renderContext
  487. */
  488. whenSetDataReady: function whenSetDataReady(renderContext) {
  489. var result = Promise.resolve(true);
  490. if (this.canRender() && !this.hasUnavailableMetadataColumns() && !this.hasMissingFilters()) {
  491. var autoRefresh = !!(renderContext && renderContext.extraInfo && renderContext.extraInfo.queryRefresh);
  492. // we only care if its the same query IFF the query is an auto refresh query
  493. // otherwise the query is considered valid to construct a new VIPRData
  494. var sameQueryData = autoRefresh ? !!renderContext.sameQueryData : false;
  495. var requiresNewVIPRData = this.viprData ? !sameQueryData : true;
  496. if (requiresNewVIPRData) {
  497. this._isAnnotated = false;
  498. // Some properties, such as custom polygons, need to be set before data is set. Do so now.
  499. this._setPreDataProperties();
  500. // preserve the query results
  501. this._dataObject = renderContext.data;
  502. this._viprSlotMapping = VIPRUtils.createSlotMapping(this.visualization);
  503. this.viprData = this.createViprData(this._dataObject);
  504. if (this.viprData) {
  505. try {
  506. this.viprWidget.setData(this.viprData, this._viprSlotMapping);
  507. } catch (e) {
  508. result = Promise.reject(e);
  509. }
  510. } else {
  511. result = Promise.reject(new Error('Unable to create VIPR data in whenSetDataReady'));
  512. }
  513. }
  514. } else {
  515. //for cases that that we can render without complete mapping and there is no required slots like schematic, we need to check the slots,
  516. // if not data item is mapped, so we need to clear data
  517. var isMappingComplete = this.isMappingComplete() && this.visualization.getSlots().getMappingInfoList().length > 0;
  518. if (this.isRenderWithoutCompletingMapping() && !isMappingComplete) {
  519. this.viprWidget.setData(null);
  520. if (this.infoIndicator) {
  521. this.infoIndicator.reset();
  522. }
  523. }
  524. }
  525. return result;
  526. },
  527. _getAnnotationMessages: function _getAnnotationMessages(facetData) {
  528. return facetData.getMessages() || {};
  529. },
  530. whenAnnotatedResultsReady: function whenAnnotatedResultsReady() {
  531. var _this7 = this;
  532. return VIPRView.inherited('whenAnnotatedResultsReady', this, arguments).then(function (data) {
  533. if (data) {
  534. // preserve the result object which holds the annotation titles
  535. _this7._dataObject = data._aQueryResults && data._aQueryResults.length ? data : _this7._dataObject;
  536. if (!_.isEmpty(_this7.content.getFeature('Forecast').getForecastInfo().annotations)) {
  537. _this7.viprData = _this7.createViprData(_this7._dataObject);
  538. _this7.viprWidget.setData(_this7.viprData, _this7._viprSlotMapping);
  539. }
  540. // preserve the query results
  541. _this7._queryResults = data.getQueryResults();
  542. _this7._isAnnotated = true;
  543. _this7.visAPI.setAnnotationMessages(_this7._getAnnotationMessages(data));
  544. }
  545. return data;
  546. }).catch(function (e) {
  547. throw e;
  548. });
  549. },
  550. onShowTitle: function onShowTitle(event) {
  551. this._hasUserTitle = event.value !== 'noTitle';
  552. if (this._hasUserTitle) {
  553. this._hasAnnotationTitle = false;
  554. }
  555. },
  556. /**
  557. * VIPR view should use VIPR's built-in animations and not do the default animations.
  558. */
  559. // @Override
  560. animate: function animate() {},
  561. _readyForRender: function _readyForRender() {
  562. return (this.canRender() || this.isRenderWithoutCompletingMapping()) && !this.hasUnavailableMetadataColumns() && !this.hasMissingFilters();
  563. },
  564. _updateViprProp: function _updateViprProp(viprPropId, viprPropValue) {
  565. // we need to explicitly update property value so that dirty flag would be set and users will be aware.
  566. var options = {
  567. merge: true,
  568. remove: false,
  569. silent: false
  570. };
  571. if (viprPropId !== undefined && viprPropValue !== undefined) {
  572. this.visModel.ownerWidget.updateVisProperties({
  573. 'id': viprPropId,
  574. 'value': viprPropValue && viprPropValue.name ? viprPropValue.name : viprPropValue
  575. }, options);
  576. }
  577. },
  578. _onViprPropValueChange: function _onViprPropValueChange(viprProp) {
  579. var viprPropId = viprProp.property.getName();
  580. var viprPropValue = viprProp.property.getValue();
  581. /*
  582. * It seems like dashboard is storing the object structures when persisting length properties.
  583. * This will (e.g. for Length) return an object { value:15, unit:"px" }. However, if vida starts adding
  584. * internal variables on the object, these will unnecessarily end up in the serialization.
  585. * If we want to store property values in a spec, need to serialize them by calling 'Prop.toString()'.
  586. * This will yield e.g. "15px" for the above object.
  587. * They can then simply be reconstituted into objects by calling Length.parse("15px").
  588. * This applies to all complex properties, e.g. Color, Palettes, Length, Font etc.
  589. * NOTE: Have a discussion with Shawn, this is a temporary fix to have the minimum impact on the product,
  590. * need a generic fix in future
  591. */
  592. if (viprProp.property.type === 'length') {
  593. viprPropValue = viprPropValue ? viprPropValue.toString() : viprPropValue;
  594. }
  595. this._updateViprProp(viprPropId, viprPropValue);
  596. },
  597. _allowShowTabs: function _allowShowTabs() {
  598. return this.ownerWidget.allowShowTabs && this.ownerWidget.allowShowTabs();
  599. },
  600. _renderTabs: function _renderTabs() {
  601. // ensure the a tabs are visible with the selected tab
  602. if (this._tabs.getTabsCount() > 0 && this._allowShowTabs()) {
  603. this._tabs.show();
  604. this._tabs.selectTab(this.visModel.getPropertyValue('actions'));
  605. } else {
  606. this._tabs.hide();
  607. }
  608. },
  609. /**
  610. * Render the VIPR visualization
  611. */
  612. render: function render(renderInfo) {
  613. var _this8 = this;
  614. VIPRView.inherited('render', this, [renderInfo, /*callRenderComplete*/false]);
  615. this._destroyCustomVisShowError();
  616. if (!this.viprWidget) {
  617. return Promise.resolve();
  618. }
  619. if (this._renderCustomVisContext()) {
  620. renderInfo.widgetSize.height = this.$el.closest('.liveWidgetContent').height();
  621. }
  622. this.resizeToWidget(renderInfo);
  623. if (!this._readyForRender()) {
  624. return VisUtil.validateVisDefinition(this.content, this.dashboardApi, { visId: this.ownerWidget.model.visId }).then(function (isValid) {
  625. if (isValid) {
  626. _this8.renderIconView();
  627. } else {
  628. var $originalContentBeforeError = _this8.$el.children();
  629. $originalContentBeforeError.detach();
  630. _this8.sdkShowError = new SdkShowError(_this8.$el[0], stringResources.get('extVisNoSDKConnection'), stringResources.get('extVisNoSDKPreviewMsg'), 'disconnect');
  631. _this8.sdkShowError.showError();
  632. }
  633. });
  634. }
  635. this._renderTabs();
  636. this.removeIconView();
  637. //Listen for property value change if any, add a flag to prevent registering the same listener multiple times
  638. if (!this.propChangeslistener) {
  639. this._registerListenerForPropChanges();
  640. }
  641. return this._applySavedModelProperties(renderInfo).then(function () {
  642. if (!_this8.visModel.getRenderSequence().isActive()) {
  643. return;
  644. }
  645. var augmentations = _this8.visAPI.ownerWidget.model.augmentation; //TODO: add getAugmentations to visAPI
  646. if (augmentations && augmentations.length > 0) {
  647. for (var i = 0; i < augmentations.length; i++) {
  648. var augmentation = augmentations[i];
  649. _this8._appendDVI(augmentation);
  650. }
  651. }
  652. return _this8.renderSelected(renderInfo);
  653. });
  654. },
  655. /**
  656. * Render items that are specific to custom visualizations (ex. Custom Vis Preview Message)
  657. */
  658. _renderCustomVisContext: function _renderCustomVisContext() {
  659. if (this.ownerWidget.model.visId === 'visualizationPreview') {
  660. var iconsFeature = this.dashboard.getFeature('Icons');
  661. var $parent = $(this.$el.closest('.widgetContentWrapper'));
  662. if ($parent.find('.customVisPreviewMessage').length < 1) {
  663. this.$customVisPreviewMessage = $('<div>');
  664. this.$customVisPreviewMessage.addClass('customVisPreviewMessage');
  665. $parent.prepend(this.$customVisPreviewMessage);
  666. ReactDOM.render(React.createElement(CustomVisPreviewMessage, { iconsFeature: iconsFeature }), this.$customVisPreviewMessage[0]);
  667. }
  668. return true;
  669. }
  670. return false;
  671. },
  672. reveal: function reveal() {
  673. var _this9 = this;
  674. if (BrowserUtils.isIE11() || !this._readyForRender() || !this._getEntryDurationProperty() || !this.viprData) {
  675. this.visAPI.renderCompleteBeforeAnimation();
  676. return Promise.resolve();
  677. }
  678. // reveal is a render which triggers the widget's entry level animation.
  679. // This is done by clearing and resetting the data as there is no API for it atm.
  680. var emptyData = this.viprWidget.processData(this.viprData, this._viprSlotMapping).empty();
  681. this.viprWidget.setData(emptyData, this._viprSlotMapping);
  682. this._applyEntryDurationProperty('zero');
  683. return this.renderVIPRControl().then(function () {
  684. _this9._applyEntryDurationProperty('model');
  685. _this9.viprWidget.setData(_this9.viprData, _this9._viprSlotMapping);
  686. _this9.renderVIPRControl();
  687. return {
  688. // renderControlApi is a thenable object (has a then method),
  689. // but it's not a pure promise since it has other methods added by VIDA.
  690. // if we return it directly those api's get lost.
  691. renderControlApi: _this9.renderControlApi
  692. };
  693. }).catch(function (e) {
  694. _this9.viprWidget.setData(_this9.viprData, _this9._viprSlotMapping);
  695. throw e;
  696. });
  697. },
  698. getCurrentViewSelector: function getCurrentViewSelector() {
  699. return this.eventHandler;
  700. },
  701. /**
  702. * @private
  703. * TODO: SmartsExecution requests are using a legacy QueryResultsObject.
  704. * Annotations should be moved to a feature and updated with proper api's for decorations.
  705. * In the meantime, the response value indexes and decorations can be accessed via the "pt" array and "deco" member.
  706. * @param {Object} value - datapoint value
  707. * @return {String} unique string representing the datapoint
  708. */
  709. _getDatapointKeyFromSmartAnnotationsResult: function _getDatapointKeyFromSmartAnnotationsResult(value) {
  710. // generate a unique key that consists of the category indices
  711. // without the ordinal values
  712. // INPUT: [2, 1, {v: 886.970000016}]
  713. // OUTPUT: '2,1'
  714. return value ? _.filter(value.pt, function (pt) {
  715. return typeof pt === 'number';
  716. }).toString() : '';
  717. },
  718. _decorateDatapoints: function _decorateDatapoints(dataset, datasetIndex) {
  719. var it = dataset.getDataPointIterator();
  720. var selection = this.getSelector().getSelection(ContentUtil.getColumnIdList(dataset.slots || this.visualization.getSlots().getMappedSlotList(), 'attribute'));
  721. var queryResult = this._isAnnotated ? this._queryResults[datasetIndex] : null;
  722. var facetData = queryResult ? queryResult.getFacetData() : null;
  723. var annotatedDatapoints = facetData ? facetData.getDatapoints() : null;
  724. var nextValue = it.nextValue();
  725. var index = 0;
  726. while (nextValue !== null) {
  727. if (nextValue.decorate && nextValue.hasDecoration) {
  728. if (annotatedDatapoints && annotatedDatapoints[index] &&
  729. // When dashboard submits a stats query for smart annotations,
  730. // certain rows may be removed when attempting to calculate using columns with no values.
  731. // As a result the stats query (and SA execution query) may have less rows compared to the main data query.
  732. // This code ensures they match.
  733. nextValue.getDataPointKey() === this._getDatapointKeyFromSmartAnnotationsResult(annotatedDatapoints[index])) {
  734. var decorations = annotatedDatapoints[index++].deco;
  735. if (decorations !== undefined) {
  736. _.each(decorations, function (value, key) {
  737. nextValue.decorate(key, value);
  738. });
  739. } else {
  740. nextValue.clearDecorations();
  741. }
  742. } else {
  743. nextValue.clearDecorations();
  744. }
  745. // Decorate only if needed. Avoid re-decorating with the same decorations.
  746. if (selection && selection.isSelected(it.getTupleItems())) {
  747. nextValue.decorate('selected', true);
  748. } else if (nextValue.hasDecoration('selected')) {
  749. nextValue.decorate('selected', false);
  750. }
  751. }
  752. nextValue = it.nextValue();
  753. }
  754. return !!selection;
  755. },
  756. _decorateDataItems: function _decorateDataItems(dataset, datasetIndex) {
  757. var _this10 = this;
  758. var decorated = false;
  759. var queryResult = this._isAnnotated ? this._queryResults[datasetIndex] : null;
  760. var annotatedData = queryResult ? queryResult.getFacetData() : null;
  761. var _loop = function _loop(iDataItem) {
  762. var dataItem = dataset.getDataItem(iDataItem);
  763. // decorate annotations
  764. if (annotatedData) {
  765. var annotatedDataItem = annotatedData.getResultDataItem(iDataItem);
  766. if (annotatedDataItem) {
  767. var decoration = annotatedDataItem.getDecoration();
  768. if (_.isEmpty(decoration)) {
  769. dataItem.clearDecorations();
  770. } else {
  771. _.each(decoration, function (value, key) {
  772. dataItem.decorate(key, value);
  773. });
  774. }
  775. }
  776. } else {
  777. dataItem.clearDecorations();
  778. }
  779. // Maintain any decoration that were added using the widget decorator API
  780. if (_this10.dataItemDecorations[datasetIndex] && _this10.dataItemDecorations[datasetIndex][iDataItem]) {
  781. var dataItemDecorations = _this10.dataItemDecorations[datasetIndex][iDataItem];
  782. var decoName = void 0;
  783. for (decoName in dataItemDecorations) {
  784. if (dataItemDecorations[decoName] !== null && dataItemDecorations[decoName] !== undefined) {
  785. dataItem.decorate(decoName, dataItemDecorations[decoName]);
  786. }
  787. }
  788. }
  789. // decorate selection
  790. if (dataItem.getType() === 'cat') {
  791. (function () {
  792. // collect the ItemIds (single or nested)
  793. var itemIds = [];
  794. var aItemClassSet = dataItem.getItemClassSet();
  795. for (var iItemClass = 0; iItemClass < aItemClassSet.getItemClassCount(); iItemClass++) {
  796. itemIds.push(aItemClassSet.getItemClass(iItemClass).getUniqueName());
  797. }
  798. var selection = _this10.getSelector().getSelection(itemIds);
  799. var selectedVIPRItem = {};
  800. var allVIPRItem = {};
  801. for (var iTuple = 0; iTuple < dataItem.getTupleCount(); iTuple++) {
  802. var tuple = dataItem.getTuple(iTuple);
  803. tuple.items.forEach(function (VIPRItem) {
  804. return allVIPRItem[VIPRItem.getUniqueName()] = VIPRItem;
  805. });
  806. var tupleItems = [];
  807. for (var iTupleItem = 0; iTupleItem < tuple.getItemCount(); iTupleItem++) {
  808. tupleItems.push(tuple.getItem(iTupleItem).item);
  809. }
  810. // unlike the datapoint decorations, each legend items need to be explictly selected/unselected
  811. if (selection) {
  812. var isTupleSelected = !!selection.isSelected(tupleItems);
  813. tuple.decorate('selected', isTupleSelected);
  814. isTupleSelected && tuple.items.forEach(function (VIPRItem) {
  815. selectedVIPRItem[VIPRItem.getUniqueName()] = VIPRItem;
  816. });
  817. decorated = true;
  818. } else {
  819. tuple.decorate('selected', false);
  820. tuple.items.forEach(function (VIPRItem) {
  821. VIPRItem.decorate('selected', false);
  822. });
  823. }
  824. }
  825. // handle VIPRItem selection
  826. Object.values(selectedVIPRItem).forEach(function (viprItem) {
  827. return viprItem.decorate('selected', true);
  828. });
  829. Object.keys(allVIPRItem).filter(function (key) {
  830. return !selectedVIPRItem[key];
  831. }).forEach(function (itemKey) {
  832. allVIPRItem[itemKey].decorate('selected', false);
  833. });
  834. })();
  835. }
  836. };
  837. for (var iDataItem = 0; iDataItem < dataset.getDataItemCount(); iDataItem++) {
  838. _loop(iDataItem);
  839. }
  840. return decorated;
  841. },
  842. decorateData: function decorateData(viprData) {
  843. var decorations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
  844. dataPoints: true,
  845. dataItems: true,
  846. selection: true,
  847. annotations: true
  848. };
  849. var dataset = void 0;
  850. for (var i = 0; i < viprData.getDataSetCount(); i++) {
  851. dataset = viprData.getDataSetAt(i);
  852. if (dataset) {
  853. var dataItemsDecorated = false;
  854. if (decorations.dataItems) {
  855. dataItemsDecorated = this._decorateDataItems(dataset, i);
  856. }
  857. var datapointsDecorated = false;
  858. if (decorations.dataPoints) {
  859. datapointsDecorated = this._decorateDatapoints(dataset, i);
  860. }
  861. if (decorations.selection) {
  862. // The hasSelection decoration tells the visualization if there is any selection in play, and changes
  863. // how items are rendered by default.
  864. dataset.decorate('hasSelection', datapointsDecorated || dataItemsDecorated);
  865. }
  866. if (decorations.annotations) {
  867. // Check for annotation type
  868. var meaningfulDiff = _.where(this.visAPI.getEnabledAnnotations(), { type: 'MEANINGFUL_DIFFERENCES' });
  869. dataset.decorate('hasAnnotations', !!meaningfulDiff.length);
  870. }
  871. }
  872. }
  873. },
  874. renderSelected: function renderSelected(renderInfo) {
  875. var _this11 = this;
  876. if (!this.visModel.getRenderSequence().isActive()) {
  877. return Promise.resolve();
  878. }
  879. if (this.viprData) {
  880. this.decorateData(this.viprData);
  881. }
  882. // restore the visualization state
  883. if (this.eventHandler) {
  884. this.eventHandler.restoreState();
  885. }
  886. var perfMarkName = 'WidgetRender_' + this.visModel.getWidgetId();
  887. PerfUtils.createPerformanceMark({
  888. 'component': 'dashboard',
  889. 'name': perfMarkName,
  890. 'state': 'start'
  891. });
  892. return this.renderVIPRControl({ renderInfo: renderInfo, callRenderComplete: true }).then(function () {
  893. PerfUtils.createPerformanceMark({
  894. 'component': 'dashboard',
  895. 'name': perfMarkName,
  896. 'state': 'end'
  897. });
  898. if (!_this11.visModel.getRenderSequence().isActive()) {
  899. return;
  900. }
  901. });
  902. },
  903. renderVIPRControl: function renderVIPRControl() {
  904. var _this12 = this;
  905. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { callRenderComplete: false };
  906. var renderInfo = options.renderInfo,
  907. callRenderComplete = options.callRenderComplete;
  908. // complete the previous render if it's still running.
  909. if (this.renderControlApi && this.renderControlApi.complete) {
  910. this.renderControlApi.complete();
  911. }
  912. this.viprControlRenderInProgress = true;
  913. this.renderControlApi = this.viprWidget.render('client');
  914. this.renderControlApi.onprogress = function (_message) {
  915. if (_message.status === 'animating') {
  916. _this12.visAPI.renderCompleteBeforeAnimation();
  917. }
  918. };
  919. return this.renderControlApi.then(function () {
  920. callRenderComplete && _this12.visAPI.renderComplete(renderInfo);
  921. _this12._deferredDestroyVIPRWidgets();
  922. _this12.viprControlRenderInProgress = false;
  923. }).catch(function (e) {
  924. throw e;
  925. });
  926. },
  927. /**
  928. * check if the value of a property matched expected
  929. * @param {String} propertyName
  930. * @param {object} expectedValue
  931. * @return {boolean} true if it matches
  932. */
  933. doesVisPropertyMatchExpected: function doesVisPropertyMatchExpected(propertyName, expectedValue) {
  934. if (propertyName && this.viprWidget) {
  935. return VIPRUtils.doesConfigPropertyMatchExpected(this.visualization.getDefinition().getId(), propertyName, expectedValue);
  936. }
  937. return false;
  938. },
  939. /**
  940. * check if auto binning is set for this view.
  941. * @return {boolean} true if anto binning can be appied for this view
  942. */
  943. canApplyAutoBin: function canApplyAutoBin() {
  944. var doesConfigSupportAutobinning = VIPRUtils.canApplyAutoBin(this.visualization.getDefinition().getId());
  945. var definition = this.visualization.getDefinition();
  946. var slots = this.visualization.getSlots().getMappedSlotList();
  947. var slotOneRole = 'explanatory';
  948. var colorSlotRole = 'group';
  949. var doesWidgetHaveBinnableDataItem = false;
  950. if (definition.getProperty('canApplyBinning')) {
  951. _.find(slots, function (slot) {
  952. var role = slot.getDefinition().getRole();
  953. if (slot.getDefinition().getType() !== 'ordinal' && (role === slotOneRole || role === colorSlotRole)) {
  954. var fact = slot.getDataItemList().find(function (dataItem) {
  955. return dataItem.getMetadataColumn().getType() === 'fact';
  956. });
  957. doesWidgetHaveBinnableDataItem = !!fact;
  958. return doesWidgetHaveBinnableDataItem;
  959. }
  960. });
  961. }
  962. return doesConfigSupportAutobinning && doesWidgetHaveBinnableDataItem;
  963. },
  964. /**
  965. * @returns the default binning config for this widget.
  966. */
  967. getBinningConfig: function getBinningConfig() {
  968. return VIPRUtils.getBinning(this.visualization.getDefinition().getId());
  969. },
  970. /**
  971. * @returns the default palette from the colorsService
  972. */
  973. _getDefaultContinuousPaletteName: function _getDefaultContinuousPaletteName() {
  974. return this.colorsService.getDefaultPaletteName('HeatPalette');
  975. },
  976. /**
  977. * @returns the default palette from the colorsSerivce
  978. */
  979. _getDefaultCategoricalPaletteName: function _getDefaultCategoricalPaletteName() {
  980. return this.colorsService.getDefaultPaletteName('ColorPalette');
  981. },
  982. /**
  983. * @param palette - palette property item describing a specific vipr palette
  984. * @param possibleDataSlots - all possible data slots for the current vis type.
  985. * @returns a continuous heat palette description needed to set a palette resolver in VIPR
  986. * eg.
  987. * {
  988. * type: "cont"
  989. * colors: description of colors (either continuous or categorical)
  990. * defaultIndex: index into the palette for an element when the color by slot is empty.
  991. * }
  992. */
  993. _getContinuousColorPaletteDesc: function _getContinuousColorPaletteDesc(viprPalette, possibleDataSlots) {
  994. var _this13 = this;
  995. // Get either the overriden palette or the default palette
  996. var colorPropsCreatorInstance = ColorPropertiesCreator.getInstance();
  997. var dataLayerId = colorPropsCreatorInstance.getDataLayerIdFromPaletteAndSlots(viprPalette, possibleDataSlots);
  998. var propertyName = colorPropsCreatorInstance.getContinuousColorPalettePropertyNameWithLayer(dataLayerId);
  999. var paletteName = this.visModel.getPropertyValue(propertyName) || this._getDefaultContinuousPaletteName();
  1000. return this.colorsService.getPalette({
  1001. paletteId: paletteName,
  1002. type: 'HeatPalette'
  1003. }).then(function (palette) {
  1004. var paletteDef = {
  1005. type: ''
  1006. };
  1007. if (palette) {
  1008. paletteDef.type = 'cont';
  1009. paletteDef.dataLayerId = dataLayerId;
  1010. var colors = [];
  1011. /* VIPR had an original issue with the typical way we express our color
  1012. * stops. We could wait for their fix (its on its way) or work around it.
  1013. * This is the work around. We want to change our stops to return in this
  1014. * format:
  1015. * ["color %", "color %", ...]
  1016. */
  1017. // Order the colors depending on the heat scale color order property.
  1018. var heatScalePropId = colorPropsCreatorInstance.getHeatScalePalettePropertyNameWithLayer(dataLayerId);
  1019. var colorOrder = _this13.visModel.getPropertyValue(heatScalePropId);
  1020. var paletteFills = palette.fills;
  1021. var paletteLength = paletteFills.length;
  1022. for (var index = 0; index < paletteLength; index++) {
  1023. // If the colorOrder is dark to light then reverse the colors.
  1024. var color = colorOrder !== 'DarkerForLowerValue' ? paletteFills[index].fill : paletteFills[paletteLength - index - 1].fill;
  1025. var at = paletteFills[index].at;
  1026. var colorStr = color + ' ' + String(at * 100) + '%';
  1027. colors.push(colorStr);
  1028. }
  1029. paletteDef.colors = colors;
  1030. }
  1031. return paletteDef;
  1032. });
  1033. },
  1034. /**
  1035. * @param {Object} palette - viprWidget palette
  1036. * @returns secondary color index is needed, undefined otherwise.
  1037. */
  1038. _getSecondaryColorIndexForCatColorPalettes: function _getSecondaryColorIndexForCatColorPalettes(palette) {
  1039. var defaultSecondaryColor = void 0;
  1040. var secondaryColorProp = void 0;
  1041. var singlePaletteProps = VIPRUtils.getSinglePaletteProperties(this.visAPI.getVisId());
  1042. if (singlePaletteProps) {
  1043. Object.values(singlePaletteProps).forEach(function (propDesc) {
  1044. if (propDesc.defaultColorIndex === 1) {
  1045. secondaryColorProp = propDesc;
  1046. }
  1047. });
  1048. }
  1049. if (secondaryColorProp) {
  1050. var secondaryValue = this.visModel.getPropertyValue(secondaryColorProp.id);
  1051. defaultSecondaryColor = secondaryValue !== null ? secondaryValue : 1;
  1052. // Ensure defaultIndex is not above the number of colors in the current palette
  1053. defaultSecondaryColor = defaultSecondaryColor < palette.fills.length ? defaultSecondaryColor : 1;
  1054. }
  1055. return defaultSecondaryColor;
  1056. },
  1057. /**
  1058. * @param {Object} palette - viprWidget palette
  1059. * @returns {Object} primary and secondary color index
  1060. */
  1061. _getColorIndicesForCatColorPalettes: function _getColorIndicesForCatColorPalettes(palette, propertyName) {
  1062. var defaultIndex = this.visModel.getPropertyValue('defaultPaletteIndex') || this.visModel.getPropertyValue(propertyName + '_defaultIndex') || 0;
  1063. // Ensure defaultIndex is not above the number of colors in the current palette
  1064. defaultIndex = defaultIndex < palette.fills.length ? defaultIndex : 0;
  1065. var defaultSecondaryColor = this._getSecondaryColorIndexForCatColorPalettes(palette);
  1066. return {
  1067. defaultIndex: defaultIndex,
  1068. secondaryIndex: defaultSecondaryColor
  1069. };
  1070. },
  1071. /**
  1072. * @param viprPalette - viprWidget.palettes item describing a specific vipr palette
  1073. * @param possibleDataSlots - all possible data slots for the current vis type.
  1074. * @returns a categorical palette description needed to set a palette resolver in VIPR
  1075. * eg.
  1076. * {
  1077. * type: "cat"
  1078. * colors: description of colors (either continuous or categorical)
  1079. * defaultIndex: index into the palette for an element when the color by slot is empty.
  1080. * }
  1081. */
  1082. _getCategoricalColorPaletteDesc: function _getCategoricalColorPaletteDesc(viprPalette, possibleDataSlots) {
  1083. var _this14 = this;
  1084. // Get either the overriden palette or the default palette
  1085. var colorPropsCreatorInstance = ColorPropertiesCreator.getInstance();
  1086. var dataLayerId = colorPropsCreatorInstance.getDataLayerIdFromPaletteAndSlots(viprPalette, possibleDataSlots);
  1087. var propertyName = colorPropsCreatorInstance._getCategoricalColorPalettePropertyNameWithLayer(dataLayerId);
  1088. var paletteName = this.visModel.getPropertyValue(propertyName) || this._getDefaultCategoricalPaletteName();
  1089. return this.colorsService.getPalette({
  1090. paletteId: paletteName,
  1091. type: 'ColorPalette'
  1092. }).then(function (palette) {
  1093. var paletteDef = {
  1094. type: '',
  1095. colors: ''
  1096. };
  1097. var colorIndices = _this14._getColorIndicesForCatColorPalettes(palette, propertyName);
  1098. if (palette) {
  1099. paletteDef.type = 'cat';
  1100. paletteDef.colors = palette.fills;
  1101. paletteDef.defaultIndex = colorIndices.defaultIndex;
  1102. paletteDef.secondaryColorIndex = colorIndices.secondaryIndex;
  1103. }
  1104. return paletteDef;
  1105. });
  1106. },
  1107. /**
  1108. * @param viprPalette - viprWidget.palettes item describing a specific vipr palette
  1109. * @param possibleDataSlots - all possible data slots for the current vis type.
  1110. * @returns a palette description needed to set a palette resolver in VIPR
  1111. * eg.
  1112. * {
  1113. * type: "" // cat or cont
  1114. * colors: description of colors (either continuous or categorical)
  1115. * defaultIndex: index into the palette for an element when the color by slot is empty. This is only supplied for categorical palettes.
  1116. * }
  1117. */
  1118. _getPaletteDescForPalette: function _getPaletteDescForPalette(viprPalette, possibleDataSlots) {
  1119. var getColorPaletteDesc = void 0;
  1120. switch (viprPalette.paletteType) {
  1121. case 'cont':
  1122. case 'customcont':
  1123. getColorPaletteDesc = this._getContinuousColorPaletteDesc.bind(this);
  1124. break;
  1125. case 'cat':
  1126. case 'single':
  1127. case 'customcat':
  1128. getColorPaletteDesc = this._getCategoricalColorPaletteDesc.bind(this);
  1129. break;
  1130. default:
  1131. getColorPaletteDesc = null;
  1132. }
  1133. return getColorPaletteDesc ? getColorPaletteDesc(viprPalette, possibleDataSlots).then(function (desc) {
  1134. desc.type = viprPalette.paletteType;
  1135. return desc;
  1136. }) : Promise.resolve({});
  1137. },
  1138. _getEntryDurationProperty: function _getEntryDurationProperty() {
  1139. var name = null;
  1140. var configuration = VIPRConfig.getConfig(this.visAPI.getVisId());
  1141. if (configuration && configuration.entryDurationProperty) {
  1142. name = configuration.entryDurationProperty;
  1143. } else if (this.viprWidget.properties.get('effect.duration')) {
  1144. var val = VIPRUtils.getOverridenDefaultForProperty(this.visAPI.getVisId(), 'effect.duration').defaultValue;
  1145. if (val !== null && val >= 0) {
  1146. // backward compatible value, if we actually have a value to set (I.e defaultValue is configured)
  1147. name = 'effect.duration';
  1148. }
  1149. }
  1150. return name;
  1151. },
  1152. _isDurationPropertyValuePropValid: function _isDurationPropertyValuePropValid(value) {
  1153. return !(value === undefined || value < 0);
  1154. },
  1155. _applyEntryDurationProperty: function _applyEntryDurationProperty(durationOverwrite) {
  1156. var propertyName = this._getEntryDurationProperty();
  1157. if (!propertyName) {
  1158. return;
  1159. }
  1160. /*
  1161. * 3 possible values for the duration:
  1162. * 1) zero - set the value to 0 so there is no animation
  1163. * 2) model - ask the model for the value to use. If the user has set a value
  1164. * then it will be used.
  1165. * 3) if value is still undefined, check our local config for overrides.
  1166. *
  1167. * zero is a special case where we set all the animations values to zero.
  1168. * for now this only includes effect.duration.
  1169. *
  1170. */
  1171. var value = void 0;
  1172. var effectValue = VIPRUtils.getOverridenDefaultForProperty(this.visAPI.getVisId(), 'effect.duration').defaultValue || 0;
  1173. if (durationOverwrite === 'zero') {
  1174. value = 0;
  1175. effectValue = 0;
  1176. } else if (durationOverwrite === 'model') {
  1177. value = this.visModel.getPropertyValue(propertyName);
  1178. }
  1179. //default (and if model has no value) - check for config override.
  1180. if (!this._isDurationPropertyValuePropValid(value)) {
  1181. value = VIPRUtils.getOverridenDefaultForProperty(this.visAPI.getVisId(), propertyName).defaultValue;
  1182. }
  1183. // If we still don't have a value, forget it, we'll use the default.
  1184. if (this._isDurationPropertyValuePropValid(value)) {
  1185. this.setProperty({ id: 'effect.duration', value: effectValue });
  1186. this.setProperty({ id: propertyName, value: value });
  1187. }
  1188. },
  1189. /**
  1190. * Single palettes are handled differently than categorical or continuous
  1191. * For one, there is always two of them. Secondly, both the single palette
  1192. * resolvers must use the same categorical palette (or at least same colors)
  1193. */
  1194. _applySavedSingleColorPalette: function _applySavedSingleColorPalette() {
  1195. var _this15 = this;
  1196. // Create the categorical palette resolver needed for the single palette.
  1197. return this._getCategoricalColorPaletteDesc().then(function (catPaletteDesc) {
  1198. return VIPRProperties.getInstance().setSinglePaletteResolvers(_this15.viprWidget, catPaletteDesc);
  1199. });
  1200. },
  1201. /**
  1202. * VIPR has some properties in its bundles that are handled in a different way.
  1203. * We have to protect against setting them using the properties API as there
  1204. * could be unexpected side affects.
  1205. * @param property - specific vipr defined property in question
  1206. * @returns true iff the property should be applied
  1207. * @// TODO: replace this list with dontApply: true in the VIPR config
  1208. */
  1209. _shouldPropertyBeApplied: function _shouldPropertyBeApplied(propertyName) {
  1210. var blackList = ['legend.display', 'legend.position', 'effect.duration', 'effect.entry.line.duration', 'effect.entry.bar.duration'];
  1211. blackList = blackList.concat(this._getDontApplyProperties());
  1212. return !(blackList.indexOf(propertyName) !== -1);
  1213. },
  1214. _getDontApplyProperties: function _getDontApplyProperties() {
  1215. var dontApplyProperties = [];
  1216. //Since the VIDA 2.10 change, VIDA is now treating color palettes like properties.
  1217. //They are now included as part of the VIPRWidget properties.
  1218. //Therefore, we dont want to override the palettes with the default value
  1219. //Add them to the list of dontApplyProperties
  1220. var colorPalettes = VIPRUtils.getPalettes(this.viprWidget.properties, this.visualization.getDefinition().getId());
  1221. colorPalettes.forEach(function (palette) {
  1222. if (palette.name !== 'colors.series') {
  1223. //colors.series is marked in VIPRConfig to not set the default value
  1224. dontApplyProperties.push(palette.name);
  1225. }
  1226. });
  1227. return dontApplyProperties;
  1228. },
  1229. /**
  1230. * Set the palette resolvers for the categorical and continuous palettes.
  1231. */
  1232. _applySavedNonSingleColorPalette: function _applySavedNonSingleColorPalette() {
  1233. var _this16 = this;
  1234. var promises = [];
  1235. // Only apply the palettes associated with the current visualization.
  1236. var possibleDataSlots = this.visualization.getSlots().getSlotList();
  1237. VIPRUtils.getPalettes(this.viprWidget.properties, this.visualization.getDefinition().getId()).forEach(function (palette) {
  1238. promises.push(_this16._getPaletteDescForPalette(palette, possibleDataSlots).then(function (paletteDef) {
  1239. // Make sure there is avalid defintion for the palette type.
  1240. if (paletteDef) {
  1241. VIPRProperties.getInstance().setPaletteResolvers(palette, paletteDef, possibleDataSlots, _this16.visAPI.getFredIsRed());
  1242. }
  1243. return paletteDef;
  1244. }));
  1245. });
  1246. return Promise.all(promises);
  1247. },
  1248. /**
  1249. * Apply all palette properties relevant to the current visualization
  1250. */
  1251. _applySavedColorPalette: function _applySavedColorPalette() {
  1252. var isThereSinglePalettes = VIPRUtils.getSinglePalettes(this.viprWidget.properties, this.visualization.getDefinition().getId()).length > 0;
  1253. if (isThereSinglePalettes) {
  1254. return this._applySavedSingleColorPalette();
  1255. } else {
  1256. return this._applySavedNonSingleColorPalette();
  1257. }
  1258. },
  1259. /**
  1260. * VIPR will optimize the size of a visualization when told (i.e. remove axis labels
  1261. * when it thinks more space should be given to the visual elements). We want
  1262. * to enable this be default or if we are showing small multiples. It should
  1263. * only be disabled for upgraded content.
  1264. */
  1265. _setOptimizedSizeProperty: function _setOptimizedSizeProperty(visId) {
  1266. var propertyId = 'optimizeSize';
  1267. var defaultValue = this._getPropValueWhenSaving(visId, propertyId);
  1268. if (!defaultValue) {
  1269. // Do we have small multiple mapped slots?
  1270. var aMultipliers = _.filter(this.visualization.getSlots().getMappedSlotList(), function (dataSlot) {
  1271. return dataSlot.getDefinition().getProperty('multiplier') === true;
  1272. });
  1273. // If we have small multiple mapped slots then lets optimize.
  1274. if (aMultipliers && aMultipliers.length > 0 || this.visAPI.isOptimizeForSize()) {
  1275. defaultValue = true;
  1276. }
  1277. }
  1278. var propInfo = {
  1279. id: propertyId,
  1280. value: defaultValue === undefined || defaultValue === null ? true : defaultValue // true by default
  1281. };
  1282. this.setProperty(propInfo);
  1283. },
  1284. /**
  1285. * @return the default background color in hex
  1286. */
  1287. _getDefaultBackgroundColorInHex: function _getDefaultBackgroundColorInHex() {
  1288. var defaultSpecColor = this.colorsService.getPropertyForUIElement('widget', 'backgroundColor').value;
  1289. // The value may be equal to a simple hex or variable name or it may be an object which we have to dig into a little more.
  1290. if (_.isObject(defaultSpecColor)) {
  1291. defaultSpecColor = defaultSpecColor.color;
  1292. }
  1293. // I love themes and the theme definition object <insert sarcasm smirk here>. The color may come back
  1294. // as a nice hex value or as a variable that needs to be mapped. If its a variable it will begin with
  1295. // a '$' and we have to map it to get the hex value.
  1296. if (defaultSpecColor.substring(0, 1) === '$') {
  1297. defaultSpecColor = this.colorsService.getValueForVariable('Color', defaultSpecColor.substr(1));
  1298. }
  1299. // Ensure we have a valid hex value or transparent
  1300. if (defaultSpecColor.substring(0, 1) === '#' && !isNaN(parseInt(defaultSpecColor.substr(1), 16)) || defaultSpecColor === 'transparent') {
  1301. return defaultSpecColor;
  1302. }
  1303. return null;
  1304. },
  1305. /**
  1306. * Set the background color of the viprwidget
  1307. */
  1308. _setBackgroundColor: function _setBackgroundColor() {
  1309. var _this17 = this;
  1310. if (this.highContrastEnabled) {
  1311. //Clear background and foreground element colors in high-contrast mode and allow idvis to determine them.
  1312. this.setProperty({
  1313. id: 'backgroundColor',
  1314. value: undefined
  1315. });
  1316. var fgElementProps = this.colorsService.getForegroundPropertiesForUIElement();
  1317. var propMap = {};
  1318. this.visModel.getDefinition().themeMapping.forEach(function (prop) {
  1319. propMap[prop.id] = prop.mapping;
  1320. });
  1321. fgElementProps.forEach(function (prop) {
  1322. if (propMap[prop.id]) {
  1323. propMap[prop.id].forEach(function (mappedPropName) {
  1324. _this17.setProperty({ id: mappedPropName, value: undefined });
  1325. });
  1326. } else {
  1327. _this17.setProperty({ id: prop.id, value: undefined });
  1328. }
  1329. });
  1330. } else {
  1331. // Get the current fill color stored in our model
  1332. var fillColor = this.visModel.ownerWidget.model.fillColor;
  1333. var hexFillColor = void 0;
  1334. if (fillColor) {
  1335. // If there is a defined fill color its in the form of 'colorx', we need
  1336. // it in the hex form. Get the hex value and set the property.
  1337. hexFillColor = this.colorsService.getHexColorFromDashboardColorSet(fillColor);
  1338. } else {
  1339. // Get the default value and set the property.
  1340. hexFillColor = this._getDefaultBackgroundColorInHex();
  1341. }
  1342. var propInfo = {
  1343. id: 'backgroundColor',
  1344. value: hexFillColor
  1345. };
  1346. this.setProperty(propInfo);
  1347. }
  1348. },
  1349. _getColorToSave: function _getColorToSave(savedValue, isCustomVis) {
  1350. var colorToSave = void 0;
  1351. if (_.isString(savedValue)) {
  1352. if (this.colorsService.isCustomColor(savedValue)) {
  1353. this.colorsService.addCustomColor(this.colorsService.getHexColorFromClassName(savedValue));
  1354. }
  1355. colorToSave = this.colorsService.getHexColorFromDashboardColorSet(savedValue);
  1356. } else {
  1357. if (isCustomVis) {
  1358. savedValue = this.colorsService.makeSureColorIsValidInModel(savedValue);
  1359. }
  1360. colorToSave = savedValue;
  1361. }
  1362. return colorToSave;
  1363. },
  1364. /**
  1365. * Apply the color set property of the specified property id
  1366. * @param {String} visId - visualization type id
  1367. * @param {String} propId - id of the color set property to set
  1368. */
  1369. _applyColorSetProperty: function _applyColorSetProperty(visId, propId, isCustomVis) {
  1370. var savedValue = this._getPropValueWhenSaving(visId, propId);
  1371. // Only apply the color if we have something saved
  1372. if (savedValue) {
  1373. var colorToSave = this._getColorToSave(savedValue, isCustomVis);
  1374. // Put the information in a structure Vida understands
  1375. var colorInfo = {
  1376. id: propId,
  1377. value: colorToSave
  1378. };
  1379. this.setProperty(colorInfo);
  1380. }
  1381. },
  1382. /**
  1383. * @param {String} visId - id of the current visualization.
  1384. * @param {Array} properties - array of property names for the specified vis
  1385. */
  1386. _applyColorSetProperties: function _applyColorSetProperties(visId, properties, isCustomVis) {
  1387. var _this18 = this;
  1388. properties.forEach(function (propertyName) {
  1389. var property = _this18.visModel.getPropertyById(propertyName);
  1390. if (property && property.colorClass) {
  1391. _this18._applyColorSetProperty(visId, propertyName, isCustomVis);
  1392. }
  1393. });
  1394. },
  1395. _getLengthPropWithPxUnit: function _getLengthPropWithPxUnit(value) {
  1396. if (typeof value !== 'undefined' && value !== null) {
  1397. return value && value.endsWith && value.endsWith('px') ? value : value + 'px';
  1398. }
  1399. return null;
  1400. },
  1401. _applyTargetMarkerThicknessProperties: function _applyTargetMarkerThicknessProperties(visId) {
  1402. var targetThickness = this._getPropValueWhenSaving(visId, 'target.marker.thickness');
  1403. if (VIPRProperties.getInstance().isTargetThicknessInputValid(targetThickness)) {
  1404. var valueToSet = this._getLengthPropWithPxUnit(targetThickness);
  1405. var targetThicknessInfo = {
  1406. id: 'target.marker.thickness',
  1407. value: valueToSet
  1408. };
  1409. this.setProperty(targetThicknessInfo);
  1410. }
  1411. },
  1412. /**
  1413. * Apply any saved layer transparencies.
  1414. * Only applies to visualizations that support layers.
  1415. */
  1416. _applySavedLayerTransparencies: function _applySavedLayerTransparencies() {
  1417. var configuration = VIPRConfig.getConfig(this.visAPI.getVisId());
  1418. if (configuration && configuration.supportsLayers) {
  1419. configuration.layerDescriptions.forEach(function (layerDesc) {
  1420. var val = this.visModel.getPropertyValue(layerDesc.colorRelatedProps.transparencyProp);
  1421. if (val !== undefined && val !== null) {
  1422. // Can be false
  1423. var propInfo = {
  1424. id: layerDesc.colorRelatedProps.transparencyProp,
  1425. value: val * 100 // Property is saved from 0.0 to 1.0, we want 0-100
  1426. };
  1427. this.setProperty(propInfo);
  1428. }
  1429. }.bind(this));
  1430. }
  1431. },
  1432. /**
  1433. * @returns true iff the value is not undefined.
  1434. */
  1435. _isPropValueValid: function _isPropValueValid(value, propDesc) {
  1436. var isPropValidByDescCheck = propDesc.checkForValidValue ? propDesc.checkForValidValue(value) : true;
  1437. return isPropValidByDescCheck && value !== undefined;
  1438. },
  1439. /**
  1440. * @returns true if the prop is inactive, readonly and has a valid default value
  1441. */
  1442. _isValidReadOnlyProperty: function _isValidReadOnlyProperty(propDesc) {
  1443. return propDesc && propDesc.isActive === false && propDesc.isReadOnly === true && this._isPropValueValid(propDesc.defaultValue, propDesc);
  1444. },
  1445. /**
  1446. * So, Vida will provide us with defaults for value and default value among
  1447. * other things. We need these for properties such as themeable props. One
  1448. * thing we don't need is all the vida property methods that come alogn with
  1449. * the property. So, we want to overide our model prop with wanted object
  1450. * properties only. Note, calling this will actually override the property
  1451. * in the model!
  1452. * @param {String} propertyName - id of the property of interest.
  1453. */
  1454. overrideWithVidaProperty: function overrideWithVidaProperty(propertyName) {
  1455. var modelProp = this.visModel.getPropertyById(propertyName);
  1456. var vidaProp = this.viprWidget.properties.get(propertyName);
  1457. if (vidaProp && modelProp) {
  1458. // Should never happen but Vida is missing some deprecated props right now.
  1459. var propsWeWantFromVidaProp = {
  1460. active: vidaProp.active,
  1461. caption: vidaProp.caption,
  1462. defaultValue: vidaProp.defaultValue,
  1463. description: vidaProp.description,
  1464. name: vidaProp.name,
  1465. type: vidaProp.type,
  1466. possibleValues: vidaProp.possibleValues
  1467. };
  1468. if (modelProp.value !== undefined) {
  1469. _.extend(propsWeWantFromVidaProp, { value: vidaProp.value });
  1470. }
  1471. _.defaults(modelProp, propsWeWantFromVidaProp);
  1472. }
  1473. },
  1474. /**
  1475. * When saving the values for a property it can be a little tricky. For example,
  1476. * if you set the stacked parameter to false in an area chart and then change the
  1477. * vis type to a stacked bar chart we still want it to stack. So, we should
  1478. * check the property to see if its active. If it isn't then we have to do a
  1479. * little priority checking.
  1480. * @param {String} visId - bundle id
  1481. * @param {String} propertyName - name of the property of interest
  1482. * @returns value of the property to use when saving.
  1483. */
  1484. _getPropValueWhenSaving: function _getPropValueWhenSaving(visId, propertyName) {
  1485. var result = null;
  1486. var propDesc = VIPRUtils.getOverridenDefaultForProperty(visId, propertyName);
  1487. /*
  1488. * Do we have a readonly property (i.e. one that has a default and can't be
  1489. * overriden by a user or programmatically)? If so, use the defaultValue
  1490. */
  1491. if (this._isValidReadOnlyProperty(propDesc)) {
  1492. result = propDesc.defaultValue;
  1493. } else {
  1494. // Get any vida defaults we may need.
  1495. this.overrideWithVidaProperty(propertyName);
  1496. // Now we should look at the model. If there is a valid (non undefined) value there
  1497. // use it, otherwise check for the defaultValue in the config.
  1498. var modelValue = this.visModel.getPropertyValue(propertyName);
  1499. if (this._isPropValueValid(modelValue, propDesc)) {
  1500. result = modelValue;
  1501. } else {
  1502. result = propDesc.defaultValue;
  1503. }
  1504. }
  1505. return result;
  1506. },
  1507. _registerListenerForPropChanges: function _registerListenerForPropChanges() {
  1508. var _this19 = this;
  1509. var listenForPropChanges = this.visAPI.getListenForPropChangesFromDefinition();
  1510. if (listenForPropChanges) {
  1511. _.each(listenForPropChanges, function (prop) {
  1512. _this19.viprWidget.properties.get(prop).on('value', _this19._onViprPropValueChange.bind(_this19));
  1513. });
  1514. //should update the flag when there are actual listeners have been registered
  1515. this.propChangeslistener = true;
  1516. }
  1517. },
  1518. /**
  1519. * When a visualization is about to be rendered we want to ensure that the
  1520. * visualization properties are all set to the user overriden value, if any.
  1521. */
  1522. _applySavedModelProperties: function _applySavedModelProperties(renderInfo) {
  1523. var _this20 = this;
  1524. return this._applySavedColorPalette().then(function () {
  1525. var visId = _this20.visAPI.getVisId();
  1526. var configuration = VIPRConfig.getConfig(visId);
  1527. var configInclude = configuration && configuration.config && configuration.config.include ? configuration.config.include : [];
  1528. if (configuration && configuration.isCustomVis && configuration.bundleInclude) {
  1529. configInclude = configuration.bundleInclude;
  1530. }
  1531. configInclude.forEach(function (propertyName) {
  1532. _this20._setModelProperty(propertyName, visId);
  1533. });
  1534. _this20._applySavedLayerTransparencies();
  1535. if (renderInfo && renderInfo.extraInfo && renderInfo.extraInfo.preserveDrawingBuffer === true) {
  1536. _this20.setProperty({ id: 'webGL.preserveDrawingBuffer', value: true });
  1537. } else {
  1538. _this20.setProperty({ id: 'webGL.preserveDrawingBuffer', value: false });
  1539. }
  1540. // Now that the default value for optimize size is set, override it to what we really want.
  1541. _this20._setOptimizedSizeProperty(visId);
  1542. _this20._setBackgroundColor();
  1543. _this20._applyEntryDurationProperty(renderInfo && renderInfo.extraInfo && renderInfo.extraInfo.entryDuration);
  1544. _this20._applyTargetMarkerThicknessProperties(visId);
  1545. // Apply all color set property values as denoted in VIPRConfig
  1546. configuration && _this20._applyColorSetProperties(visId, configuration.config.include, configuration.isCustomVis);
  1547. });
  1548. },
  1549. /**
  1550. * @returns array of run time properties in a format usable by the properties panel.
  1551. */
  1552. getProperties: function getProperties() {
  1553. var _this21 = this;
  1554. return this.whenVisControlReady().then(function () {
  1555. return VIPRProperties.getInstance().getProperties(_this21.viprWidget.properties, _this21.visualization.getSlots().getSlotList(), _this21.visualization.getDefinition().getId());
  1556. }).then(function (properties) {
  1557. //todo ???widget.getFeature? is it dead code?? livewidget_cleanup
  1558. var propertiesFilter = _this21.visModel.ownerWidget.getFeature('visPropertiesFilter');
  1559. return propertiesFilter ? propertiesFilter.filter(properties) : properties;
  1560. });
  1561. },
  1562. getPropertyList: function getPropertyList() {
  1563. return VIPRProperties.getInstance().getPropertyList(this.viprWidget.properties, this.visualization.getSlots().getSlotList(), this.content);
  1564. },
  1565. getPropertyLayoutList: function getPropertyLayoutList() {
  1566. return VIPRProperties.getInstance().getPropertyLayoutList(this.viprWidget.properties, this.visualization.getSlots().getSlotList(), this.content, this.dashboard);
  1567. },
  1568. /**
  1569. * When a theme changes we expect that all the models and their theme definitions have been
  1570. * updated before we are notified. Then all we have to do is re-render.
  1571. *
  1572. * NOTE: Only Rave and VIPR Views have to do this as all other (current views) use css.
  1573. */
  1574. onChangeTheme: function onChangeTheme() {
  1575. this.visModel.getRenderSequence().reRender();
  1576. },
  1577. /**
  1578. * Set the specified property to the specified value
  1579. * @param - info -> property of interest
  1580. * {
  1581. * id - property id,
  1582. * value - new value for the prop
  1583. * }
  1584. */
  1585. setProperty: function setProperty(info) {
  1586. VIPRProperties.getInstance().setProperty(this.viprWidget, info);
  1587. },
  1588. /**
  1589. * Generate thumbnail
  1590. *
  1591. * @param {Object} [options] - generate options
  1592. * @param {Object} [options.size] - aspect ratio to generate
  1593. * @param {number} [options.size.width=150] - aspect ratio width
  1594. * @param {number} [options.size.height=100] - aspect ratio height
  1595. * @param {string} [options.type=svg] - type of thumbnail to generate
  1596. *
  1597. * @return {Promise}
  1598. */
  1599. generateThumbnail: function generateThumbnail() {
  1600. var _this22 = this;
  1601. var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
  1602. _ref2$size = _ref2.size,
  1603. size = _ref2$size === undefined ? {} : _ref2$size,
  1604. _ref2$type = _ref2.type,
  1605. type = _ref2$type === undefined ? 'svg' : _ref2$type;
  1606. var _getThumbnailConfig = this.getThumbnailConfig(),
  1607. _getThumbnailConfig$e = _getThumbnailConfig.enabled,
  1608. enabled = _getThumbnailConfig$e === undefined ? true : _getThumbnailConfig$e;
  1609. var isMappingIncomplete = false;
  1610. var isDisabled = !enabled;
  1611. if (!this.isMappingComplete()) {
  1612. isMappingIncomplete = true;
  1613. }
  1614. var promise = void 0;
  1615. if (isDisabled || isMappingIncomplete) {
  1616. promise = Promise.resolve();
  1617. } else {
  1618. var _getThumbnailConfig2 = this.getThumbnailConfig(),
  1619. configType = _getThumbnailConfig2.type,
  1620. _getThumbnailConfig2$ = _getThumbnailConfig2.properties,
  1621. configProperties = _getThumbnailConfig2$ === undefined ? {} : _getThumbnailConfig2$;
  1622. var width = size.width,
  1623. height = size.height;
  1624. if (configType) {
  1625. type = configType;
  1626. }
  1627. var handler = this._createPredictHandler(VIPRCachedDataRequestHandler, this.predictHandler);
  1628. promise = this.viprWidget.createHidden(width, height, type, true, IGNORED_THUMBNAIL_DECORATIONS, handler).then(function (_hiddenViprWidgetInstance) {
  1629. var properties = Object.assign({}, DEFAULT_THUMBNAIL_PROPERTIES, configProperties);
  1630. Object.keys(properties).forEach(function (key) {
  1631. var value = properties[key];
  1632. _hiddenViprWidgetInstance.setProperty(key, value);
  1633. });
  1634. return _hiddenViprWidgetInstance.render(type).then(function (_renderOperation) {
  1635. var result = void 0;
  1636. if (_renderOperation && _renderOperation.completed) {
  1637. result = _this22.processThumbnailData(_renderOperation.data);
  1638. }
  1639. _hiddenViprWidgetInstance.destroy();
  1640. return result;
  1641. });
  1642. });
  1643. }
  1644. return promise.then(function (thumbnail) {
  1645. return {
  1646. thumbnail: thumbnail,
  1647. isMappingIncomplete: isMappingIncomplete,
  1648. isDisabled: isDisabled
  1649. };
  1650. });
  1651. },
  1652. processThumbnailData: function processThumbnailData(data) {
  1653. var _this23 = this;
  1654. var result = void 0;
  1655. if (data instanceof Blob) {
  1656. result = new Promise(function (resolve, reject) {
  1657. try {
  1658. var reader = new FileReader();
  1659. var altThumbnailImage = stringResources.get('loadedThumbnailImage', { visType: _this23.visModel.getDefinition().label });
  1660. reader.addEventListener('loadend', function () {
  1661. resolve('<img src="' + reader.result + '" alt="' + altThumbnailImage + '"></img>');
  1662. });
  1663. reader.readAsDataURL(data);
  1664. } catch (error) {
  1665. reject(error);
  1666. }
  1667. });
  1668. } else {
  1669. result = Promise.resolve(data);
  1670. }
  1671. return result;
  1672. },
  1673. /**
  1674. * Thumbnail config
  1675. *
  1676. * @return {Object} thumbnail config
  1677. */
  1678. getThumbnailConfig: function getThumbnailConfig() {
  1679. var _ref3 = VIPRConfig.getConfig(this.visAPI.getVisId()) || {},
  1680. _ref3$thumbnail = _ref3.thumbnail,
  1681. thumbnail = _ref3$thumbnail === undefined ? {} : _ref3$thumbnail;
  1682. return thumbnail;
  1683. },
  1684. _isSmartTitleEnabled: function _isSmartTitleEnabled() {
  1685. var featureChecker = this.dashboard && this.dashboard.getGlassCoreSvc('.FeatureChecker');
  1686. if (featureChecker && featureChecker.checkValue) {
  1687. return !featureChecker.checkValue('dashboard', 'SmartTitle', 'disabled');
  1688. }
  1689. return false;
  1690. },
  1691. /**
  1692. * check if vipr widget is valid (its id does not exists in the destroyed widgets array)
  1693. *
  1694. * @return {Boolean} True, if valid, False otherwise
  1695. */
  1696. _isViprWidgetValid: function _isViprWidgetValid() {
  1697. var _this24 = this;
  1698. return !this._deferredDestroyViprWidgetsList.find(function (widget) {
  1699. return widget.id === _this24.viprWidget.id;
  1700. });
  1701. }
  1702. });
  1703. return VIPRView;
  1704. });
  1705. //# sourceMappingURL=VIPRView.js.map