feat(org-chart): implement expandable layout and multi-company navigation

Integrate P5-1B through P5-4 shared Core layout, collapse, zoom/pan/fit, company roots and keyboard accessibility. Include React/HTML examples, virtual 20/100/300 employee fixtures, focused checks and the additive data contract.
This commit is contained in:
shkim4 committed 2026-10-12 21:59:09 +09:00
1 parent a92913d6bc
commit 064517ec46
30 files changed
+7532 -183

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
import { createOrgChart, JsonOrgChartDataSource } from './assets/index.js';
const chart = document.getElementById('chart');
const selector = document.getElementById('dataset');
const fieldset = document.getElementById('companies');
const error = document.getElementById('error');
const fixtures = Object.fromEntries(await Promise.all(['small', 'medium', 'large'].map(async size => [size, await (await fetch(`./data-expanded-${size}.json`)).json()])));
const connections = Object.fromEntries(fixtures.large.organizations.map((org, index) => [org.id, ['top', 'left', 'right'][index % 3]]));
const handle = createOrgChart({ container: chart, layoutMode: 'auto', displayMode: 'readOnly', dataSource: new JsonOrgChartDataSource(fixtures.small),
stylesheetUrls: { engine: './assets/engine.css', core: './assets/style.css' }, employeeConnections: connections,
companyTopNodes: { ptc: { title: '기술총괄', name: '가상책임자 5' } },
onStateChange: state => { error.textContent = state.status === 'error' ? '조직도 데이터 또는 스타일을 확인해 주세요.' : ''; } });
// Dev/example ownership only. Filtering is done by the public Core handle.
window.expandedHandle = handle;
async function selection() {
await handle.setSelectedCompanies([...fieldset.querySelectorAll('input:checked')].map(input => input.value));
}
function companies() {
fieldset.querySelectorAll('label').forEach(label => label.remove());
for (const company of fixtures[selector.value].affiliations) {
const label = document.createElement('label'), input = document.createElement('input');
input.type = 'checkbox'; input.checked = true; input.value = company.id;
input.id = `company-${company.id}`; label.htmlFor = input.id;
label.append(input, document.createTextNode(company.name));
input.addEventListener('change', () => { void selection(); }); fieldset.append(label);
}
}
selector.addEventListener('change', async () => {
companies(); await handle.setSelectedCompanies(); await handle.reload(new JsonOrgChartDataSource(fixtures[selector.value]));
});
document.getElementById('all').addEventListener('click', async () => { fieldset.querySelectorAll('input').forEach(input => { input.checked = true; }); await handle.setSelectedCompanies(); });
document.getElementById('none').addEventListener('click', async () => { fieldset.querySelectorAll('input').forEach(input => { input.checked = false; }); await selection(); });
companies(); await handle.mount();
window.addEventListener('pagehide', () => handle.destroy(), { once: true });