      1 define([
      2     'jquery',
      3     'underscore',
      4     'viewcontroller',
      5     'shape-editor',
      6     'shapes'
      7 ], function($, _, ViewControllers, Shape, shapes) {
      8
      9   // we only use the base attribute class, no need to get the base class
     10   var EmperorAttributeABC = ViewControllers.EmperorAttributeABC;
     11   var ShapeEditor = Shape.ShapeEditor;
     12   var ShapeFormatter = Shape.ShapeFormatter;
     13   /**
     14    * @class ShapeController
     15    *
     16    * Manipulates and displays the shape of objects on screen.
     17    *
     18    * @param {UIState} uiState The shared state
     19    * @param {Node} container Container node to create the controller in.
     20    * @param {Object} decompViewDict This is object is keyed by unique
     21    * identifiers and the values are DecompositionView objects referring to a
     22    * set of objects presented on screen. This dictionary will usually be shared
     23    * by all the tabs in the application. This argument is passed by reference.
     24    * Note that only the decompositions of type 'scatter' will be controlled,
     25    * other types will be ignored.
     26    *
     27    * @return {ShapeController} An instance of ShapeController
     28    * @constructs ShapeController
     29    * @extends EmperorAttributeABC
     30    */
     31   function ShapeController(uiState, container, decompViewDict) {
     32     var helpmenu = 'Change the shapes representing groups of data on the plot';
     33     var title = 'Shape';
     34
     35     // Constant for width in slick-grid
     36     var SLICK_WIDTH = 100, scope = this;
     37     var name, value, shapeItem;
     38
     39     // Build the options dictionary
     40     var options = {
     41       'valueUpdatedCallback': function(e, args) {
     42         var val = args.item.category, shape = args.item.value;
     43         var group = args.item.plottables;
     44         var element = scope.getView();
     45         scope.setPlottableAttributes(element, shape, group);
     46       },
     47       'categorySelectionCallback': function(evt, params) {
     48         var category = scope.$select.val();
     49
     50         var decompViewDict = scope.getView();
     51
     52         // getting all unique values per categories
     53         var uniqueVals = decompViewDict.decomp.getUniqueValuesByCategory(
     54           category);
     55
     56         // Reset all to shapes to default
     57         var attributes = {};
     58         for (var index in uniqueVals) {
     59           attributes[uniqueVals[index]] = 'Sphere';
     60         }
     61         // fetch the slickgrid-formatted data
     62         var data = decompViewDict.setCategory(
     63           attributes, scope.setPlottableAttributes, category);
     64
     65         scope.setSlickGridDataset(data);
     66       },
     67       'slickGridColumn': {
     68         id: 'title', name: '', field: 'value',
     69         sortable: false, maxWidth: SLICK_WIDTH, minWidth: SLICK_WIDTH,
     70         editor: ShapeEditor,
     71         formatter: ShapeFormatter
     72       }
     73     };
     74
     75     // shapes are only supported for scatter types
     76     var reshapeable = {};
     77     for (var key in decompViewDict) {
     78       if (decompViewDict[key].decomp.isScatterType()) {
     79         reshapeable[key] = decompViewDict[key];
     80       }
     81     }
     82
     83     EmperorAttributeABC.call(this, uiState, container, title, helpmenu,
     84                              reshapeable, options);
     85     return this;
     86   }
     87
     88   ShapeController.prototype = Object.create(EmperorAttributeABC.prototype);
     89   ShapeController.prototype.constructor = EmperorAttributeABC;
     90
     91   /**
     92    *
     93    * Private method to reset the shape of all the objects to spheres.
     94    *
     95    * @extends EmperorAttributeABC
     96    * @private
     97    *
     98    */
     99   ShapeController.prototype._resetAttribute = function() {
    100     EmperorAttributeABC.prototype._resetAttribute.call(this);
    101     var scope = this;
    102
    103     _.each(this.decompViewDict, function(view) {
    104       scope.setPlottableAttributes(view, 'Sphere', view.decomp.plottable);
    105       view.needsUpdate = true;
    106     });
    107   };
    108
    109   /**
    110    * Helper function to set the shape of plottable
    111    *
    112    * @param {Object} scope The scope where the plottables exist
    113    * @param {string} shape String representation of the shape to be applied
    114    * to the plottables.
    115    * @param {Object[]} group Array of objects that should be changed in scope
    116    */
    117   ShapeController.prototype.setPlottableAttributes =
    118       function(scope, shape, group) {
    119
    120     if (scope.UIState['view.viewType'] == 'parallel-plot')
    121       return;
    122
    123     var idx, factor = scope.getGeometryFactor();
    124
    125     // get the appropriately sized geometry
    126     var geometry = shapes.getGeometry(shape, factor);
    127
    128     if (geometry === undefined) {
    129       throw new Error('Unknown shape ' + shape);
    130     }
    131
    132     _.each(group, function(element) {
    133       idx = element.idx;
    134       scope.markers[idx].geometry = geometry;
    135       scope.markers[idx].userData.shape = shape;
    136     });
    137     scope.needsUpdate = true;
    138   };
    139
    140   return ShapeController;
    141 });
    142