Is it possible to allow the user to visually alter a graph? - d3.js

I created a simple graph (it will become more complex, but for the purpose of this example it will do):
function createGraph(){
var graph = jsnx.Graph();
graph.add_nodes_from([
[1,{color:'red'}],
[2,{color:'green'}],
[3,{color:'blue'}]
]);
graph.add_edges_from([[1,2],[1,3]]);
jsnx.draw(graph,{
element: '#my-canvas',
with_labels: true,
node_style:{
fill: function(d){
return d.data.color;
}
}
});
}
This code successfully draws the graph. Now, I'd like the user to be able to select an edge with the mouse and, when this edge is selected, by pressing the "canc" key the edge should be deleted.
Also, if the user clicks on a node and then drags on another node, he should be able to create an edge.
In short: is d3.js just for visualization or does it allow to visually alter a graph too?

In principle, you can do this with D3 (see here for example). You will however have to implement the functionality that allows the user to change the graph yourself. That is, D3 doesn't provide this functionality out of the box.

Related

D3 Brush Custom Handles null selection visibility

I am trying to figure out how to have custom brush handles highlight data in a range equal to a single value, which seems to result in a null selection.
Here the Plunkr I recreated on one of Mike Bostock's examples. It's in Angular 2/ionic, so if that's an issue, please go here to view his example's plain javascript. The primary thing I edited was commenting out where he hides the custom handles with css when there is a null selection.
if (s == null) {
//handle.attr("display", "none");
//circle.classed("active", false);
}
http://plnkr.co/edit/tRyhlJ
https://bl.ocks.org/mbostock/4349545
If you look in the plunkr example, you can see that if you click and let go the brush is still a perfect sphere, with the line where you clicked. Instead if disappearing, I want the brush handles to stay... and not cause errors when you click to expand the handles.
The error I am currently getting, and can't seem to find a workaround, is this:
How do I gracefully ignore this internal d3 error and continue on letting my selection expand?
I've tried all sorts of things like turning pointer-events off when it's in this state, and manually unhiding/resizing the default handles, to no avail. Every time, when I click the handles I get this error.
As far as I can tell, there's no "clean" way to deal with it. The reason is that a single click defines a range whose size is 0, which the brush considers an empty range (see source) and so it purposely nullifies the selection (see source).
That all means that unless you create your own version of d3-brush to do what you want, there's no way to have an empty selection that's not null nor a way to render a brush for an empty selection.
There's one workaround I can think of: when you detect an empty selection (where s == null) use brush.move to set the selection to something. That something would have to be a range whose size is not 0 (because if you make it 0 then d3, again, would consider that an empty selection and nullify it). To make a non-zero selection that looks like a zero-sized selection (which it has to be, because it's being defined by a single click event) you'd have to make it a tiny selection, eg [123, 123.0001]. Instead of 123, you need to know the mouse position of the click, which you can get using d3.mouse. Putting it all together, it looks like this:
if (s == null) {
var mousex = d3.mouse(this)[0]
gBrush.call(brush.move, [mousex, mousex+.001]);
}

dc.js rowChart - make entire row clickable?

I've got a dc.js rowChart (using the current stable release). It's beautiful. I need it to be more touch-friendly though.
In particular, rows with small values have very tiny bars and are very hard to tap. What I'd like to do it make it such that the user can click anywhere on a row to select/deselect that row rather than having to click directly on the bar.
Is this possible?
As a very hacky solution, I was able to add a bunch of non-breaking spaces after the label and get this effect:
.label(function (d) { return /* your label here */ + new Array(100).join('\xa0'); })
(An invisible element would be better.)

d3 conditional transition of exit and enter selections

I have a stacked bar chart which has time on the x-axis and a count on the y-axis. I have most of the transitions working but there is a scenario where I'm unsure what to do.
If the new data is part of the update selection then I know to grow the bars (as they already exist).
If, if however, the data is part of the enter selection then, depending on where the data is entering, there are two possible transitions:
If the data is newer than the current "end time" then it should slide in from the right, as per this well known tutorial.
If the data is new but older than the current "end time" then a new category should be formed.
The analogous situation occurs in the exit selection.
I am already taking care of #2 above but am having trouble implementing #1. Especially at the same time as #2. It seem to me that I need to inspect the new datum and see where it falls on the chart, probably using the xScale.
How does one run different transitions on the same selection (enter or exit, in this case)?
Here's some pseudo code for what I could imagine for the exit selection:
rects.exit(function () {
if (d.timestamp < that.chartStartTime) {
transitionOffLeftEdge();
} else {
transitionOffBottom();
}
)};

Is there a way to disable mouseover on highcharts entirely?

I'm building a website that uses highcharts. When I view the site on a mobile device, touching within the graph area pops up the tooltip, which prevents scrolling. I have tried all of the following, as suggested in other SO questions, without success:
$('#graph-container').click(function() { return false; });
$('#graph-container').children().click(function() { return false; });
chart.container.onclick = null;
plotOptions: {
series: {
enableMouseTracking: false // (stops tooltip but still blocks scrolling)
}
}
For now I've added a second div that covers the graph on mobile devices, so the user touches the div instead of the graph, but that is more a workaround than a solution. I also tried removing all listeners from every element of the graph using things like $('svg').off() in Chrome's console, without any noticeable change in the graph's behaviour. Is there a way to do this that I'm missing?
Highcharts JS v2.3.5 (2012-12-19)
Little HACK:
edit Line: 9026: this.setDOMEvents();
into: // this.setDOMEvents();
or delete it.
I hope it helped!
Here you can find simple Gist for that.
Also, in upcoming Highcharts 3.0 touch events should be upgraded and fixed similar issues. See roadmap: http://www.highcharts.com/support/roadmap

How to make selection on QGraphicsScene?

I'm writing a diagram editor in Qt with Graphics View Framework.
Currently I'm just trying to create a simple Node (QGraphicsItem) on GraphScene (QGraphicsScene). I created a Canvas (QGraphicsView) and added a grid to it. I can even add Nodes and move them around on scene. My final goal is to have different working modes, editing and styling options, etc. For now I just want to know how can I setup selection for Nodes already present on scene. I tried doing it with mouse events but noticed that event calls for selection and Node insertion overlap... When I try to select something a new Node is created... This is my first Qt application so I don't fully understand how the functionality I want to achieve should be designed.
How the Selection Rectangle should be properly drawn?
How should I manage mouse events that conflict with each other?
You can use a checkable button/action(that's a QPushButton/QAction with a checkable property set to 'true) to switch between Edit & Insert mode. Then you check the state in your mouse event and insert a new item only if you're in Insertion mode.
You can also distinct between mouse buttons - insert item when dragged with the right button for example
Or use QKeyboardModifiers - for example: on drag + Ctrl - insert item.
Hope this helps.
In case of the overlapping mouse events, you should have a single place (like QGraphicsView to handle the mouse clicking/moving events) and create a state machine and then handle the events according to the state you are in. You need to plan your architecture well and that can be really complex task.
set your state enum/constants
refer to the current machine state in your events in your if conditions
keep your "business logic" on a single place
Like it's shown in these two NodeEditor tutorials #11 and #12: https://www.youtube.com/watch?v=pk4v2xuXlm4 and https://www.youtube.com/watch?v=-VYcQojkloE)
If you still want more in depth explanation of the functionality and events of Qt, here is a full list of tutorials with implementing all possible features like dragging edges to nodes, selecting them and deleting them, cutting edges, serialization, etc., you can have a look on the whole list of 50 tutorials I've recorded here: https://www.blenderfreak.com/tutorials/node-editor-tutorial-series/.
I'm putting a link to the whole list, since it's not possible to write all the code on this page...

Resources