DC.js - deselect feature or filter all but the ones that are clicked - charts

I'm not sure if this is possible and no luck on researching this. I'm working on a dashboard using DC.js charts and crossfilter.js. I'm going to use a Row chart as an example. Instead of clicking on the items to filter, is it possible to do that opposite?
For example. When I click on an item from a row chart, instead of filtering on that selected item, it will deselect that item and filter the rest of the other items. And then I will keep clicking on other items to deselect.
Pretty much my goal is to implement a feature where a user can hold the 'CTRL key' and 'left click' the items in the Row Chart to deselect. This way a user dont need to click more than 50+ items in the row chart to filter and have few items not to filter.
I do have a code where Javascript detect an event where "CTRL" and "Left click" triggers. but not sure of how to filter all except the ones that are clicked.
I hope this makes sense. I tried to look at the DC.js or Crossfilter api and I cannot find a function that can do that or am i missing something.

It sounds like you want the same behavior except for the very first click, where you want to keep everything else and remove the clicked item if ctrl is pressed.
If there is anything selected, then a click should toggle as usual, whether or not ctrl is pressed.
As Ethan suggests, you could probably implement this as a filterHandler. That should work too, but since it's mostly the same behavior, I'd suggest using an override of onClick.
Unfortunately the technique for overriding this method is not pretty, but it works!
var oldClick = rowChart.onClick;
rowChart.onClick = function(d) {
var chart = this;
if(!d3.event.altKey)
return oldClick.call(chart, d); // normal behavior if no mod key
var current = chart.filters();
if(current.length)
return oldClick.call(chart, d); // normal behavior if there is already a selection
current = chart.group().all()
.map(kv => kv.key)
.filter(k => k != d.key);
chart.replaceFilter([current]).redrawGroup();
};
I used the alt key instead of ctrl because ctrl-click on Macs is a synonym for right-click.

I'm using this on the rowcharts where I need this feature.
It's a little bit shorter than the other answer, maybe it can be useful to someone (I don't know which is better).
// select only one category at a time
mychart.onClick = function(_chart){ return function (d) {
var filter = _chart.keyAccessor()(d);
dc.events.trigger(function () {
_chart.filter(null);
_chart.filter(filter);
_chart.redrawGroup();
});
}; }(mychart)
Where mychart is the name of your dc.rowchart
var mychart = dc.rowChart('#mychart');
[EDIT]
This one works too, is shorter, and works with barcharts
mychart.addFilterHandler(function (filters, filter) {
filters.length = 0; // empty the array
filters.push(filter);
return filters;
});

Related

Is there a way to highlight a specific item in the search results?

I have been trying to implement a slight change in the behavior of the chosen dropdown search results, but there doesn't seem to be any straightforward way to get at them. I have a list of countries preceded by three-letter ISO country code. I would like to be able to search as usual, but highlight the country if there is an exact match on the country code. The problem is that the matching country code will not always be the first item in the list. A more general request would be able to access the result list, and set the selection to some item other than the first.
By inspection, it looks to me like the search results only exist as a jquery object and within that the list items include a data-option-array-index with the original option list index, so I could find the item that I know I want highlighted in that DOM object and set the class "highlighted". But I also might need to scroll it into view, and messing with the underlying DOM directly is not ideal, so it would really be nice to have access to Chosen functions that would do that.
So, I figured it out, by accessing DOM. I have the index in the initial array that I want to highlight, and the following code will do it, assuming it is in the result list (using lodash _.find):
var highlightChosenResult = function(index) {
var resultList = $('li.active-result');
var result = _.find(resultList, function(el) {
return +$(el).attr('data-option-array-index') === index;
});
if (result) {
this.chosenApi.result_do_highlight($(result));
}
}

How to select a treeItem in a treeView, after checking a Condition on that treeItem, in Javafx

I have downloaded familyTree project and it doesn't have the ability to search for an specific family member!
I have added a search button to it, and in the handler method section, I need the code that searches for a member that has the specified socialID , and select it (scroll it to the sight, and make it blue (selected)). But I don't know how to programmatically select a treeItem, and make it visible and selected?
My code:
#FXML
private void btnSearch_click(ActionEvent event){
for(TreeItem<FamilyMember> treeItem:root.getChildren()){
if(treeItem.getValue().getNationality().toString()=="22"){
// treeView.setSelectionModel(item);
treeView.getSelectionModel().select(treeItem);
//it still doesnt select the item with nationality=="22"
break;
}
}
}
You can select the item with
treeView.getSelectionModel().select(item);
and if you still need to scroll (I think selecting it might automatically scroll to it), do
treeView.scrollTo(treeView.getRow(item));
A couple of notes:
I do not understand the for loop. Why are you doing
TreeItem<FamilyMember> item = root.getChildren().get(i);
and why are you creating the index i? What is wrong with the treeItem variable you already defined in the loop syntax? Isn't this necessarily exactly the same thing as item?
You need to read How do I compare strings in Java?

Ag-Grid expand row

Im using Ag-grid to control my table, but i want in my group that stores a list of rows instead of having to make the row group expand in 2 clicks, i want to be on 1 click.
If i click on the icon arrow it works, but if i click on the title row it only opens on 2 clicks.
I already tried to find in the documentation any information about it, but cant find nothing.
Here is a example from the documentation.
https://ag-grid.com/javascript-grid-tree/index.php
example image:
We are now recommended not to use the onGroupExpandedOrCollapsed, so this should now be...
This will also update the icons and animate the rows, which onGroupExpandedOrCollapsed won't.
onRowClicked(params) {
params.node.setExpanded(!params.node.expanded);
}
This will toggle the expansion, use params.node.setExpanded(true) if you want the rows to just stay open.
You can listen to events on either a row or cell clicked, and expand nodes accordingly.
For example to expand a row based on a click you could do the following:
onRowClicked: (params) => {
// update the node to be expanded
params.node.expanded = true;
// tell the grid to redraw based on state of nodes expanded state
gridOptions.api.onGroupExpandedOrCollapsed(params.rowIndex)
}
This should be in the documentation - I'll update it to reflect this information.
In the column definition, you can use the onCellClicked(params) function to tell it to do something when the cell is clicked. I tried looking for an expand function, but I could only find expandAll() which I don't think you will want. So what I would do is just use jquery or simple DOM selection to click on the expand icon inside of that cell.
this one works
onRowClicked(params) {
params.context.setExpand.onExpandClicked(params.rowIndex, params.node.rowHeight);
}

ag-grid: Using Drag drop to reorder rows within the grid

I need to re-order rows within ag-grid by using drag-drop. The drag drop methods are simple enough but when the drop occurs there seems no easy way to switch the rows locations.
I attempted a
gridOptions.api.removeItems(selectedNode);
to clear the current and then
gridOptions.api.insertItemsAtIndex(2, savedNode);
but the drop event appeared to re-fire preventing that approach. Plus the insertItems (when ran first) falls over in internal ag-grid looping.
I would rather not re-sort the gridRows manually and then reset the gridRow data which would be somewhat clunky. This seems a common request on most grids so i assume it can be done but have just missed the relevant documentation. Thanks for any help..
K have finally got an Angular 2 method working, though currently I have to switch off sorting and filtering on the grid.
This particular example is relying on row selection being enabled (due to how it is finding some records). Grid dragdrop should be disabled (as that drags the grid visually which sucks) Instead use a processRowPostCreate to set up draggable params at the row level. This sets the dragged option to the row which looks much nicer.
in gridOptions
processRowPostCreate: (params) => {
this.generateRowEvents(params);
},
which calls
private generateRowEvents(params) {
params.eRow.draggable = true;
params.eRow.ondragstart = this.onDrag(event);
params.eRow.ondragover = this.onDragOver(event);
params.eRow.ondrop = this.onDrop(event);
}
I track the source recrord in the onDrag method
var targetRowId: any = $event.target.attributes.row.value;
this.savedDragSourceData = targetRowId;
onDragOver as usual
On drop we have to protect against an infinite loop (ag-grid appears to recall live methods when items are added to the grid hence the ondrop occurs multiple times) and then insert, delete and splice over both the grid and its data source ( I will carry on looking at using the grid to populate the data as opposed to the source data as that would allow source/filter, currently doign that inserts blank rows). An event (in this case) is then emitted to ask the owning component to 'save' the adjusted data.
private onDrop($event) {
if ($event && !this.infiniteLoopCheck) {
if ($event.dataTransfer) {
if (this.enableInternalDragDrop) {
this.infiniteLoopCheck= true;
var draggedRows: any = this.gridRows[this.savedDragSourceData];
// get the destination row
var targetRowId: any = $event.target.offsetParent.attributes.row.value;
// remove from the current location
this.gridOptions.api.removeItems(this.gridOptions.api.getSelectedNodes());
// remove from source Data
this.gridRows.splice(this.savedDragSourceData, 1);
if (draggedRows) {
// insert into specified drop location
this.gridOptions.api.insertItemsAtIndex(targetRowId, [draggedRows]);
// re-add rows to source data..
this.gridRows.splice(targetRowId, 0, checkAdd);
this.saveRequestEvent.emit(this.gridRows);// shout out that a save is needed }
this.v= false;
}
else {
this.onDropEvent.emit($event);
}
}
}
}
NOTE we are wrapping the grid in our own class to allow us to write one set of grid methods and not replicate over the application whenever the grid is used.
I will be refining this over the next few days but as a basic this allows the ag-grid in angular 2 to drag drop rows to sort records.
If you don't find a solution within ag-grid then you can do this by adding one more directive("ngDraggable") and integrate it with ag-grid.
Please find the following working plnkr for this.
https://embed.plnkr.co/qLy0EX/
ngDraggable
Hope this helps..

Fancybox and Isotope sort and update gallery order

Using the jQuery Fancybox plugin with Isotope, I'm trying to figure out how to update the Fancybox gallery order in lightbox view after I change the Isotope sort by options.
When I re-sort the images I need to be able to tell Fancybox what the new order is, so that when I navigate between images in lightbox view it goes to the next image in the newly sorted order. Right now the next/previous buttons take you to the next/previous image in the original sort order.
Any help is much appreciated.
With reference to this page, the relevant part looks something like this...
$('.option-set').change(function() {
var $this = $(this);
var delay = 1100; // approx 1 second delay after last input
clearTimeout($this.data('timer'));
$this.data('timer', setTimeout(function(){
$this.removeData('timer');
$('a[rel^="lightbox"]').each(function() {
var opacity = $(this).parent().css("opacity");
$(this).attr('rel','lightbox['+opacity+']');
});
Shadowbox.clearCache();
Shadowbox.setup();
}, delay));
});
It's a hack of course. Whenever one of the checkboxes is changed, this routine waits a bit to let isotope do its thing and then updates all 'rels' to correspond to the opacity of their respective parents. So there will actually be two sets of rels (lightbox[0] and lightbox[1]). But because there is no visible thumbnail for lightbox[0], those images are in effect removed from the lightbox/shadowbox.
I came across the same problem and looked around to find a solution and stumbled upon this as well. As I couldn't find a solution, I thought I'd try it myself and the solution was simple. Not sure if this has an affect on performance of the browser, but simple DOM manipulation will give you the required behavior. I'm using isotope V2 and events in this version is a bit different to that in V1. Fancybox version shouldn't matter.
First you have to make sure you have set isInitLayout: false when initializing isotope.
var $container = $("#isotopeContainer");
$container.isotope({
//other options
isInitLayout: false
});
After that, you have to bind to the layoutComplete event on your isotope container.
$container.isotope('on', 'layoutComplete', function(isoInstance, laidOutItems) {
var $firstItem = laidOutItems[0].element;
$($firstItem).prependTo(isoInstance.element);
var $lastMovedItem = $firstItem,$nextItem;
for (var i = 0; i < laidOutItems.length; i++) {
$nextItem = laidOutItems[i].element;
if ($nextItem != $firstItem) {
$($nextItem).insertAfter($lastMovedItem);
$lastMovedItem = $nextItem;
}
}
});
As you set isInitLayout to false while initializing isotope, you have to call the arrange method manually to lay it all out properly.
$container.isotope('arrange');
I'm pretty sure there is room for improvement. But I'm happy with this solution.
Hope someone will find this useful.
Came across the exact same issue tonight!
I suggest re-ordering the order of your griditems in javascript, before you call the isotope function, that way, all your items will already be in the correct order and any lightbox plugin won't get confused :)
(like this for example: jquery sort list based on data attribute value)
Hope I helped someone ;-) Worked like a charm for me :-)