feat(org-chart): finalize chart features and AI generation rules
This commit is contained in:
1 parent
7614507583
commit
d0828a7ff4
80 files changed
+8152
-221
No files matched your search
@@ -0,0 +1,58 @@
|
||||
/** Story-only alignment of the entire transformed Workdesk stage in the visible
|
||||
* Content Wrapper's content box. Core retains its proportional width/height fit. */
|
||||
export function centerCompositionPreview(host: HTMLElement): () => void {
|
||||
let frame: number | undefined;
|
||||
let shadow: ShadowRoot | undefined;
|
||||
let stage: HTMLElement | undefined;
|
||||
const schedule = () => { frame ??= requestAnimationFrame(align); };
|
||||
const resize = new ResizeObserver(schedule);
|
||||
const mutation = new MutationObserver(schedule);
|
||||
const outer = new MutationObserver(schedule);
|
||||
const align = () => {
|
||||
frame = undefined;
|
||||
const nextShadow = host.querySelector('.hm-orgchart-host')?.shadowRoot;
|
||||
if (!nextShadow) return;
|
||||
if (shadow !== nextShadow) {
|
||||
mutation.disconnect();
|
||||
shadow = nextShadow;
|
||||
mutation.observe(shadow, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'data-layout'] });
|
||||
}
|
||||
const wrapper = shadow.querySelector<HTMLElement>('.hm-orgchart-composition');
|
||||
const nextStage = shadow.querySelector<HTMLElement>('.hm-orgchart-stage[data-workdesk-artwork]');
|
||||
if (!wrapper || !nextStage) return;
|
||||
if (stage !== nextStage) {
|
||||
if (stage) resize.unobserve(stage);
|
||||
stage = nextStage;
|
||||
resize.observe(stage);
|
||||
}
|
||||
const container = host.getBoundingClientRect();
|
||||
const css = getComputedStyle(host);
|
||||
const inset = (key: 'borderLeftWidth' | 'borderRightWidth' | 'paddingLeft' | 'paddingRight') => parseFloat(css[key]) || 0;
|
||||
const left = container.left + inset('borderLeftWidth') + inset('paddingLeft');
|
||||
const right = container.right - inset('borderRightWidth') - inset('paddingRight');
|
||||
const bounds = stage.getBoundingClientRect();
|
||||
if (right <= left || !bounds.width) return;
|
||||
// The stage keeps its unscaled layout width, so centering that width with
|
||||
// flex/grid would misplace Core's transformed rectangle. Measure the actual
|
||||
// rendered rectangle instead; translate it as one unit without changing the
|
||||
// transform, scale, 1920 x 914.5 canvas or any stage-relative coordinates.
|
||||
const difference = (left + right - bounds.left - bounds.right) / 2;
|
||||
// Fractional proportional scales can alternate the rounded correction by
|
||||
// 0.0001px. Keep the same content-box calculation without a feedback loop.
|
||||
if (Math.abs(difference) < 0.001) return;
|
||||
const translation = `${Number(((parseFloat(stage.style.translate) || 0) + difference).toFixed(4))}px`;
|
||||
if (stage.style.translate !== translation) stage.style.translate = translation;
|
||||
};
|
||||
resize.observe(host);
|
||||
// A padding redistribution can move the content center without resizing it.
|
||||
outer.observe(host, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
||||
window.addEventListener('resize', schedule);
|
||||
document.fonts.addEventListener('loadingdone', schedule);
|
||||
schedule();
|
||||
return () => {
|
||||
resize.disconnect(); mutation.disconnect(); outer.disconnect();
|
||||
window.removeEventListener('resize', schedule);
|
||||
document.fonts.removeEventListener('loadingdone', schedule);
|
||||
if (frame !== undefined) cancelAnimationFrame(frame);
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user