multiLayersSupport.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. 'use strict';
  2. /*
  3. *+------------------------------------------------------------------------+
  4. *| Licensed Materials - Property of IBM
  5. *| IBM Cognos Products: BI Dashboard
  6. *| (C) Copyright IBM Corp. 2017
  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(['underscore', '../../../lib/@waca/core-client/js/core-client/ui/core/Class', '../../../lib/@waca/upgrades/UpgradeBase'], function (_, Class, UpgradeBase) {
  13. 'use strict'; //NOSONAR
  14. /*jshint maxcomplexity:15 */
  15. /*jshint unused:false*/
  16. // Slots can be in any order in dashboard spec, order them to ease the upgrade and the verification of result
  17. var SLOT_ORDERS = {
  18. 'locations': 0,
  19. 'locationColor': 1,
  20. 'pointColor': 2,
  21. 'pointSize': 3
  22. };
  23. var TILEDMAP_VISID = 'com.ibm.vis.rave2bundletiledmap';
  24. var PROPERTY_METADATA = {
  25. oldPaletteId: 'contColorPalette',
  26. palettePrefix: 'colorPalette',
  27. oldHeatScalePaletteId: 'heatScalePalette'
  28. };
  29. var Upgrade = Class.extend([UpgradeBase], {
  30. init: function init() {
  31. this.VERSION = 1007;
  32. },
  33. /**
  34. * Perform upgrade
  35. *
  36. * @param {object} spec - spec to perform upgrade on
  37. *
  38. * @return {Promise} Promise to be resolved when upgrade performed
  39. */
  40. up: function up(spec) {
  41. if (spec.widgets) {
  42. this._upgradeWidgets(spec);
  43. }
  44. return Promise.resolve(spec);
  45. },
  46. _upgradeWidgets: function _upgradeWidgets(spec) {
  47. try {
  48. _.each(spec.widgets, function (model) {
  49. if (model.visId === TILEDMAP_VISID) {
  50. this._convertTiledMapVis(model);
  51. }
  52. }.bind(this));
  53. } catch (error) {
  54. throw error;
  55. }
  56. },
  57. // Build the new dataViews and slotmapping for tiledmap visualization
  58. _convertTiledMapVis: function _convertTiledMapVis(model) {
  59. // get existing slots
  60. var existingSlots = model.slotmapping.slots;
  61. if (!existingSlots || !existingSlots.length) {
  62. return;
  63. }
  64. var newDataViews = [];
  65. var newSlotMapping = {
  66. slots: [],
  67. layers: []
  68. };
  69. var slotIndexes = [];
  70. for (var i = 0; i < existingSlots.length; ++i) {
  71. var slotName = existingSlots[i].name;
  72. slotIndexes.push({ order: SLOT_ORDERS[slotName], existingSlotIndex: i });
  73. }
  74. var sortedSlots = _.sortBy(slotIndexes, 'order');
  75. // Convert each existing slot to new slot, new dataView, new layer
  76. _.each(sortedSlots, function (sortedSlot) {
  77. var slot = existingSlots[sortedSlot.existingSlotIndex];
  78. switch (slot.name) {
  79. case 'locations':
  80. this._convertLocationSlot(model, slot, newDataViews, newSlotMapping);
  81. break;
  82. case 'locationColor':
  83. this._convertLocationColorSlot(model, slot, newDataViews, newSlotMapping);
  84. break;
  85. case 'pointColor':
  86. this._convertPointColorSlot(model, slot, newDataViews, newSlotMapping);
  87. break;
  88. case 'pointSize':
  89. this._convertPointSizeSlot(model, slot, newDataViews, newSlotMapping);
  90. break;
  91. default:
  92. break;
  93. }
  94. }.bind(this));
  95. // replace old dataViews and old slotmapping with the new one
  96. model.data.dataViews = newDataViews;
  97. model.slotmapping = newSlotMapping;
  98. // upgrade map properties
  99. this._upgradeProperties(model);
  100. },
  101. // If the old spec doesn't have palette or heatScalePalette property, nothing to upgrade
  102. // If the old spec has these properties, here is the rule for the upgrade
  103. // if the new spec has:
  104. // (a) 1 layer: then keep the same palette as R8
  105. // (b) 2 layers: create a new property for the second layer palette and it should be different than the first one
  106. // - if R8 has palette 0, then set palette 1 for the second layer
  107. // - if R8 has palette != 0, then set palette 0 to the second layer. This way, we don't need to
  108. // know if the existing palette is the last palette or not
  109. // The heatScalePalette value is the same as R8
  110. _upgradeProperties: function _upgradeProperties(model) {
  111. if (!model.properties) {
  112. return;
  113. }
  114. var properties = model.properties;
  115. var existingPalette = _.findWhere(properties, { id: PROPERTY_METADATA.oldPaletteId });
  116. var existingHeatScale = _.findWhere(properties, { id: PROPERTY_METADATA.oldHeatScalePaletteId });
  117. if (!existingPalette && !existingHeatScale) {
  118. return;
  119. }
  120. var existingPaletteNumber;
  121. var nbLayers = model.slotmapping.layers.length;
  122. if (existingPalette) {
  123. // First layer: update property id and keep the same palette value
  124. existingPalette.id = PROPERTY_METADATA.oldPaletteId + '_' + model.slotmapping.layers[0].id;
  125. existingPaletteNumber = existingPalette.value.substring(PROPERTY_METADATA.palettePrefix.length);
  126. // Second layer palette
  127. if (nbLayers > 1) {
  128. var newPaletteNumber;
  129. if (existingPaletteNumber === '0') {
  130. newPaletteNumber = '1';
  131. } else {
  132. newPaletteNumber = '0';
  133. }
  134. properties.push({
  135. id: PROPERTY_METADATA.oldPaletteId + '_' + model.slotmapping.layers[1].id,
  136. value: PROPERTY_METADATA.palettePrefix + newPaletteNumber
  137. });
  138. }
  139. }
  140. if (existingHeatScale) {
  141. // First layer: update palette id
  142. existingHeatScale.id = PROPERTY_METADATA.oldHeatScalePaletteId + '_' + model.slotmapping.layers[0].id;
  143. if (nbLayers > 1) {
  144. // Add property for second layer
  145. properties.push({
  146. id: PROPERTY_METADATA.oldHeatScalePaletteId + '_' + model.slotmapping.layers[1].id,
  147. value: existingHeatScale.value
  148. });
  149. }
  150. }
  151. },
  152. _addNewDataView: function _addNewDataView(modelRef, newDataViews) {
  153. newDataViews.push({
  154. id: _.uniqueId('model'),
  155. modelRef: modelRef,
  156. dataItems: []
  157. });
  158. return newDataViews[newDataViews.length - 1].id;
  159. },
  160. _addNewLayer: function _addNewLayer(layers, layerInfo) {
  161. layers.push({
  162. id: layerInfo.type,
  163. type: layerInfo.type,
  164. dataViewId: layerInfo.dataViewId
  165. });
  166. return layers[layers.length - 1].id;
  167. },
  168. _addNewDataItem: function _addNewDataItem(dataItems, oldDataItem) {
  169. var cloneDataItem = _.clone(oldDataItem);
  170. // update uniqueId to avoid collision
  171. cloneDataItem.id = _.uniqueId('model');
  172. dataItems.push(cloneDataItem);
  173. return cloneDataItem.id;
  174. },
  175. _convertLocationSlot: function _convertLocationSlot(model, slot, newDataViews, newSlotMapping) {
  176. // Do not create the region layer if location color is not mapped and we have pointSize/pointColor mapped.
  177. // Old locations will be mapped to pointLocations slot
  178. var oldSlots = _.pluck(model.slotmapping.slots, 'name');
  179. var existLocationColor = oldSlots.indexOf('locationColor') > -1 ? true : false;
  180. var existPointSizeOrPointColor = oldSlots.indexOf('pointSize') > 0 || oldSlots.indexOf('pointColor') > 0 ? true : false;
  181. if (!existLocationColor && existPointSizeOrPointColor) {
  182. return;
  183. }
  184. // add dataView for layer "region"
  185. var oldDataView = model.data.dataViews[0];
  186. var newDataViewId = this._addNewDataView(oldDataView.modelRef, newDataViews);
  187. // create layer "region"
  188. var layerInfo = {
  189. type: 'data.region',
  190. dataViewId: newDataViewId
  191. };
  192. var newLayerId = this._addNewLayer(newSlotMapping.layers, layerInfo);
  193. // create slot "Locations" from the old slot "Locations"
  194. var newSlot = _.clone(slot);
  195. newSlot.layerId = newLayerId;
  196. // Copy data items from old slot
  197. newSlot.dataItems = [];
  198. _.each(slot.dataItems, function (dataItemRef) {
  199. var existingDataItem = _.findWhere(oldDataView.dataItems, { id: dataItemRef });
  200. var newDataItemId = this._addNewDataItem(newDataViews[0].dataItems, existingDataItem);
  201. newSlot.dataItems.push(newDataItemId);
  202. }.bind(this));
  203. newSlotMapping.slots.push(newSlot);
  204. },
  205. _convertLocationColorSlot: function _convertLocationColorSlot(model, slot, newDataViews, newSlotMapping) {
  206. // DataView and layer for "region" should already exist, only create slot LocationColor and add dataItem for this slot
  207. var newSlot = _.clone(slot);
  208. newSlot.layerId = 'data.region';
  209. var dataItemRef = slot.dataItems[0];
  210. var existingDataItem = _.findWhere(model.data.dataViews[0].dataItems, { id: dataItemRef });
  211. var newDataItemId = this._addNewDataItem(newDataViews[0].dataItems, existingDataItem);
  212. newSlot.dataItems = [newDataItemId];
  213. newSlotMapping.slots.push(newSlot);
  214. },
  215. _createPointLocationsSlot: function _createPointLocationsSlot(newSlotMapping, oldLocationSlot) {
  216. var pointLocationSlot = _.clone(oldLocationSlot);
  217. pointLocationSlot.name = 'pointLocations';
  218. pointLocationSlot.caption = 'Point locations';
  219. pointLocationSlot.dataItems = [];
  220. newSlotMapping.slots.push(pointLocationSlot);
  221. return pointLocationSlot;
  222. },
  223. _createPointLayer: function _createPointLayer(model, newDataViews, newSlotMapping) {
  224. // create slot "pointLocations" from the slot "Locations" of region if this one exists
  225. var pointLocationSlot;
  226. var slots = model.slotmapping.slots;
  227. var index = slots.map(function (slot) {
  228. return slot.name;
  229. }).indexOf('locations');
  230. if (index > -1) {
  231. pointLocationSlot = this._createPointLocationsSlot(newSlotMapping, slots[index]);
  232. }
  233. // Create new data view
  234. var modelRef = model.data.dataViews[0].modelRef;
  235. this._addNewDataView(modelRef, newDataViews);
  236. var newDataView = newDataViews[newDataViews.length - 1];
  237. // create "point" layer
  238. var layerInfo = {
  239. type: 'data.point',
  240. dataViewId: newDataView.id
  241. };
  242. var newLayerId = this._addNewLayer(newSlotMapping.layers, layerInfo);
  243. // copy data items from old location slot to pointLocations slot
  244. if (pointLocationSlot) {
  245. pointLocationSlot.layerId = newLayerId;
  246. var dataItemRefs = slots[index].dataItems;
  247. _.each(dataItemRefs, function (dataItemRef) {
  248. var existingDataItem = _.findWhere(model.data.dataViews[0].dataItems, { id: dataItemRef });
  249. var newDataItemId = this._addNewDataItem(newDataView.dataItems, existingDataItem);
  250. pointLocationSlot.dataItems.push(newDataItemId);
  251. }.bind(this));
  252. }
  253. },
  254. _convertPointColorSlot: function _convertPointColorSlot(model, slot, newDataViews, newSlotMapping) {
  255. // create new DataView and layer for point layer
  256. this._createPointLayer(model, newDataViews, newSlotMapping);
  257. // Add slot "pointColor"
  258. var newSlot = _.clone(slot);
  259. newSlot.layerId = 'data.point';
  260. // name and caption do not change
  261. var dataItemRef = slot.dataItems[0];
  262. var existingDataItem = _.findWhere(model.data.dataViews[0].dataItems, { id: dataItemRef });
  263. var newDataItemId = this._addNewDataItem(newDataViews[newDataViews.length - 1].dataItems, existingDataItem);
  264. newSlot.dataItems = [newDataItemId];
  265. newSlotMapping.slots.push(newSlot);
  266. },
  267. _convertPointSizeSlot: function _convertPointSizeSlot(model, slot, newDataViews, newSlotMapping) {
  268. var pointLayer;
  269. if (newSlotMapping.layers) {
  270. pointLayer = newSlotMapping.layers.find(function (layer) {
  271. return layer.id === 'data.point';
  272. });
  273. }
  274. if (!pointLayer) {
  275. // Point layer is not created yet, create new DataView and layer for point layer
  276. this._createPointLayer(model, newDataViews, newSlotMapping);
  277. }
  278. // convert pointSize slot
  279. var newSlot = _.clone(slot);
  280. newSlot.layerId = 'data.point';
  281. // name and caption do not change
  282. var dataItemRef = slot.dataItems[0];
  283. var existingDataItem = _.findWhere(model.data.dataViews[0].dataItems, { id: dataItemRef });
  284. var newDataItemId = this._addNewDataItem(newDataViews[newDataViews.length - 1].dataItems, existingDataItem);
  285. newSlot.dataItems = [newDataItemId];
  286. newSlotMapping.slots.push(newSlot);
  287. },
  288. down: function down(spec) {
  289. return Promise.resolve(spec);
  290. }
  291. });
  292. return new Upgrade();
  293. });
  294. //# sourceMappingURL=multiLayersSupport.js.map