VIPRData.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. 'use strict';
  2. /*
  3. *+------------------------------------------------------------------------+
  4. *| Licensed Materials - Property of IBM
  5. *| IBM Cognos Products: Dashboard
  6. *| (C) Copyright IBM Corp. 2017, 2020
  7. *|
  8. *| US Government Users Restricted Rights - Use, duplication or disclosure
  9. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  10. *+------------------------------------------------------------------------+
  11. */
  12. define(['jquery', 'underscore', '../../lib/@waca/core-client/js/core-client/ui/core/Class', '../../apiHelpers/SlotAPIHelper', '../../widgets/livewidget/nls/StringResources', '../../util/DashboardFormatter', 'com/ibm/vida/vizbundles/extensions/decorations'], function ($, _, Class, SlotAPIHelper, StringResources, Formatter, decorations) {
  13. 'use strict';
  14. // implements IDecorated
  15. var VIPRDecoratable = Class.extend({
  16. init: function init(object, context) {
  17. this.context = context;
  18. //Save indexes that help describes the results data location of the decoratable object.
  19. //(eg. A VIPRItemClass will have the dataitem index defined but not the tuple (since it corresponds to an axis title)
  20. // A VIPRTuple will have dataitem and tuple defined (since it corresponds to the nth intersected value)
  21. // A VIPRItem will have dataitem, tuple and tupleitem (since it corresponds to an item in a slot)
  22. this.indexes = context && context.index && {
  23. dataitem: context.index.dataitem, //The resultsDataItem index (corresponds to the slot index)
  24. tuple: context.index.tuple, //The tuple (corresponds to the nth value eg: 2005-Camping)
  25. tupleitem: context.index.tupleitem //The tupleitem is the index (n) for the nth item assigned to the slot
  26. } || {};
  27. this.decorations = object ? object.deco || {} : {};
  28. },
  29. hasDecoration: function hasDecoration(name) {
  30. return typeof this.decorations[name] !== 'undefined';
  31. },
  32. getDecoration: function getDecoration(name) {
  33. return this.decorations[name];
  34. },
  35. /**
  36. * decorate vipr data - Deprecated! do not update
  37. * @param {String} name - name of decoration
  38. * @param {Object} [value] - value of decoration
  39. * @return the decoration value being saved in decorations.
  40. */
  41. decorate: function decorate(name, value) {
  42. /**
  43. * TODO need to find a generic way to use decoration APIs post Endor R4
  44. * Endor R4 solution - compare line stays as a special case to use the new VIDA decoration
  45. */
  46. var decorationValue = value;
  47. if (name === 'lines') {
  48. decorationValue = this._createLinesDecoration(name, value);
  49. }
  50. // If this decoration isn't already in the map add it
  51. if (!(name in this.decorations) || this.decorations[name] !== decorationValue) {
  52. this.decorations[name] = decorationValue;
  53. this.context.version++;
  54. }
  55. return decorationValue;
  56. },
  57. clearDecorations: function clearDecorations() {
  58. var _this = this;
  59. var deleted = false;
  60. _.each(_.keys(this.decorations), function (name) {
  61. delete _this.decorations[name];
  62. deleted = true;
  63. });
  64. if (deleted) {
  65. this.context.version++;
  66. }
  67. },
  68. _createLinesDecoration: function _createLinesDecoration(name, value) {
  69. var existingLinesDecorations = this.getDecoration(name);
  70. var linesDecorations = [];
  71. var baseLine = void 0;
  72. var grabber = void 0;
  73. var vane = void 0;
  74. _.each(existingLinesDecorations, function (lineDecoration) {
  75. if (lineDecoration instanceof decorations.BaseLine) {
  76. baseLine = lineDecoration;
  77. } else if (lineDecoration instanceof decorations.Grabber) {
  78. grabber = lineDecoration;
  79. } else if (lineDecoration instanceof decorations.Vane) {
  80. vane = lineDecoration;
  81. }
  82. });
  83. // value can be a spec object (when first creating the decoration) or an array of lines decoration (when re-apply the SAME decoration)
  84. var isReDecorate = Array.isArray(value);
  85. if (isReDecorate) {
  86. linesDecorations = value;
  87. } else if (value && !isReDecorate) {
  88. if (value.baseLine) {
  89. baseLine = baseLine ? baseLine : this._createBaseline('baseLine');
  90. if (typeof value.baseLine.position !== 'undefined') {
  91. baseLine.setPosition(value.baseLine.position);
  92. }
  93. if (value.baseLine.color) {
  94. baseLine.setColor(value.baseLine.color);
  95. }
  96. baseLine.setShowInLegend(false || value.baseLine.setShowInLegend);
  97. linesDecorations.push(baseLine);
  98. }
  99. if (value.grabber && baseLine) {
  100. grabber = grabber ? grabber : this._createGrabber('grabber');
  101. grabber.setPositionType(value.grabber.positionType);
  102. baseLine.setGrabber(grabber);
  103. linesDecorations.push(grabber);
  104. }
  105. // the label on the side of the compare line
  106. if (value.vane && baseLine) {
  107. vane = vane ? vane : this._createVane('vane');
  108. vane.setCaption(value.vane.caption);
  109. baseLine.setVane(vane);
  110. linesDecorations.push(vane);
  111. }
  112. }
  113. return linesDecorations;
  114. },
  115. _createBaseline: function _createBaseline() {
  116. var baseLineId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _.uniqueId('baseLine');
  117. return new decorations.BaseLine(baseLineId);
  118. },
  119. _createGrabber: function _createGrabber() {
  120. var grabberId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _.uniqueId('grabber');
  121. return new decorations.Grabber(grabberId);
  122. },
  123. _createVane: function _createVane() {
  124. var vaneId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _.uniqueId('vane');
  125. return new decorations.Vane(vaneId);
  126. }
  127. });
  128. // implements IFormatter
  129. var VIPRFormatter = Class.extend({
  130. init: function init(slotIndex, dataItemIndex, context) {
  131. this.slot = context.dataset.slotAPIs[slotIndex];
  132. this.dataItemIndex = dataItemIndex;
  133. this._format = this.slot.getDataItemList()[dataItemIndex].getFormat();
  134. },
  135. format: function format(value) {
  136. return Formatter.format(value, this._format);
  137. }
  138. });
  139. // implements IItemClass
  140. var VIPRItemClass = VIPRDecoratable.extend({
  141. init: function init(itemClass, context) {
  142. VIPRItemClass.inherited('init', this, [itemClass, context]);
  143. this.itemClass = itemClass;
  144. this.context = context;
  145. },
  146. getUniqueName: function getUniqueName() {
  147. return this.itemClass.u;
  148. },
  149. getCaption: function getCaption() {
  150. var summaryStr = void 0;
  151. if (!this.context.hideAggTypeInAxisLabels) {
  152. summaryStr = this.itemClass.aggregate && this.itemClass.aggregate !== 'none' ? ' (' + StringResources.get(this.itemClass.aggregate) + ')' : null;
  153. }
  154. var caption = this.itemClass.d ? this.itemClass.d : this.itemClass.u;
  155. return summaryStr ? caption + summaryStr : caption;
  156. }
  157. });
  158. // implements IItem
  159. var VIPRItem = VIPRDecoratable.extend({
  160. init: function init(item, tuple, context, content) {
  161. VIPRItem.inherited('init', this, [item, context, content]);
  162. this.item = item;
  163. this.context = context;
  164. this.index = context.index.tupleitem;
  165. this.content = content;
  166. this.datapoints = tuple.datapoints;
  167. this.recalculateFormattedValue();
  168. },
  169. /**
  170. * TODO: This function is a duplicate of the one in VIPRItem
  171. * these classes will be removed once forecasting and smart annotations move to the new query format.
  172. */
  173. recalculateFormattedValue: function recalculateFormattedValue() {
  174. var formatter = new VIPRFormatter(this.context.index.dataitem, this.context.index.tupleitem, this.context);
  175. if (this.item.d === undefined || this.item.d === null) {
  176. this.formattedValue = formatter.format(null);
  177. this.unformattedValue = this.formattedValue;
  178. } else if (this.item.aggregate) {
  179. var aggregateTypeVisible = !!(!this.content || this.content.getPropertyValue('widget.legend.aggregateTypeVisible'));
  180. if (aggregateTypeVisible) {
  181. this.formattedValue = formatter.format(StringResources.get('multiMeasureLabel', { 'measureName': this.item.d.toString(), 'aggregate': StringResources.get(this.item.aggregate.toString()) }));
  182. this.unformattedValue = this.item.d + this.item.aggregate;
  183. } else {
  184. this.formattedValue = formatter.format(StringResources.get('measureLabel', { 'measureName': this.item.d.toString() }));
  185. this.unformattedValue = this.item.d + this.item.aggregate;
  186. }
  187. } else {
  188. this.formattedValue = formatter.format(this.item.d.toString());
  189. this.unformattedValue = this.item.d;
  190. }
  191. },
  192. getUniqueName: function getUniqueName() {
  193. return this.item.u === undefined || this.item.u === null ? this.item.u : this.item.u.toString();
  194. },
  195. getCaption: function getCaption() {
  196. if (this.item.aggregate) {
  197. var currentAggregationPropertyValue = !this.content || this.content.getPropertyValue('widget.legend.aggregateTypeVisible');
  198. if (currentAggregationPropertyValue != this.aggregationPropertyValue) {
  199. this.recalculateFormattedValue();
  200. this.aggregationPropertyValue = currentAggregationPropertyValue;
  201. }
  202. }
  203. if (!this.formattedValue) {
  204. this.recalculateFormattedValue();
  205. }
  206. return this.formattedValue;
  207. },
  208. getParent: function getParent() {
  209. return this.item.p;
  210. },
  211. decorate: function decorate(action, value) {
  212. if (this.datapoints.length > 0) {
  213. this.context.version++;
  214. // decorate the datapoints
  215. _.each(this.datapoints, function (dp) {
  216. dp.decorate(action, value);
  217. });
  218. }
  219. }
  220. });
  221. var VIPRItem_CaptionAsUnid = VIPRItem.extend({
  222. getUniqueName: function getUniqueName() {
  223. return this.getCaption();
  224. }
  225. });
  226. // implements IItemClassSet
  227. var VIPRItemClassSet = VIPRDecoratable.extend({
  228. init: function init(header, context) {
  229. VIPRItemClassSet.inherited('init', this, [header, context]);
  230. this.header = header;
  231. this.context = context;
  232. this.itemClasses = [];
  233. },
  234. getItemClassCount: function getItemClassCount() {
  235. return this.header.length;
  236. },
  237. getItemClass: function getItemClass(index) {
  238. if (this.itemClasses[index] === undefined) {
  239. this.itemClasses[index] = new VIPRItemClass(this.header[index], this.context);
  240. }
  241. return this.itemClasses[index];
  242. }
  243. });
  244. // implements ITuple
  245. var VIPRTuple = VIPRDecoratable.extend({
  246. init: function init(tuple, context, content) {
  247. VIPRTuple.inherited('init', this, [tuple, context, content]);
  248. this.tuple = tuple;
  249. this.context = context;
  250. this.datapoints = [];
  251. this.items = [];
  252. this.dataset = context.dataset;
  253. this.dataItemIndex = this.context.index.dataitem;
  254. this.itemClassSetIndex = this.context.index.itemClassSet;
  255. this.content = content;
  256. },
  257. getUniqueName: function getUniqueName() {
  258. return this.getItem(0).getUniqueName();
  259. },
  260. //This function should be only used for rave2bundlesnetwork bundle
  261. //this bundle has certain slots that have subtype: reference
  262. //this function now works as a workaround and has no impact on livewidget vis
  263. getReference: function getReference() {
  264. return this.getItem(0).getUniqueName();
  265. },
  266. getCaption: function getCaption() {
  267. return this.getItem(0).getCaption();
  268. },
  269. getParent: function getParent() {
  270. return this.getItem(0).getParent();
  271. },
  272. getItemClassSetIndex: function getItemClassSetIndex() {
  273. //Since Enodr release, a tuple could have a itemClassSetIndex property
  274. //that indicates which itemClass the current tuple is using
  275. return this.itemClassSetIndex;
  276. },
  277. getItem: function getItem(index) {
  278. if (this.items[index] === undefined) {
  279. // keep track of the tuple item index as part of the context index
  280. this.context.index.tupleitem = index;
  281. this.context.dataset = this.dataset;
  282. var isCaptionAsUniqueName = false;
  283. var dataItemIndex = this.context.index.dataitem;
  284. if (dataItemIndex >= 0) {
  285. var oSlotAPI = this.context.dataset.slotAPIs[dataItemIndex];
  286. isCaptionAsUniqueName = oSlotAPI.isCaptionAsUniqueName && oSlotAPI.isCaptionAsUniqueName();
  287. }
  288. var classOfVIPRItem = isCaptionAsUniqueName ? VIPRItem_CaptionAsUnid : VIPRItem;
  289. this.items[index] = new classOfVIPRItem(this.tuple[index], this, this.context, this.content);
  290. }
  291. return this.items[index];
  292. },
  293. getItemCount: function getItemCount() {
  294. return this.tuple ? this.tuple.length : 0;
  295. },
  296. addDataPoint: function addDataPoint(datapoint) {
  297. if (this.datapoints.indexOf(datapoint) === -1) {
  298. this.datapoints.push(datapoint);
  299. }
  300. },
  301. decorate: function decorate(action, value) {
  302. VIPRTuple.inherited('decorate', this, [action, value]);
  303. if (this.datapoints.length > 0) {
  304. this.context.version++;
  305. // decorate the datapoints
  306. _.each(this.datapoints, function (dp) {
  307. dp.decorate(action, value);
  308. });
  309. }
  310. }
  311. });
  312. // implements ICatDataItem
  313. var VIPRCatDataItem = VIPRDecoratable.extend({
  314. init: function init(dataItem, context, content) {
  315. VIPRCatDataItem.inherited('init', this, [dataItem._dataItem, context]);
  316. this.dataItem = dataItem;
  317. this.context = context;
  318. this.index = this.context.index.dataitem;
  319. this.dataset = this.context.dataset;
  320. this.tuples = [];
  321. this.itemClassSets = [];
  322. this.content = content;
  323. _.each(this.dataItem.getTupleHeaders(), function (entry) {
  324. this.itemClassSets.push(new VIPRItemClassSet(entry, this.context));
  325. }.bind(this));
  326. },
  327. getUniqueName: function getUniqueName() {},
  328. postProcessing: function postProcessing() {},
  329. getCaption: function getCaption() {},
  330. getType: function getType() {
  331. return 'cat';
  332. },
  333. getTupleCount: function getTupleCount() {
  334. return this.dataItem ? this.dataItem.getTupleCount() : 0;
  335. },
  336. getTuple: function getTuple(index) {
  337. if (this.tuples[index] === undefined) {
  338. this.context.dataset = this.dataset;
  339. this.context.index = {
  340. dataitem: this.index,
  341. tuple: index,
  342. itemClassSet: this.dataItem.getTupleItemClassSetIndex(index)
  343. };
  344. this.tuples[index] = new VIPRTuple(this.dataItem.getTuple(index), this.context, this.content);
  345. }
  346. return this.tuples[index];
  347. },
  348. getDataWindowStart: function getDataWindowStart() {
  349. return 0;
  350. },
  351. getDataWindowEnd: function getDataWindowEnd() {
  352. return this.getTupleCount();
  353. },
  354. getItemClassSetCount: function getItemClassSetCount() {
  355. return this.itemClassSets.length;
  356. },
  357. getItemClassSet: function getItemClassSet(index) {
  358. return this.itemClassSets[index || 0];
  359. }
  360. });
  361. var VIPRCatContDataItem = VIPRCatDataItem.extend({
  362. init: function init() {
  363. VIPRCatContDataItem.inherited('init', this, arguments);
  364. this.formatter = new VIPRFormatter(this.context.index.dataitem, 0, this.context);
  365. this.postProcessing();
  366. },
  367. getType: function getType() {
  368. return 'cont';
  369. },
  370. getFormatter: function getFormatter() {
  371. return this.formatter;
  372. },
  373. postProcessing: function postProcessing() {
  374. var index = this.context.index.dataitem;
  375. var subType = this.dataset.slotAPIs[index].getSubType();
  376. if (subType && subType === 'latitude' || subType === 'longitude') {
  377. _.each(this.dataItem._dataItem.items, function (item) {
  378. if (item.t[0].hasOwnProperty('d') && item.t[0].hasOwnProperty('u') && item.t[0].d !== item.t[0].u) {
  379. item.t[0].u = item.t[0].d;
  380. }
  381. });
  382. }
  383. },
  384. getItemClass: function getItemClass() {
  385. return null;
  386. },
  387. getDomain: function getDomain() {
  388. return null;
  389. }
  390. });
  391. // implements IContDataItem
  392. var VIPRContDataItem = VIPRDecoratable.extend({
  393. init: function init(dataItem, context) {
  394. VIPRContDataItem.inherited('init', this, [dataItem._dataItem, context]);
  395. this.dataItem = dataItem;
  396. this.context = context;
  397. this.queryResult = context && context.queryResult;
  398. // Ordinal slots normally does not take multiple dataitems (ie. stacked)
  399. // even for multi-measures case (ie. bar, column) the multiple ordinal dataitems are merged in to a single ordinal measure
  400. // and each measures are separated as series.
  401. // So at the end, from the VIPRData perspective a numeric dataitem (aka slot), has only one measure.
  402. this.formatter = new VIPRFormatter(this.context.index.dataitem, 0, this.context);
  403. //getTupleHeaders() return the array of itemClass, each Item Class contains an array of Tuple headers
  404. this.itemClass = new VIPRItemClass(this.dataItem.getTupleHeaders()[0][0], this.context);
  405. this.domain = this._createDomain(); // Min Max Data Item domain
  406. },
  407. /**
  408. * @returns the domain when the data item is a multi measure.
  409. */
  410. _createMultiMeasureDomain: function _createMultiMeasureDomain() {
  411. var domain = null;
  412. var topBottomMappings = this.queryResult && this.queryResult.getTopBottomMappings();
  413. var keys = _.keys(topBottomMappings);
  414. var overAllMin;
  415. var overAllMax;
  416. /*
  417. * This may have to be tweaked depending on how Ruben asks for the domain
  418. * as we may have to deal with aggregated or not. For now keep it simple.
  419. * Make the min the min of all the min values. Make the max the max of all
  420. * max values.
  421. */
  422. if (keys.length) {
  423. keys.forEach(function (key) {
  424. var minValue = topBottomMappings[key].bottomResult.useValue;
  425. var maxValue = topBottomMappings[key].topResult.useValue;
  426. overAllMin = overAllMin ? Math.min(overAllMin, minValue) : minValue;
  427. overAllMax = overAllMax ? Math.max(overAllMax, maxValue) : maxValue;
  428. });
  429. domain = {
  430. min: overAllMin,
  431. max: overAllMax
  432. };
  433. }
  434. return domain;
  435. },
  436. /**
  437. * @returns the domain when the data item is not a multi measure.
  438. */
  439. _createNonMultiMeasureDomain: function _createNonMultiMeasureDomain() {
  440. var domain = null;
  441. var topBottomMappings = this.queryResult && this.queryResult.getTopBottomMappings();
  442. // Use the mappings object to determine the min and max of the domain
  443. var topBottomMapItemName = this.itemClass.itemClass.u + this.itemClass.itemClass.aggregate;
  444. if (topBottomMapItemName && topBottomMappings) {
  445. var topBottom = topBottomMappings[topBottomMapItemName];
  446. if (topBottom) {
  447. domain = {
  448. min: topBottom.bottomResult.useValue,
  449. max: topBottom.topResult.useValue
  450. };
  451. }
  452. }
  453. return domain;
  454. },
  455. /**
  456. * @returns the domain (min/max) for the data item
  457. */
  458. _createDomain: function _createDomain() {
  459. var domain = null;
  460. if (this.itemClass && this.itemClass.itemClass) {
  461. if (this.itemClass.itemClass.u === '_multiMeasuresValue') {
  462. domain = this._createMultiMeasureDomain();
  463. } else {
  464. domain = this._createNonMultiMeasureDomain();
  465. }
  466. }
  467. return domain;
  468. },
  469. getUniqueName: function getUniqueName() {
  470. return this.itemClass.getUniqueName();
  471. },
  472. getCaption: function getCaption() {
  473. return this.itemClass.getCaption();
  474. },
  475. getType: function getType() {
  476. return 'cont';
  477. },
  478. getDomain: function getDomain() /*aggregation TODO for stacked charts*/{
  479. return this._createDomain();
  480. },
  481. getFormatter: function getFormatter() {
  482. return this.formatter;
  483. },
  484. getItemClass: function getItemClass() {
  485. return this.itemClass;
  486. }
  487. });
  488. // IValue-ization
  489. function asIValue(valueObj, formatter, index) {
  490. //FIXME The situation happens Only when using Fact value with multiple itemsetClassset,
  491. //Will fix this when VIDA provides a solution for this.
  492. if (_.isNumber(valueObj)) {
  493. valueObj = { v: valueObj };
  494. }
  495. if (typeof valueObj.getValue === 'undefined') {
  496. valueObj.getIndex = function () {
  497. return index;
  498. };
  499. valueObj.getValue = function () {
  500. return this.v;
  501. };
  502. valueObj.getValueType = function () {
  503. if (this.v === null) {
  504. return 'missing'; //NULL Value support, to be parsed by VIDA
  505. }
  506. return 'numeric'; //Default Value Type
  507. };
  508. var caption = formatter.format(valueObj.v);
  509. valueObj.getCaption = function () {
  510. return caption;
  511. };
  512. }
  513. return valueObj;
  514. }
  515. // IDataPoint-ization
  516. function asIDataPoint(datapoint, dataset, context) {
  517. if (typeof datapoint.context === 'undefined') {
  518. datapoint.dataset = dataset;
  519. datapoint.getTupleIndex = function (index) {
  520. var tupleIndex = this.pt[index];
  521. // Keep a reverse-reference from tuple to the datapoint
  522. this.dataset.getDataItem(index).getTuple(tupleIndex).addDataPoint(this);
  523. return tupleIndex;
  524. }.bind(datapoint);
  525. //return all of the categorical indexes in the pt array as a string 'key' for this datapoint.
  526. datapoint.getDataPointKey = function () {
  527. return this.pt ? _.filter(this.pt, function (pt) {
  528. return typeof pt === 'number';
  529. }).toString() : '';
  530. }.bind(datapoint);
  531. var getValue = typeof datapoint.getValue === 'function' ? datapoint.getValue : undefined;
  532. datapoint.getValue = function (index) {
  533. var valueObj = getValue ? getValue(index) : this.pt[index];
  534. var bIsUseCategoryAsValue = this.dataset.slotAPIs[index].getDefinition().useCategoryAsValue;
  535. if (bIsUseCategoryAsValue) {
  536. var tuple = this.dataset.resultData.getResultDataItem(index).getTuple(this.pt[index]);
  537. valueObj = {
  538. 'v': tuple[0].u
  539. };
  540. }
  541. var formatter = this.dataset.getDataItem(index).getFormatter();
  542. return asIValue(valueObj, formatter, index);
  543. }.bind(datapoint);
  544. // IDecorated-ize the datapoint
  545. if (!datapoint.hasDecoration || !datapoint.getDecoration || !datapoint.decorate) {
  546. datapoint._decorations = new VIPRDecoratable(datapoint, context);
  547. datapoint.hasDecoration = datapoint._decorations.hasDecoration.bind(datapoint._decorations);
  548. datapoint.getDecoration = datapoint._decorations.getDecoration.bind(datapoint._decorations);
  549. datapoint.clearDecorations = datapoint._decorations.clearDecorations.bind(datapoint._decorations);
  550. datapoint.decorate = function (action, value) {
  551. // default value: true
  552. value = typeof value === 'undefined' ? true : value;
  553. this._decorations.decorate(action, value);
  554. }.bind(datapoint);
  555. }
  556. }
  557. return datapoint;
  558. }
  559. // implements IDataPointIterator
  560. var VIPRDataPointIterator = Class.extend({
  561. init: function init(dataset, context) {
  562. this.dataset = dataset;
  563. this.resultData = dataset.resultData;
  564. this.slotAPIs = dataset.slotAPIs;
  565. this.datapoints = this.resultData.getDatapoints();
  566. this.context = context;
  567. this.index = -1;
  568. },
  569. nextValue: function nextValue() {
  570. if (this.index < this.datapoints.length - 1) {
  571. return asIDataPoint(this.datapoints[++this.index], this.dataset, this.context);
  572. }
  573. return null;
  574. },
  575. getTupleItems: function getTupleItems() {
  576. var items = [];
  577. for (var i = 0; i < this.datapoints[this.index].pt.length; i++) {
  578. var value = this.resultData.getCellValue(this.index, i);
  579. if ($.isArray(value)) {
  580. items = items.concat(value);
  581. }
  582. }
  583. return items;
  584. }
  585. });
  586. var VIPRDataSet = VIPRDecoratable.extend({
  587. init: function init(resultData, slotAPIs, queryResult, context, content, datasetId) {
  588. VIPRDataSet.inherited('init', this, []);
  589. this.resultData = resultData;
  590. this.slotAPIs = slotAPIs;
  591. // Need to preload dataItems to handle empty result.
  592. this.dataItems = [];
  593. var aResultDataItems = this.resultData.getResultDataItems();
  594. this.context = context;
  595. this.context.queryResult = queryResult;
  596. this.context.dataset = this;
  597. this.content = content;
  598. this.id = datasetId;
  599. var numberOfDataItems = aResultDataItems ? aResultDataItems.length : 0;
  600. for (var index = 0; index < numberOfDataItems; index++) {
  601. var dataItem = aResultDataItems[index];
  602. if (this.slotAPIs[index]) {
  603. // TODO livewidget_cleanup .. old API.. but where is it used ?
  604. var slotType = this.slotAPIs[index].getDataItemList()[0].getType();
  605. var VIPRDataItem = slotType === 'attribute' ? VIPRCatDataItem : VIPRContDataItem;
  606. //fixme hack
  607. if (this.slotAPIs[index].getId().indexOf('latlongLocations.lat') !== -1 || this.slotAPIs[index].getId().indexOf('latlongLocations.long') !== -1) {
  608. VIPRDataItem = VIPRCatContDataItem;
  609. }
  610. this.context.index = {
  611. dataitem: index
  612. };
  613. this.dataItems[index] = new VIPRDataItem(dataItem, this.context, content);
  614. }
  615. }
  616. },
  617. // implement IDataSet
  618. getDataItem: function getDataItem(index) {
  619. return index < this.dataItems.length ? this.dataItems[index] : null;
  620. },
  621. getDataItemCount: function getDataItemCount() {
  622. return this.resultData.getResultDataItemCount();
  623. },
  624. getDataPointIterator: function getDataPointIterator() {
  625. return new VIPRDataPointIterator(this, this.context);
  626. }
  627. });
  628. var VIPRData = VIPRDecoratable.extend({
  629. /**
  630. * @param {Object[]} queryResults
  631. */
  632. init: function init(queryResults, visualization, hideAggTypeInAxisLabels, content) {
  633. VIPRData.inherited('init', this, []);
  634. this.content = content;
  635. this.context = {
  636. version: 0,
  637. VIPRData: this,
  638. hideAggTypeInAxisLabels: hideAggTypeInAxisLabels
  639. };
  640. this._aVIPRDataSets = [];
  641. var aDataSets = visualization.getDefinition().getDatasetList();
  642. _.each(aDataSets, function (dataset) {
  643. var aQueryResult = _.find(queryResults, function (entry) {
  644. return entry.getDataViewId() === dataset.id;
  645. });
  646. if (aQueryResult) {
  647. this._aVIPRDataSets.push(new VIPRDataSet(aQueryResult.getFacetData(), SlotAPIHelper.getMappedSlotListByDataset(visualization, aQueryResult.getDataViewId()), aQueryResult, this.context, this.content, dataset.id));
  648. } else {
  649. this._aVIPRDataSets.push(null);
  650. }
  651. }.bind(this));
  652. },
  653. getDataSetAt: function getDataSetAt(index) {
  654. return this._aVIPRDataSets[index];
  655. },
  656. getDataSetCount: function getDataSetCount() {
  657. return this._aVIPRDataSets.length;
  658. },
  659. getDecorationsVersion: function getDecorationsVersion() {
  660. return this.context.version;
  661. }
  662. });
  663. return VIPRData;
  664. });
  665. //# sourceMappingURL=VIPRData.js.map