- Added a new Archify skill, enabling users to create polished architecture, workflow, sequence, data-flow, and lifecycle diagrams. - Implemented comprehensive functionality including rendering, validation, and delivery of diagrams in various formats. - Integrated a user-friendly command-line interface for generating and previewing diagrams. - Developed supporting files including package.json, LICENSE, and SKILL.md for documentation and licensing. - Added unit tests to ensure reliability and functionality of the new skill. These changes enhance the application by providing a structured approach to visualizing system architecture and workflows, improving user experience and data representation.
50 lines
2.1 KiB
JavaScript
50 lines
2.1 KiB
JavaScript
// Single-line node text fitting, shared by every renderer.
|
|
//
|
|
// Node text (`label`, `sublabel`, `tag`) renders as one <text> element with
|
|
// text-anchor="middle" and is never wrapped. Left unmeasured, an over-long
|
|
// value silently spills across its neighbours while validation still reports
|
|
// a clean receipt — the failure mode this module exists to close.
|
|
//
|
|
// Two halves, always used together:
|
|
// - fittedNodeFontSize shrinks the text toward a legible minimum at render
|
|
// time, so ordinary overruns simply get smaller instead of overlapping.
|
|
// - minimumNodeTextWidth reports the width the text still needs once it has
|
|
// shrunk as far as it may, so validation can reject what shrinking cannot
|
|
// save.
|
|
//
|
|
// The geometry constants below are shared; the per-field `preferred` and
|
|
// `minimum` font sizes are not, because renderers set node text at different
|
|
// sizes (architecture sublabels are 9px, the rest are 7px).
|
|
|
|
import { textUnits } from './utils.mjs';
|
|
|
|
// widthFactor: px of advance width per text unit, per px of font size.
|
|
// horizontalPadding: total px reserved inside the box so text never touches
|
|
// the border.
|
|
export const nodeTextFit = {
|
|
widthFactor: 0.6,
|
|
horizontalPadding: 8,
|
|
};
|
|
|
|
// Largest font size at or below `preferred` that fits `text` inside `width`,
|
|
// floored at `minimum` — below that the text is no longer legible and the
|
|
// caller should be reporting a problem instead.
|
|
export function fittedNodeFontSize(text, width, preferred, minimum) {
|
|
const units = Math.max(1, textUnits(text));
|
|
const available = Math.max(1, width - nodeTextFit.horizontalPadding);
|
|
const fitted = Math.min(preferred, available / (units * nodeTextFit.widthFactor));
|
|
return Math.max(minimum, Math.floor(fitted * 10) / 10);
|
|
}
|
|
|
|
// Width `text` occupies at its legible minimum. Compare against
|
|
// `width - nodeTextFit.horizontalPadding` to decide whether shrink-to-fit can
|
|
// rescue it.
|
|
export function minimumNodeTextWidth(text, minimum) {
|
|
return textUnits(text) * minimum * nodeTextFit.widthFactor;
|
|
}
|
|
|
|
// Available text width inside a box of `width`.
|
|
export function availableNodeTextWidth(width) {
|
|
return width - nodeTextFit.horizontalPadding;
|
|
}
|