When using mxHierarchicalLayout together with strokeWidth > 1 borders for all topmost and leftmost vertexes will be displayed incorrectly. See the screenshot below:
That is because border width doesn't count to total vertex height/width.
Is there a possibility to set box sizing model for mxGraph the same way box-sizing: border-box; works for CSS?
If no, is it possible to move entire graph context downward or leftward after it has been laid by layout engine?
I think that the borders are drawn correctly but the problem is that the leftmost and topmost vertices' borders get hidden because they are placed "behind" the canvas, so a workaround would be to move your whole graph a little to the bottom and to the right dependening on your needs. Code to do this:
let layout = new mxHierarchicalLayout(graph);
layout.execute(graph.getDefaultParent());
graph.model.beginUpdate();
let children = graph.getChildCells();
graph.moveCells(children, undefined , 20); // assuming you want to "move your graph 20px to the bottom"
graph.model.endUpdate();
You can use the same function to move horizontally your graph (left-right), check the
moveCells function of mxGraph.js
mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt, mapping)
Related
I'm making a diagramming library in Blazor which uses HTML nodes and SVG links. I am wondering how can I draw links between two nodes when they aren't always rectangular.
All the solutions I find are based on nodes that are rectangles/squares, where it's easy to draw a link on the borders (or even the center, but only works for direct links).
But what about nodes that have custom stuff in them that makes them non rectangular, for example a div with border-radius: 50%?
One possible solution is to draw the lines from/to the center of the elements, but that would only work with simple lines, curved lines would look weird.
In this example:
How does arrow position get calculated?
You need to have an container, width and height of the container, then inside the container find the x / y point of the element that you want to connect and draw a line to the next elements x / y point, the x/y points can be calculated using x,y,w,h of the element, for an example x:100 y:100 w:100 h:100 the center point sits at x:150, y:150 x = x + ( w / 2 ), y = y + ( h / 2 ).. using math just calculate the point of connection of the elements, the complexity of math for calculating the connection point is in the shape of the element, for each different shape you need a different calculation metod if not in center
I've been working on this problem for days. I am trying to implement a "free transform" tool for svgs. Similar to that of Raphael.FreeTransform or how you would move/rotate/scale images in MS Word. (Yes, I am aware there are libraries) The following jSFiddle displays my problem: https://jsfiddle.net/hLjvrep7/12/
There are 5 functions in the jsFiddle: rotate-t. shrink-t, grow-t, shrink, grow. The functions suffixed with '-t' also apply the current rotation transformation. e.g.:
grow-t
rect.attr({height : height * 1.25, width : width * 1.25}).transform('r' + degree);
grow
rect.attr({height : height * 1.25, width : width * 1.25});
Once an svg is rotated, then scaled. If you try to rotate the svg again (after scale), the svg jumps. To see this, go top the fiddle:
Hit rotate-t twice. Svg should rotate a total of 30 degrees from the rectangles origin.
Hit grow (not grow-t) twice. Note the top left position of the svg stays the same.
Hit rotate-t once. Note the svg jumps to a different position, then rotates.
Note hitting rotate-t subsequent times will continue to rotate the image around the origin (which is what I want the first time rotate-t is clicked)
One solution I had was to apply the current rotation transformation whenever changing the height and width. This fixes my previous problem, but introduces another problem. To see an example of this, go to the fiddle, and:
Hit rotate-t twice.
Hit grow-t a couple times. Notice the svg grows, but the top left position of the rectangle moves. That's a problem for me. I want the svg to grow without the top left corner to move.
Notes on using the jsFiddle:
Any combination of rotate-t, grow-t, shrink-t will exhibit the ideal rotation behavior (about the origin, no jumping). But this also demonstrates the undesired growing and shrinking (top left position moved when svg is on angle).
Any combination pf rotate-t, grow, shrink will exhibit the ideal scaling behavior (top left corner of svg doesn't move). But this also demonstrates the undesired rotation property (will jump around after different rotations and scales).
Bottom line: I want to be able to the svg rotate around the origin. Then grow the image, while the top left position remains the same. Then rotate the svg again, around the origin without any jumping.
I am aware the how the transform function impacts the local coordinate system of the svg. I'm leaning towards using rotate-t, grow, shrink combo and simply apply some x-y offsets to remove the "jumping" effect. I would imagine there must be some sort of offset I could apply to avoid jumping or shifting during rotation or scaling, but its not clear to me how to calculate such offsets. Any help would be appreciated.
Please don't hesitate to ask anymore questions. Like I said, I've been digging into this for days. Clearly, I don't understand it all, but am somewhat intimate with what's happening and happy to explain anything in more detail.
My solutions for scale, rotate, move back and front etc:
$scope.back = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.prev!=undefined) {
var bot = $scope.currentImage.prev;
$scope.currentImage.insertBefore(bot);
ft.apply();
}
}
};
//Function for moving front
$scope.front = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.next!=undefined) {
var top = $scope.currentImage.next;
if($scope.currentImage.next.node.localName == "image")
$scope.currentImage.insertAfter(top);
ft.apply();
}
}
};
//ZOOM
$scope.zoomIn = function () {
if ($scope.currentImage!= null) {
var ft = paper.freeTransform($scope.currentImage);
if(ft.attrs.scale.y<4) {
$scope.currentImage.toFront();
ft.attrs.scale.y = ft.attrs.scale.y *(1.1);
ft.attrs.scale.x = ft.attrs.scale.x *(1.1);
ft.apply();
ft.updateHandles();
}
}
};
I was creating some visual elements using Fabric js. In my project, the path's were getting updated. But the issue is, the path's measurements were not as expected.
Refrer to jsFiddle
var canvas = new fabric.Canvas('c', {width: 400, height: 400});
var line = new fabric.Path('M,50,50,L,50,150,150,150,150,50,Z', {
fill: 'blue'
});
line.setCoords();
// During update
line.initialize('M,150,50,L,150,150,300,150,300,50,Z')
line.setCoords();
canvas.renderAll();
In the sample the path was initially drawn 50px away from the canvas left border. Then I have changed the path command so that it move's 100px towards the right.
But after updating the path, the shape is actually positioned at 175px away from the left.
Also, the left property of the path element is not changed.
Also, unable to get the idea of all these properties and their relations like,
left, top, scaleX, scaleY, height, width, pathOffset, oCoords, originalState etc in various conditions like the path / canvas is scaled, rotated, moved, placed inside a group etc.
I'm not sure what you are trying to achieve but the initialize method is not an update method but it's the constructor of the class, you are practically overriding the initial object's path.
If your are just trying to move around your original created path you should play with left, top properties of the Path object like in this updated fiddler
I need to do something like this:
This may look quite easy, but there are some requirements:
- the width of the containing div should depend on the text length (is it possible at all in CSS?)
- all circles should be positioned randomly - this is the most diffucult part for me.
As I'm using border-radius for creating circles (setting height, width and border-radius of 50%) I try to create some kind of grid in JavaScript where I iterate through each element and get its dimensions. Then I get the position of previous element (if any) and add them to the current element dimensions. Additionally, adding some margins will help avoid collisions. Is it correct approach?
I'm just looking for a suggestion how to solve my two issues.
Circles that scale based on size of content.
This is something you will need to solve first, because you wont be able to place them anywhere without first knowing their dimensions.
Naturally the size of a DIV expands first by width, then by height. That is, the maximum width of a container must first be utilized before moving on to the height constraint. Because of this, making a circle scale with equal radius may prove to be quite difficult without using a relative averaging.
Relative averaging is finding the average dimensions of your height / width based of the exhisting area of the contianer bounding your content. For example:
The width and height of the DIV bounding your content can be detected with javascript. Let's say youve discovered those properties too be 200px x 20px respectively.
Your total area is width * height so 4000px; But we are trying to acheive a square so we can apply rounded corners and form a rounded circle. We want to find dimensions of a rectangle that will be equal to the same area and then apply those new dimensions.
To acheive the same area with an equal width * height you can do something like:
√ 4000 = 63.2455532
Thus: 63.2455532 x 63.2455532 = 4000
Random placement of DIVs, and avoid collisons between DIVs.
After finding dimensions, you will be able to use a rand on your (X,Y) coordinates for the placement. Push these coordinates and radius onto an array. Use recursion too place the remaining circles on collsion failures. A collision failure would come from an element that has overlapping (X,Y)+radius relative too elements in the array that were pushed successfully.
How can I draw a line between every h2 element on my HTML page so that I can receive the effect in the picture below? Initially, I would presume you would go about this by working out the size of the line required in-between the divs (divs are separated by the 1px horizontal line) + the distance between each of the h2s, but i'm not entirely sure how one could work out this distance.
You can try something like:
a) find the position w.r.t document (i.e. by calling $(element).offset()) of the 2 elements you want to connect, call the positions p1 and p2
b) Append an absolutely positioned canvas to the body with a z-index to ensure it is displayed on top of everything else.
c) Draw a line between p1 and p2 on the canvas
This is assuming the elements can be anywhere on screen. If the line you need to draw is assured to be always horizontal or vertical, it can probably be done in a simpler manner.
Just use offset() method. You can easily find the distance between elements using it.