How do I prevent nodes in a graph from stacking on each other? I want there to be a minimum distance between nodes and if someone was to drag a node over another the graph throws an error to the user. I saw this solution and tried it but it doesnt work Prevent node overlap in JGraphX
I'll appreciate any ideas.
For rearranging your diagram automatically with some distance between them you can try to use something like this:
let layout = new mxHierarchicalLayout(this.graph, mxConstants.DIRECTION_WEST);
layout.intraCellSpacing = 50; //horizontal
layout.interRankCellSpacing = 200; //vertical
layout.execute(this.parent);
The mxHierarchicalLayout method will automatically rearrange your current nodes. The other two settings will give spacing between them ( horizontally and vertically )
Also, run this before rendering the screen or if you want to change after the display has already rendered, just this.graph.refresh() if needed
Related
I am using chart.js to try to create a timeline of events relative to current date.
The horizontal bar chart is close but would like to show only the tips of the bars eg as points which would pretty much be a horizontal line chart.
I have shown my horizontal bar chart along with a mock-up of what it would look like as horizontal line chart.
Is this possible with chart.js ?
You first need to know that every information that you can edit about the chart is stored in the variable containing your chart (called myChart usually, but my2Bar in your fiddle).
If you want to globally change the graph, you will need to edit attributes in myChart.config.options.
If you want to change a specific chart, you will need to edit attributes in myChart.config.data.
In this case, you need to change a specific chart (which is the horizontal bar).
If you happen to check the logs of your graph, and go very deep in the config, you will finally see that bars in your chart are drawn using attributes stored in myChart.config.data.datasets[0]._meta[0].data[n]._model (n being the nth rectangle drawn, top to bottom).
Some attributes you can find there :
base : The X position where the rectangle is starting to be drawn (0 in your xAxe for instance).
x : The rectangle is being drawn until this X position.
height : The height of the drawn rectangle.
and so on ...
To edit these values, you just need to loop in your different rectangles (the n in the above path).
But you just can't do it manually on the config of your variable. If you do this, it won't work since your chart is responsive (on resize, it will redraw the chart using the former options).
What you must use are Chart.js plugins.
Plugins let you handle all the events that are triggered while creating, updating, rendering your graph.
Then, in your beforeRender event (triggered after the initialisation, but before the drawing), you need to loop in your different rectangles to edit the values to affect how they will be drawn :
beforeRender: function(chart) {
for (var i = 0; i < chart.config.data.datasets[0]._meta[0].data.length; i++) {
// Change both `3` values to change the height & width of the point
chart.config.data.datasets[0]._meta[0].data[i]._model["base"] = chart.config.data.datasets[0]._meta[0].data[i]._model["x"] + 3;
chart.config.data.datasets[0]._meta[0].data[i]._model["height"] = 3;
}
}
Here is a jsFiddle with the final result.
Unfortunately, I wasn't able to make round dots, instead of squared ones.
Update :
I have also made another jsFiddle where all the dots are linked together which makes it look like it is a horizontal line chart (can be improved of course, but it is a good start).
This is in response to the following question, How to remove padding in c3.js?, where the answer that was provided solves this issue, but also raises another issue -- the buttons on the graph are cut off at the end --
How would I get there to be no padding and the buttons not to be cut off, for example, it should look like:
The dots are getting clipped off because of the clip-path set on the chart layer. You just have to remove it. You can use D3 for this, like so
d3.select(chart.element).select("." + c3.chart.internal.fn.CLASS.chart).attr("clip-path", null);
where chart is your C3 chart object
Fiddle - http://jsfiddle.net/zds67nh1/
However you most probably want the dots to appear above the axis layer. For that you need to detach and attach the chart layer (in SVG, the z-index is determined by the order - the last of the siblings come on top. So you have to basically move it to the end of the siblings list), like so
var chartLayer = d3.select(chart.element).select("." + c3.chart.internal.fn.CLASS.chart);
var chartLayerParentNode = chartLayer.node().parentNode;
var chartLayerNode = chartLayer.remove();
chartLayerParentNode.appendChild(chartLayerNode.node());
chartLayer.attr("clip-path", null);
Fidle - http://jsfiddle.net/7e1eL22f/
I have a mathematical problem that I am trying to solve and want to realize in javascript.
I have a "space" meaning: a rectangular format. This shall work as a kind of container.
Then I have smaller forms: other rectangular ones and circles.
I need to find out a solution how to calculate how many of these forms fit into the container.
So I kind of need the ideal way, how to stack these items in there.
If it is too many, leaving out some. And if it is too few, stacking them from bottom up.
I am trying to realize this in Javascript but not getting far.
From my vision it should be kind of like this:
var items = [circle1,2],[rect1,2,4],[rect2,5,6]]; // array with the forms to put inside container, stating a radius for circle and width/height for rectangles
var container = [10, 4]; // given the size of the container in width and height.
function stackItIn (container, items){
// now this is where I am totally lost
}
The premium part would be even showing it graphically at the end.
Any help would be appreciated!
Thank you!
You can try a treemap. Sort the tiles and pick the first and create a node in a tree. Split the tree on both axis and pick the next tile and find the best fit of the nodes.
I have use the d3.js to visualize my data. And the result like this.
PIC_1
PIC_2
My question is how can I make the data present like PIC_1,the center point local in the fixed position,and the other points (children points) around the center point like a circle.
Now,when I refresh the page the data will reload in the brower and all the points' position will randomly change as well.
So which d3's api or tricks can be used to this purpose. :)
Take a look at this example:
link to jsfiddle
If you exampne the code, and play with layout, you'll see that the root node has special treatment that makes it always remain in the center of the graph (unless you drag it, but even that you can prevent if you want).
On initialization, its property fixed is set to true, so that d3 force layout simulation doesn't move it. Also, it is placed in the center of rectangle containing layout:
root.fixed = true;
root.x = width / 2;
root.y = height / 2;
You ofcourse need to change or add some code in order to integrate this feature to your example, but the core idea is really clear from the example I linked.
Hope this helps. Let me know if you have a question, need a clarification, etc.
I want to create a jqPlot line chart which has the ability to change orientation between vertical and horizontal orientation. I was able to achieve this using CSS rules, by rotating the div element containing the chart.
My work up to now: http://jsfiddle.net/GayashanNA/A4V4y/14/
But the problem is I also want to track the mouse-pointer and mouse clicks on points on chart after the orientation is flipped because i want to annotate those points. I am unable to do this when the chart is in vertical orientation. Can anyone suggest a method to do this? Or am i approaching the problem in a wrong way?
(Note: I am able to do this in horizontal orientation, you can observe it if you try to click on a point on the above chart.)
Thanks and help is much appreciated.
I've never used jqPlot, but I guess your problem is trying to use css rotate(), since the cursor plugin is using the mouse position to determine where to draw the lines, and element's size doesn't change when transformed by rotate(), it still have the same width and height values.
If you take a look at the code, you will see:
if (c.showVerticalLine) {
c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]);
}
if (c.showHorizontalLine) {
c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]);
}
So it seems like the library is always drawing the lines based on mouse position over the original element, which of course, won't match the position after being transformed by rotate(), and XY coordinates are going to be transformed to YX after rotate().
I would try to change the size of your original element, though I don't know if the library lets you specify in which sides are the labels going to be drawn.
I finally found a solution for the problem. But i had to change jqPlot library to achieve this. To help anyone else who run in to the same problem, i'll put my solution here.
First i had to insert the following code in to the jqPlot class of the jquery.jqplot.js file, which is the core library.
function jqPlot() {
//add the following code segment
var verticallyOriented = false;
this.setVertical = function(state){
verticallyOriented = state;
}
//don't change other code that isn't mentioned here
//now you have to change the logic in the getEventPosition function
//to make sure the new orientation is detected
function getEventPosition(ev) {
//change the line starting with var gridPos = ...
//to the following code segment
//depending on the orientation the event position calculating algorithm is changed
if(verticallyOriented){
var gridPos = {x:ev.pageY - go.top , y:plot.eventCanvas._elem.height() - ev.pageX + go.left};
} else {
var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top};
}
//no change to other code is needed
}
}
You can view a working example here: http://jsfiddle.net/GayashanNA/yZwxu/
Gist for the changed library file: https://gist.github.com/3755694
Please correct me if i have done something wrong.
Thanks.