d3-force-limit
Version:
A positioning hard limit force type for the d3-force simulation engine.
138 lines (129 loc) • 4.68 kB
JavaScript
// Version 1.2.2 d3-force-limit - https://github.com/vasturiano/d3-force-limit
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
})(this, (function (exports) { 'use strict';
function constant (x) {
return function () {
return x;
};
}
function limit () {
var nDim,
nodes,
radius = function radius(node) {
return 1;
},
// accessor: number > 0
x0 = function x0(node) {
return -Infinity;
},
// accessor: min X
x1 = function x1(node) {
return Infinity;
},
// accessor: max X
y0 = function y0(node) {
return -Infinity;
},
// accessor: min Y
y1 = function y1(node) {
return Infinity;
},
// accessor: max Y
z0 = function z0(node) {
return -Infinity;
},
// accessor: min z
z1 = function z1(node) {
return Infinity;
},
// accessor: max z
cushionWidth = 0,
// width of the cushion layer that pushes nodes away from boundaries
cushionStrength = 0.01; // intensity of the cushion layer that pushes nodes away from boundaries, in terms of px/tick^2
function force(alpha) {
nodes.forEach(function (node) {
var r = radius(node);
['x', 'y', 'z'].slice(0, nDim).forEach(function (coord) {
if (!(coord in node)) {
return;
}
var range = {
x: [x0, x1],
y: [y0, y1],
z: [z0, z1]
}[coord].map(function (accessFn) {
return accessFn(node);
}).sort(function (a, b) {
return a - b;
});
// take node radius into account
range[0] += r;
range[1] -= r;
var vAttr = "v".concat(coord);
var v = node[vAttr];
var pos = node[coord];
var futurePos = pos + v;
if (futurePos < range[0] || futurePos > range[1]) {
// future position out of bounds
var isBefore = futurePos < range[0];
if (pos < range[0] || pos > range[1]) {
// already out of bounds
if (isBefore === v < 0) {
node[vAttr] = 0; // moving outwards, stop its motion
}
node[coord] = range[isBefore ? 0 : 1]; // move it to the closest edge
} else {
node[vAttr] = range[isBefore ? 0 : 1] - pos; // will cross the limit, slow it down
}
}
if (cushionWidth > 0 && cushionStrength > 0) {
// repel from boundaries
node[vAttr] += (Math.max(0, 1 - Math.max(0, pos - range[0]) / cushionWidth) - Math.max(0, 1 - Math.max(0, range[1] - pos) / cushionWidth)) * cushionStrength * alpha;
}
});
});
}
force.initialize = function (initNodes) {
nodes = initNodes;
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
nDim = args.find(function (arg) {
return [1, 2, 3].includes(arg);
}) || 2;
};
force.radius = function (_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), force) : radius;
};
force.x0 = function (_) {
return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), force) : x0;
};
force.x1 = function (_) {
return arguments.length ? (x1 = typeof _ === "function" ? _ : constant(+_), force) : x1;
};
force.y0 = function (_) {
return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), force) : y0;
};
force.y1 = function (_) {
return arguments.length ? (y1 = typeof _ === "function" ? _ : constant(+_), force) : y1;
};
force.z0 = function (_) {
return arguments.length ? (z0 = typeof _ === "function" ? _ : constant(+_), force) : z0;
};
force.z1 = function (_) {
return arguments.length ? (z1 = typeof _ === "function" ? _ : constant(+_), force) : z1;
};
force.cushionWidth = function (_) {
return arguments.length ? (cushionWidth = _, force) : cushionWidth;
};
force.cushionStrength = function (_) {
return arguments.length ? (cushionStrength = _, force) : cushionStrength;
};
return force;
}
exports.forceLimit = limit;
}));
//# sourceMappingURL=d3-force-limit.js.map