diff --git a/README.md b/README.md index 59a3241..625e0ea 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A beautiful, interactive organizational chart editor with YAML input powered by - ⚡ **Fast & Efficient** - Optimized layout algorithms - 🖱️ **Draggable Nodes** - Rearrange nodes by dragging them - 💾 **Position Persistence** - Node positions saved in browser localStorage -- 🔀 **Dual View Modes** - Switch between hierarchical and force-directed graph layouts +- 🔀 **Triple View Modes** - Switch between hierarchical org chart, force-directed graph, and ReactFlow-style layouts ## Getting Started @@ -459,6 +459,26 @@ watch(() => props.data, (newData) => { ``` +## View Modes + +YChart supports three different visualization modes (experimental feature): + +1. **Hierarchical Org Chart** (default) - Traditional tree-based organizational chart using d3-org-chart +2. **Force-Directed Graph** - Physics-based network layout using D3 force simulation +3. **ReactFlow View** - Hierarchical flow chart with directed edges using Cytoscape.js + +To enable view switching, set `experimental: true` in the options: + +```typescript +const ychartEditor = new YChartEditor({ + nodeWidth: 220, + nodeHeight: 110, + experimental: true // Enables view toggle button +}); +``` + +When enabled, a toggle button appears in the toolbar allowing you to cycle through all three views. + ## Browser Support - Chrome/Edge (latest) @@ -474,6 +494,7 @@ MIT Built with: - [d3-org-chart](https://github.com/bumbeishvili/org-chart) by David Bumbeishvili - Org chart visualization - [D3.js](https://d3js.org/) - Data visualization +- [Cytoscape.js](https://js.cytoscape.org/) - Graph theory library for ReactFlow view - [CodeMirror](https://codemirror.net/) - Code editor - [js-yaml](https://github.com/nodeca/js-yaml) - YAML parser diff --git a/dist/ychart-editor.js b/dist/ychart-editor.js index 03b8c42..04a93c0 100644 --- a/dist/ychart-editor.js +++ b/dist/ychart-editor.js @@ -372,9 +372,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy let updated = child.replace(from - pos, to - pos, text); let totalLines = this.lines - child.lines + updated.lines; if (updated.lines < totalLines >> 5 - 1 && updated.lines > totalLines >> 5 + 1) { - let copy = this.children.slice(); - copy[i2] = updated; - return new TextNode(copy, this.length - (to - from) + text.length); + let copy2 = this.children.slice(); + copy2[i2] = updated; + return new TextNode(copy2, this.length - (to - from) + text.length); } return super.replace(pos, end, updated); } @@ -569,13 +569,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy return this; } skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos); - let limit = dir < 0 ? this.pos - this.from : this.to - this.pos; - if (skip > limit) - skip = limit; - limit -= skip; + let limit2 = dir < 0 ? this.pos - this.from : this.to - this.pos; + if (skip > limit2) + skip = limit2; + limit2 -= skip; let { value } = this.cursor.next(skip); this.pos += (value.length + skip) * dir; - this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit); + this.value = value.length <= limit2 ? value : dir < 0 ? value.slice(value.length - limit2) : value.slice(0, limit2); this.done = !this.value; return this; } @@ -1640,9 +1640,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy return changed; } function dynamicFacetSlot(addresses, facet, providers) { - let providerAddrs = providers.map((p) => addresses[p.id]); - let providerTypes = providers.map((p) => p.type); - let dynamic = providerAddrs.filter((p) => !(p & 1)); + let providerAddrs = providers.map((p2) => addresses[p2.id]); + let providerTypes = providers.map((p2) => p2.type); + let dynamic = providerAddrs.filter((p2) => !(p2 & 1)); let idx = addresses[facet.id] >> 1; function get2(state) { let values = []; @@ -1868,24 +1868,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy let providers = facets[id2], facet = providers[0].facet; let oldProviders = oldFacets && oldFacets[id2] || []; if (providers.every( - (p) => p.type == 0 + (p2) => p2.type == 0 /* Provider.Static */ )) { address[facet.id] = staticValues.length << 1 | 1; if (sameArray$1(oldProviders, providers)) { staticValues.push(oldState.facet(facet)); } else { - let value = facet.combine(providers.map((p) => p.value)); + let value = facet.combine(providers.map((p2) => p2.value)); staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value); } } else { - for (let p of providers) { - if (p.type == 0) { - address[p.id] = staticValues.length << 1 | 1; - staticValues.push(p.value); + for (let p2 of providers) { + if (p2.type == 0) { + address[p2.id] = staticValues.length << 1 | 1; + staticValues.push(p2.value); } else { - address[p.id] = dynamicSlots.length << 1; - dynamicSlots.push((a2) => p.dynamicSlot(a2)); + address[p2.id] = dynamicSlots.length << 1; + dynamicSlots.push((a2) => p2.dynamicSlot(a2)); } } address[facet.id] = dynamicSlots.length << 1; @@ -1896,7 +1896,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy return new Configuration(base2, newCompartments, dynamic, address, staticValues, facets); } } - function flatten(extension, compartments, newCompartments) { + function flatten(extension2, compartments, newCompartments) { let result = [[], [], [], [], []]; let seen = /* @__PURE__ */ new Map(); function inner(ext, prec2) { @@ -1937,7 +1937,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy inner(content2, prec2); } } - inner(extension, Prec_.default); + inner(extension2, Prec_.default); return result.reduce((a2, b) => a2.concat(b)); } function ensureAddr(state, addr) { @@ -2142,9 +2142,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy has `"select.pointer"` as user event, `"select"` and `"select.pointer"` will match it. */ - isUserEvent(event) { + isUserEvent(event2) { let e = this.annotation(Transaction.userEvent); - return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == ".")); + return !!(e && (e == event2 || e.length > event2.length && e.slice(0, event2.length) == event2 && e[event2.length] == ".")); } } Transaction.time = /* @__PURE__ */ Annotation.define(); @@ -2253,9 +2253,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy function extendTransaction(tr) { let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr; for (let i2 = extenders.length - 1; i2 >= 0; i2--) { - let extension = extenders[i2](tr); - if (extension && Object.keys(extension).length) - spec = mergeTransaction(spec, resolveTransactionInner(state, extension, tr.changes.newLength), true); + let extension2 = extenders[i2](tr); + if (extension2 && Object.keys(extension2).length) + spec = mergeTransaction(spec, resolveTransactionInner(state, extension2, tr.changes.newLength), true); } return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView); } @@ -3183,18 +3183,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy } } class HeapCursor { - constructor(heap) { - this.heap = heap; + constructor(heap2) { + this.heap = heap2; } static from(sets, skip = null, minPoint = -1) { - let heap = []; + let heap2 = []; for (let i2 = 0; i2 < sets.length; i2++) { for (let cur2 = sets[i2]; !cur2.isEmpty; cur2 = cur2.nextLayer) { if (cur2.maxPoint >= minPoint) - heap.push(new LayerCursor(cur2, skip, minPoint, i2)); + heap2.push(new LayerCursor(cur2, skip, minPoint, i2)); } } - return heap.length == 1 ? heap[0] : new HeapCursor(heap); + return heap2.length == 1 ? heap2[0] : new HeapCursor(heap2); } get startSide() { return this.value ? this.value.startSide : 0; @@ -3232,20 +3232,20 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy } } } - function heapBubble(heap, index2) { - for (let cur2 = heap[index2]; ; ) { + function heapBubble(heap2, index2) { + for (let cur2 = heap2[index2]; ; ) { let childIndex = (index2 << 1) + 1; - if (childIndex >= heap.length) + if (childIndex >= heap2.length) break; - let child = heap[childIndex]; - if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) { - child = heap[childIndex + 1]; + let child = heap2[childIndex]; + if (childIndex + 1 < heap2.length && child.compare(heap2[childIndex + 1]) >= 0) { + child = heap2[childIndex + 1]; childIndex++; } if (cur2.compare(child) < 0) break; - heap[childIndex] = cur2; - heap[index2] = child; + heap2[childIndex] = cur2; + heap2[index2] = child; index2 = childIndex; } } @@ -3509,11 +3509,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy // // If a Content Security Policy nonce is provided, it is added to // the `