Reputation: 15
I am developing Mind mapping tool for android. I am creating this type of layout for my mind map http://www.examtime.com/files/2013/08/How-to-create-an-online-mind-map.jpg. Is there any way to create a these type of lines(as created in image) to connect objects at run time. Please Help
Upvotes: 0
Views: 334
Reputation: 16771
You should look into cubic bezier curves (splines). There is no easy way to do this simply with a Canvas. Here's an overview:
Bezier curves use 2 points (P0 - the origin & P1 - the destination), and 2 vectors (V0 - the direction the curve leaves P0, V1 - the direction the curve enters P1). For our purposes, P0, P1, V0, V1 should all be of the type PointF
.
We will use t to denote the position on the path. When t = 0, the position is at P0, when t = 1, the position is at P1. Any value of t between 0 and 1 will be along the path. 0 <= t <= 1.
Now, just as an example, lets look at the curve that connects the "Nobody's perfect" node to the "Tidy up later" node.
In this case, P0 will be the right middle side of "Nobody's perfect", and P1 will be the bottom middle side of "Tidy up later".
We'll make both vectors perpendicular to the nodes they're leaving / entering, and so V0's value will be {P1.x - P0.x, 0}. This vector will point right, and will have the strength equivalent to the distance between the two nodes. In a similar manner, we'll construct the V1 vector pointing up towards the node: {0, P0.y - P1.y}
Now that you have the vectors and the points, you'll want to start drawing the curve. To do this, you'll iterate through t using some small stepping value that's dividable by 1, for example, 0.1, 0.025, 0.001, etc. Let's call this value "step" Each iteration will generate a point on the curve, and you'll want to connect a line between each of these points.
Here's a code sample for this part:
PointF start, end;
for (float t = 0; t < 1; t += step)
{
start = getBezierPosition(t);
end = getBezierPosition(t + step)
canvas.drawLine(start.x, start.y, end.x, end.y, paint);
}
Now, the hard part - calculating the position of the bezier curve at position t:
private PointF getBezierPosition(float t)
{
PointF result = new PointF();
float oneMinusT, x, y;
oneMinusT = 1 - t;
x = oneMinusT * oneMinusT * oneMinusT * P0.x +
3 * oneMinusT * oneMinusT * t * V0.x +
3 * oneMinusT * t * t * V1.x +
t * t * t * P1.x;
y = oneMinusT * oneMinusT * oneMinusT * P0.y +
3 * oneMinusT * oneMinusT * t * V0.y +
3 * oneMinusT * t * t * V1.y +
t * t * t * P1.y;
result.set(x, y);
return result;
}
This is the formula for a cubic bezier curve. You can learn more about it here.
I'll let you implement the logic of determining the locations of P0 & P1, and the directions of V0 & V1 (keep in mind that they should always be perpendicular to the node they're leaving / entering for best results). You'll need to play around with the logic to determine what side of the node the P is on, and it's most likely going to be linked to the logic you apply to positioning the nodes in the 1st place.
Also, for best results, try playing around with the stroke width of the paint you're drawing with. For example, When t = 0, use a stroke width of size 5, and when t = 1, use a stroke size of 3. Make sure to iterate smoothly between them (so if t = 0.5, the stroke width will be 4).
I'll admit, this stuff is a bit heavy on the mathematics, and might not be in the comfort zone of a beginner, but if you want to achieve dynamic curves like you showed in that picture, I'm afraid you're going to get your hands a bit dirty.
Best of luck man! Let me know how it all turned out :)
Upvotes: 1