There are a couple things you can do shorthand that do not require an entire physics solver.
See example.
https://youtu.be/UDkccb5fRwY
The only real code in the solver for a distance joint is to propagate the change. What you need to do is find the current distance of that object, assume the object is pulled and figure where it's new position should be. Then figure the pull of that change and propagate it down the line.
My code for the example is:
public void tugEvent(LayerIndex index, double toX, double toY) {
double newX, newY;
int posPost;
if (index == null) return;
if (!index.isValid()) return;
PointSeries points = index.getLayer().getPointSeries();
newX = toX;
newY = toY;
posPost = index.pointIndex;
for (int pose = points.size() - 1; posPost < pose; posPost++) {
Point c = points.getPoint(posPost);
Point n = points.getPoint(posPost + 1);
double originalDistance = Geometry2D.distance(c.getX(), c.getY(), n.getX(), n.getY());
invalidate((float) c.getX(), (float) c.getY());
if (posPost != index.pointIndex) {
c.setLocation(newX, newY);
}
double newDistance = Geometry2D.distance(newX, newY, n.getX(), n.getY());
double direction = Geometry2D.angleR(n.getX(), n.getY(), newX, newY);
double difference = newDistance - originalDistance;
if (Math.abs(difference) <= 0.1d) {
break;
}
newX = n.getX() + (Math.cos(direction) * difference);
newY = n.getY() + (Math.sin(direction) * difference);
if (posPost + 1 >= pose) {
n.setLocation(newX, newY);
break;
}
}
newX = toX;
newY = toY;
int posPrior;
posPrior = index.pointIndex;
for (int pose = 0; posPrior > pose; posPrior--) {
Point c = points.getPoint(posPrior);
Point n = points.getPoint(posPrior - 1);
double originalDistance = Geometry2D.distance(c.getX(), c.getY(), n.getX(), n.getY());
if (posPrior != index.pointIndex) {
c.setLocation(newX, newY);
}
double newDistance = Geometry2D.distance(newX, newY, n.getX(), n.getY());
double direction = Geometry2D.angleR(n.getX(), n.getY(), newX, newY);
double difference = newDistance - originalDistance;
if (Math.abs(difference) <= 0.1d) {
break;
}
newX = n.getX() + (Math.cos(direction) * difference);
newY = n.getY() + (Math.sin(direction) * difference);
if (posPrior - 1 <= 0) {
n.setLocation(newX, newY);
break;
}
}
invalidateRange(index.getLayer().getPointSeries(), posPrior, posPost);
}
It does it in both directions (hence the duplicate code block, but descending) so I can pull any point and abort when it gets a pull below a certain threshold. That's all you actually need. How does the change in location tug the next point down the line, and when you apply that vector to it, calculate it for the next attached values.