Skip to content

Commit

Permalink
Add a search bar to the controllers (#735)
Browse files Browse the repository at this point in the history
* WIP for search bar for categories in view controllers

* Make the searchbar look less awful

* Improve the order of the searchbar

* ENH: Add searchbar to attribute view controller

* break long line

* TST: Add tests for searchbar functionality

Fixes #710

* STY: Small cleanup

* Make searchbar available for continuous values and remove new line

* BUG: Fix "results not found" position

The legend would cover the checkbox for continuous values.

* ENH: Hide searchbar while controller is disabled

* BUG: Fix issue with "No results found" message

Fixes an extraneous tooltip (for the plotMenu) would erroneously show on
screen. We change the context where the tooltip exists and limit it to
be the search bar only.
  • Loading branch information
ElDeveloper authored and antgonza committed Oct 22, 2019
1 parent 5d4dde0 commit 886e42c
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 62 deletions.
12 changes: 8 additions & 4 deletions emperor/support_files/js/color-view-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,14 @@ define([
attributes, scope.setPlottableAttributes, category);

if (scaled) {
scope.$searchBar.prop('hidden', true);
plottables = ColorViewController._nonNumericPlottables(
uniqueVals, data);
// Set SlickGrid for color of non-numeric values and show color bar
// for rest if there are non numeric categories
if (plottables.length > 0) {
scope.setSlickGridDataset(
[{category: 'Non-numeric values', value: '#64655d',
[{id: 0, category: 'Non-numeric values', value: '#64655d',
plottables: plottables}]);
}
else {
Expand All @@ -156,6 +157,7 @@ define([
scope.$colorScale.html(colorInfo[1]);
}
else {
scope.$searchBar.prop('hidden', false);
scope.setSlickGridDataset(data);
scope.$scaleDiv.hide();
}
Expand All @@ -181,7 +183,8 @@ define([
var ready = this.ready;
this.ready = undefined;

this.$header.append(this.$colormapSelect);
// account for the searchbar
this.$colormapSelect.insertAfter(this.$select);
this.$header.append(this.$scaled);
this.$header.append(this.$scaledLabel);
this.$body.prepend(this.$scaleDiv);
Expand Down Expand Up @@ -267,7 +270,8 @@ define([
*/
ColorViewController.prototype.isColoringContinuous = function() {
// the bodygrid can have at most one element (NA values)
return this.$scaled.is(':checked') && this.bodyGrid.getData().length <= 1;
return (this.$scaled.is(':checked') &&
this.getSlickGridDataset().length <= 1);
};

/**
Expand Down Expand Up @@ -510,7 +514,7 @@ define([
var decompViewDict = this.getView();
if (this.$scaled.is(':checked')) {
// Get the current SlickGrid data and update with the saved color
data = this.bodyGrid.getData();
data = this.getSlickGridDataset();
data[0].value = json.data['Non-numeric values'];
this.setPlottableAttributes(
decompViewDict, json.data['Non-numeric values'], data[0].plottables);
Expand Down
8 changes: 4 additions & 4 deletions emperor/support_files/js/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,11 @@ define([
name: 'Open in Vega Editor',
callback: function(key, opts) {
scope.exportToVega();
},
}
}
}
},
},
}
}
});

// The context menu is only shown if there's a single right click. We
Expand Down Expand Up @@ -998,7 +998,7 @@ define([
var payload = {
mode: 'vega',
renderer: 'canvas',
spec: JSON.stringify(spec),
spec: JSON.stringify(spec)
};
_postMessage(url, payload);
};
Expand Down
2 changes: 1 addition & 1 deletion emperor/support_files/js/sceneplotview3d.js
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ define([
return;
}

var element = this.renderer.domElement;
var element = this.renderer.domElement, scope = this;
var offset = $(element).offset();
this._mouse.x = ((event.clientX - offset.left) / element.width) * 2 - 1;
this._mouse.y = -((event.clientY - offset.top) / element.height) * 2 + 1;
Expand Down
79 changes: 72 additions & 7 deletions emperor/support_files/js/view-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,31 @@ define([
this.$select = $('<select>');
this.$header.append(this.$select);

this.$searchBar = $("<input type='search' " +
"placeholder='Search for a value ...'>"
).css({
'width': '100%'
});
this.$header.append(this.$searchBar);

// there's a few attributes we can only set on "ready" so list them up here
$(function() {
scope.$searchBar.tooltip({
content: 'No results found!',
disabled: true,
// place the element with a slight offset at the bottom of the input
// so that it doesn't overlap with the "continuous values" elements
position: {my: 'center top+40', at: 'center bottom',
of: scope.$searchBar},
// prevent the tooltip from disappearing when there's no matches
close: function(event, ui) {
if (scope.bodyGrid.getDataLength() === 0 &&
scope.$searchBar.val() !== '') {
scope.$searchBar.tooltip('open');
}
}
});

var placeholder = 'Select a ' + scope.title + ' Category';

// setup the slick grid
Expand Down Expand Up @@ -308,7 +331,7 @@ define([
* displayed by the body grid.
*/
EmperorAttributeABC.prototype.getSlickGridDataset = function() {
return this.bodyGrid.getData();
return this.bodyGrid.getData().getItems();
};

/**
Expand All @@ -326,9 +349,9 @@ define([
}

// Re-render
this.bodyGrid.setData(data);
this.bodyGrid.invalidate();
this.bodyGrid.render();
this.bodyGrid.getData().beginUpdate();
this.bodyGrid.getData().setItems(data);
this.bodyGrid.getData().endUpdate();
};

/**
Expand All @@ -340,7 +363,7 @@ define([
*
*/
EmperorAttributeABC.prototype._buildGrid = function(options) {
var columns = [{id: 'field1', name: '', field: 'category'}];
var columns = [{id: 'field1', name: '', field: 'category'}], scope = this;

// autoEdit enables one-click editor trigger on the entire grid, instead
// of requiring users to click twice on a widget.
Expand All @@ -353,12 +376,52 @@ define([
columns.unshift(options.slickGridColumn);
}

var dataView = new Slick.Data.DataView(), searchString = '';

/**
* @type {Slick.Grid}
* Container that lists the metadata categories described under the
* metadata column and the attribute that can be modified.
*/
this.bodyGrid = new Slick.Grid(this.$gridDiv, [], columns, gridOptions);
this.bodyGrid = new Slick.Grid(this.$gridDiv, dataView, columns,
gridOptions);

this.$searchBar.on('input', function(e) {
dataView.refresh();

// show a message when no results are found
if (scope.bodyGrid.getDataLength() === 0 &&
scope.$searchBar.val() !== '') {
scope.$searchBar.tooltip('option', 'disabled', false);
scope.$searchBar.tooltip('open');
}
else {
scope.$searchBar.tooltip('option', 'disabled', true);
scope.$searchBar.tooltip('close');
}

});

function substringFilter(item, args) {
var val = scope.$searchBar.val();
if (!searchString && val &&
item.category.toLowerCase().indexOf(val.toLowerCase()) === -1) {
return false;
}
return true;
}

dataView.onRowCountChanged.subscribe(function(e, args) {
scope.bodyGrid.updateRowCount();
scope.bodyGrid.render();
});

dataView.onRowsChanged.subscribe(function(e, args) {
scope.bodyGrid.invalidateRows(args.rows);
scope.bodyGrid.render();
});

dataView.setFilter(substringFilter);

// hide the header row of the grid
// http://stackoverflow.com/a/29827664/379593
Expand Down Expand Up @@ -402,7 +465,7 @@ define([
json.category = this.getMetadataField();

// Convert SlickGrid list of objects to single object
var gridData = this.bodyGrid.getData();
var gridData = this.getSlickGridDataset();
var jsonData = {};
for (var i = 0; i < gridData.length; i++) {
jsonData[gridData[i].category] = gridData[i].value;
Expand Down Expand Up @@ -488,6 +551,8 @@ define([

this.$select.prop('disabled', !trulse).trigger('chosen:updated');
this.bodyGrid.setOptions({editable: trulse});
this.$searchBar.prop('disabled', !trulse);
this.$searchBar.prop('hidden', !trulse);
};

/**
Expand Down
56 changes: 29 additions & 27 deletions emperor/support_files/js/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ DecompositionView.prototype.flipVisibleDimension = function(index) {
DecompositionView.prototype.setCategory = function(attributes,
setPlottableAttributes,
category) {
var scope = this, dataView = [], plottables;
var scope = this, dataView = [], plottables, i = 0;

_.each(attributes, function(value, key) {
/*
Expand All @@ -610,7 +610,9 @@ DecompositionView.prototype.setCategory = function(attributes,
setPlottableAttributes(scope, value, plottables);
}

dataView.push({category: key, value: value, plottables: plottables});
dataView.push({id: i, category: key, value: value,
plottables: plottables});
i = i + 1;
});
this.needsUpdate = true;

Expand Down Expand Up @@ -869,7 +871,7 @@ DecompositionView.prototype._buildVegaSpec = function() {
Ring: 'circle',
Square: 'square',
Icosahedron: 'cross',
Star: 'cross',
Star: 'cross'
};

function viewMarkersAsVegaDataset(markers) {
Expand All @@ -884,8 +886,8 @@ DecompositionView.prototype._buildVegaSpec = function() {
color: rgbColor(marker.material.color),
originalShape: marker.userData.shape,
shape: getShape[marker.userData.shape],
scale: { x: marker.scale.x, y: marker.scale.y, },
opacity: marker.material.opacity,
scale: { x: marker.scale.x, y: marker.scale.y },
opacity: marker.material.opacity
});
}
}
Expand Down Expand Up @@ -924,14 +926,14 @@ DecompositionView.prototype._buildVegaSpec = function() {
padding: 5,
background: scope.backgroundColor,
config: {
axis: { labelColor: scope.axesColor, titleColor: scope.axesColor, },
title: { color: scope.axesColor, },
axis: { labelColor: scope.axesColor, titleColor: scope.axesColor },
title: { color: scope.axesColor }
},
title: 'Emperor PCoA',
data: [
{
name: 'metadata',
values: plottablesAsMetadata(model.plottable, model.md_headers),
values: plottablesAsMetadata(model.plottable, model.md_headers)
},
{
name: 'points', values: viewMarkersAsVegaDataset(scope.markers),
Expand All @@ -941,48 +943,48 @@ DecompositionView.prototype._buildVegaSpec = function() {
from: 'metadata',
key: model.md_headers[0],
fields: ['id'],
as: ['metadata'],
as: ['metadata']
}
],
},
]
}
],
signals: [
{
name: 'width',
update: baseWidth + ' * ((' + rangeX[1] + ') - (' + rangeX[0] + '))',
update: baseWidth + ' * ((' + rangeX[1] + ') - (' + rangeX[0] + '))'
},
{
name: 'height',
update: baseWidth + ' * ((' + rangeY[1] + ') - (' + rangeY[0] + '))',
},
update: baseWidth + ' * ((' + rangeY[1] + ') - (' + rangeY[0] + '))'
}
],
scales: [
{ name: 'xScale', range: 'width', domain: [rangeX[0], rangeX[1]] },
{ name: 'yScale', range: 'height', domain: [rangeY[0], rangeY[1]] }
],
axes: [
{ orient: 'bottom', scale: 'xScale', title: model.axesLabels[axisX], },
{ orient: 'left', scale: 'yScale', title: model.axesLabels[axisY], }
{ orient: 'bottom', scale: 'xScale', title: model.axesLabels[axisX] },
{ orient: 'left', scale: 'yScale', title: model.axesLabels[axisY] }
],
marks: [
{
type: 'symbol',
from: {data: 'points'},
encode: {
enter: {
fill: { field: 'color', },
x: { scale: 'xScale', field: 'x', },
y: { scale: 'yScale', field: 'y', },
shape: { field: 'shape', },
size: { signal: 'datum.scale.x * datum.scale.y * 100', },
opacity: { field: 'opacity', },
fill: { field: 'color' },
x: { scale: 'xScale', field: 'x' },
y: { scale: 'yScale', field: 'y' },
shape: { field: 'shape' },
size: { signal: 'datum.scale.x * datum.scale.y * 100' },
opacity: { field: 'opacity' }
},
update: {
tooltip: { signal: 'datum.metadata' },
},
},
},
],
tooltip: { signal: 'datum.metadata' }
}
}
}
]
};
};

Expand Down
4 changes: 3 additions & 1 deletion emperor/support_files/templates/logic-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
'slickgrid': '{{ base_url }}/vendor/js/slick.grid.min',
'slickformatters': '{{ base_url }}/vendor/js/slick.editors.min',
'slickeditors': '{{ base_url }}/vendor/js/slick.formatters.min',
'slickdataview': '{{ base_url }}/vendor/js/slick.dataview.min',

/* Emperor's objects */
'util': '{{ base_url }}/js/util',
Expand Down Expand Up @@ -94,7 +95,8 @@
'deps': ['blob']
},
'slickcore': ['jqueryui'],
'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters', 'slickeditors']
'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters', 'slickeditors',
'slickdataview']
}
});

Expand Down
1 change: 1 addition & 0 deletions emperor/support_files/vendor/js/slick.dataview.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion tests/javascript_tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
'slickgrid': './vendor/js/slick.grid.min',
'slickformatters': './vendor/js/slick.editors.min',
'slickeditors': './vendor/js/slick.formatters.min',
'slickdataview': './vendor/js/slick.dataview.min',

/* Emperor's objects */
'animationdirector': './js/animate',
Expand Down Expand Up @@ -147,7 +148,7 @@
},
'slickcore': ['jqueryui'],
'slickgrid': ['slickcore', 'jquery_drag', 'slickformatters',
'slickeditors']
'slickeditors', 'slickdataview']
}
});

Expand Down
Loading

0 comments on commit 886e42c

Please sign in to comment.