@joint/core
Version:
JavaScript diagramming library
188 lines (153 loc) • 4.99 kB
JavaScript
import * as g from '../../g/index.mjs';
import * as util from '../../util/index.mjs';
function portTransformAttrs(point, angle, opt) {
var trans = point.toJSON();
trans.angle = angle || 0;
return util.defaults({}, opt, trans);
}
function lineLayout(ports, p1, p2, elBBox) {
return ports.map(function(port, index, ports) {
var p = this.pointAt(((index + 0.5) / ports.length));
// `dx`,`dy` per port offset option
if (port.dx || port.dy) {
p.offset(port.dx || 0, port.dy || 0);
}
return portTransformAttrs(p.round(), 0, argTransform(elBBox, port));
}, g.line(p1, p2));
}
function ellipseLayout(ports, elBBox, startAngle, stepFn) {
var center = elBBox.center();
var ratio = elBBox.width / elBBox.height;
var p1 = elBBox.topMiddle();
var ellipse = g.Ellipse.fromRect(elBBox);
return ports.map(function(port, index, ports) {
var angle = startAngle + stepFn(index, ports.length);
var p2 = p1.clone()
.rotate(center, -angle)
.scale(ratio, 1, center);
var theta = port.compensateRotation ? -ellipse.tangentTheta(p2) : 0;
// `dx`,`dy` per port offset option
if (port.dx || port.dy) {
p2.offset(port.dx || 0, port.dy || 0);
}
// `dr` delta radius option
if (port.dr) {
p2.move(center, port.dr);
}
return portTransformAttrs(p2.round(), theta, argTransform(elBBox, port));
});
}
function argTransform(bbox, args) {
let { x, y, angle } = args;
if (util.isPercentage(x)) {
x = parseFloat(x) / 100 * bbox.width;
} else if (util.isCalcExpression(x)) {
x = Number(util.evalCalcExpression(x, bbox));
}
if (util.isPercentage(y)) {
y = parseFloat(y) / 100 * bbox.height;
} else if (util.isCalcExpression(y)) {
y = Number(util.evalCalcExpression(y, bbox));
}
return { x, y, angle };
}
// Creates a point stored in arguments
function argPoint(bbox, args) {
const { x, y } = argTransform(bbox, args);
return new g.Point(x || 0, y || 0);
}
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const absolute = function(ports, elBBox) {
return ports.map(port => {
const transformation = argPoint(elBBox, port).round().toJSON();
transformation.angle = port.angle || 0;
return transformation;
});
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const fn = function(ports, elBBox, opt) {
return opt.fn(ports, elBBox, opt);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const line = function(ports, elBBox, opt) {
var start = argPoint(elBBox, opt.start || elBBox.origin());
var end = argPoint(elBBox, opt.end || elBBox.corner());
return lineLayout(ports, start, end, elBBox);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const left = function(ports, elBBox, opt) {
return lineLayout(ports, elBBox.origin(), elBBox.bottomLeft(), elBBox);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const right = function(ports, elBBox, opt) {
return lineLayout(ports, elBBox.topRight(), elBBox.corner(), elBBox);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const top = function(ports, elBBox, opt) {
return lineLayout(ports, elBBox.origin(), elBBox.topRight(), elBBox);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt opt Group options
* @returns {Array<g.Point>}
*/
export const bottom = function(ports, elBBox, opt) {
return lineLayout(ports, elBBox.bottomLeft(), elBBox.corner(), elBBox);
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt Group options
* @returns {Array<g.Point>}
*/
export const ellipseSpread = function(ports, elBBox, opt) {
var startAngle = opt.startAngle || 0;
var stepAngle = opt.step || 360 / ports.length;
return ellipseLayout(ports, elBBox, startAngle, function(index) {
return index * stepAngle;
});
};
/**
* @param {Array<Object>} ports
* @param {g.Rect} elBBox
* @param {Object=} opt Group options
* @returns {Array<g.Point>}
*/
export const ellipse = function(ports, elBBox, opt) {
var startAngle = opt.startAngle || 0;
var stepAngle = opt.step || 20;
return ellipseLayout(ports, elBBox, startAngle, function(index, count) {
return (index + 0.5 - count / 2) * stepAngle;
});
};