Layout algorithm in place
This commit is contained in:
parent
7de68f0bf2
commit
8e5e212c49
|
@ -22,6 +22,7 @@
|
|||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
border: 1px solid red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
@ -41,7 +42,7 @@ journey
|
|||
Go downstairs: 5: Me
|
||||
Sit down: 5: Mee
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%;">
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
mindmap
|
||||
root[
|
||||
The root where the things
|
||||
|
@ -50,6 +51,52 @@ mindmap
|
|||
pen!
|
||||
]
|
||||
Child1
|
||||
child2[
|
||||
Child2<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
The second<br/>
|
||||
]
|
||||
Other
|
||||
Child3
|
||||
GrandChild1
|
||||
sc1
|
||||
sc2
|
||||
sc3
|
||||
GrandChild2
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%;">
|
||||
mindmap
|
||||
root[
|
||||
The root where the things
|
||||
happen!
|
||||
]
|
||||
Child2
|
||||
GrandChild1
|
||||
GrandChild2
|
||||
Child3
|
||||
GrandChild3
|
||||
GrandChild4
|
||||
Child4
|
||||
GrandChild5
|
||||
GrandChild6
|
||||
Child1
|
||||
GrandChild1
|
||||
sc1
|
||||
sc2
|
||||
sc3
|
||||
GrandChild2
|
||||
Child5
|
||||
GrandChild7
|
||||
sc1
|
||||
sc2
|
||||
sc3
|
||||
GrandChild7
|
||||
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
pie
|
||||
|
@ -62,7 +109,7 @@ mindmap
|
|||
"Magnesium" : 10.01
|
||||
"Iron" : 5
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%;">
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
gitGraph TB
|
||||
commit
|
||||
commit
|
||||
|
|
|
@ -63,9 +63,11 @@
|
|||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.8",
|
||||
"fast-clone": "^1.5.13",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^2.0.0",
|
||||
"moment-mini": "^2.24.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||
"stylis": "^4.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -112,7 +114,7 @@
|
|||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"resolutions": {
|
||||
"d3": "^7.0.0"
|
||||
},
|
||||
"files": [
|
||||
|
|
|
@ -83,7 +83,6 @@ const detectType = function (text, cnf) {
|
|||
if (cnf && cnf.flowchart && cnf.flowchart.defaultRenderer === 'dagre-wrapper')
|
||||
return 'flowchart-v2';
|
||||
const k = Object.keys(detectors);
|
||||
console.log('here', k);
|
||||
for (let i = 0; i < k.length; i++) {
|
||||
const key = k[i];
|
||||
console.log('Detecting type for', key);
|
||||
|
|
|
@ -85,7 +85,7 @@ describe('when parsing a mindmap ', function () {
|
|||
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('The root');
|
||||
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||
});
|
||||
|
@ -100,7 +100,7 @@ describe('when parsing a mindmap ', function () {
|
|||
expect(mm.children.length).toEqual(1);
|
||||
const child = mm.children[0];
|
||||
expect(child.descr).toEqual('child1');
|
||||
expect(child.id).toEqual('theId');
|
||||
expect(child.nodeId).toEqual('theId');
|
||||
expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
|
||||
});
|
||||
it('should handle an id and type for a node definition', function () {
|
||||
|
@ -114,7 +114,7 @@ root
|
|||
expect(mm.children.length).toEqual(1);
|
||||
const child = mm.children[0];
|
||||
expect(child.descr).toEqual('child1');
|
||||
expect(child.id).toEqual('theId');
|
||||
expect(child.nodeId).toEqual('theId');
|
||||
expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
|
||||
});
|
||||
it('mutiple types (circle)', function () {
|
||||
|
@ -139,7 +139,7 @@ root((the root))
|
|||
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('The root');
|
||||
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||
expect(mm.icon).toEqual('bomb');
|
||||
|
@ -153,7 +153,7 @@ root((the root))
|
|||
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('The root');
|
||||
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||
expect(mm.class).toEqual('m-4 p-8');
|
||||
|
@ -168,7 +168,7 @@ root((the root))
|
|||
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('The root');
|
||||
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||
expect(mm.class).toEqual('m-4 p-8');
|
||||
|
@ -182,7 +182,7 @@ root((the root))
|
|||
`;
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('String containing []');
|
||||
});
|
||||
it('should be possible to use node syntax in the descriptions in children', function () {
|
||||
|
@ -192,7 +192,7 @@ root((the root))
|
|||
`;
|
||||
mindmap.parse(str);
|
||||
const mm = mindmap.yy.getMindmap();
|
||||
expect(mm.id).toEqual('root');
|
||||
expect(mm.nodeId).toEqual('root');
|
||||
expect(mm.descr).toEqual('String containing []');
|
||||
expect(mm.children.length).toEqual(1);
|
||||
expect(mm.children[0].descr).toEqual('String containing ()');
|
||||
|
|
|
@ -5,9 +5,12 @@ var message = '';
|
|||
var info = false;
|
||||
const root = {};
|
||||
let nodes = [];
|
||||
|
||||
let cnt = 0;
|
||||
let elements = {};
|
||||
export const clear = () => {
|
||||
nodes = [];
|
||||
cnt = 0;
|
||||
elements = {};
|
||||
};
|
||||
|
||||
const getParent = function (level) {
|
||||
|
@ -26,7 +29,8 @@ export const getMindmap = () => {
|
|||
};
|
||||
export const addNode = (level, id, descr, type) => {
|
||||
const node = {
|
||||
id: sanitizeText(id),
|
||||
id: cnt++,
|
||||
nodeId: sanitizeText(id),
|
||||
level,
|
||||
descr: sanitizeText(descr),
|
||||
type,
|
||||
|
@ -79,6 +83,11 @@ export const getTypeFromStart = (str) => {
|
|||
return nodeType.DEFAULT;
|
||||
}
|
||||
};
|
||||
|
||||
export const setElementForId = (id, element) => {
|
||||
elements[id] = element;
|
||||
};
|
||||
|
||||
export const decorateNode = (decoration) => {
|
||||
console.log('decorateNode', decoration);
|
||||
const node = nodes[nodes.length - 1];
|
||||
|
@ -96,5 +105,9 @@ export default {
|
|||
nodeType,
|
||||
getTypeFromStart,
|
||||
decorateNode,
|
||||
setElementForId,
|
||||
getElementById: (id) => elements[id],
|
||||
// getNodeById: (id) => nodes.find((node) => node.id === id),
|
||||
getNodeById: (id) => nodes[id],
|
||||
// parseError
|
||||
};
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
import { select } from 'd3';
|
||||
import { log, getConfig, setupGraphViewbox } from '../../diagram-api/diagramAPI';
|
||||
import svgDraw from './svgDraw';
|
||||
|
||||
import { BoundingBox, Layout, Tree } from 'non-layered-tidy-tree-layout';
|
||||
import clone from 'fast-clone';
|
||||
import db from './mindmapDb';
|
||||
/**
|
||||
* @param {any} svg The svg element to draw the diagram onto
|
||||
* @param {object} mindmap The maindmap data and hierarchy
|
||||
|
@ -17,17 +19,181 @@ function drawNodes(svg, mindmap, conf) {
|
|||
}
|
||||
}
|
||||
|
||||
/** @param {any} svg The svg element to draw the diagram onto */
|
||||
function drawEdges() {}
|
||||
|
||||
/**
|
||||
* @param mindmap
|
||||
* @param callback
|
||||
*/
|
||||
function eachNode(mindmap, callback) {
|
||||
callback(mindmap);
|
||||
if (mindmap.children) {
|
||||
mindmap.children.forEach((child) => {
|
||||
eachNode(child, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
/** @param {object} mindmap */
|
||||
function transpose(mindmap) {
|
||||
console.log('transpose', mindmap);
|
||||
eachNode(mindmap, (node) => {
|
||||
// node.y = node.y - (node.y - bb.top) * 2 - node.height;
|
||||
const orgWidth = node.width;
|
||||
const orgX = node.x;
|
||||
node.width = node.height;
|
||||
node.height = orgWidth;
|
||||
node.x = node.y;
|
||||
node.y = orgX;
|
||||
});
|
||||
return mindmap;
|
||||
}
|
||||
/** @param {object} mindmap */
|
||||
function bottomToUp(mindmap) {
|
||||
console.log('bottomToUp', mindmap);
|
||||
eachNode(mindmap.result, (node) => {
|
||||
// node.y = node.y - (node.y - bb.top) * 2 - node.height;
|
||||
node.y = node.y - (node.y - 0) * 2 - node.height;
|
||||
});
|
||||
return mindmap;
|
||||
}
|
||||
/** @param {object} mindmap The mindmap hierarchy */
|
||||
function rightToLeft(mindmap) {
|
||||
console.log('bottomToUp', mindmap);
|
||||
eachNode(mindmap.result, (node) => {
|
||||
// node.y = node.y - (node.y - bb.top) * 2 - node.height;
|
||||
node.x = node.x - (node.x - 0) * 2 - node.width;
|
||||
});
|
||||
return mindmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mindmap
|
||||
* @param dir
|
||||
* @param conf
|
||||
*/
|
||||
function layout(mindmap, dir, conf) {
|
||||
const bb = new BoundingBox(40, 40);
|
||||
|
||||
const layout = new Layout(bb);
|
||||
switch (dir) {
|
||||
case 'TB':
|
||||
return layout.layout(mindmap);
|
||||
case 'BT':
|
||||
return bottomToUp(layout.layout(mindmap));
|
||||
case 'RL': {
|
||||
transpose(mindmap);
|
||||
let newRes = layout.layout(mindmap);
|
||||
transpose(newRes.result);
|
||||
return rightToLeft(newRes);
|
||||
}
|
||||
case 'LR': {
|
||||
transpose(mindmap);
|
||||
let newRes = layout.layout(mindmap);
|
||||
transpose(newRes.result);
|
||||
return newRes;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
const dirFromIndex = (index) => {
|
||||
const dirNum = index % 4;
|
||||
switch (dirNum) {
|
||||
case 0:
|
||||
return 'LR';
|
||||
case 1:
|
||||
return 'RL';
|
||||
case 2:
|
||||
return 'TB';
|
||||
case 3:
|
||||
return 'BT';
|
||||
default:
|
||||
return 'TB';
|
||||
}
|
||||
};
|
||||
|
||||
const mergeTrees = (node, trees) => {
|
||||
node.x = trees[0].result.x;
|
||||
node.y = trees[0].result.y;
|
||||
trees.forEach((tree) => {
|
||||
tree.result.children.forEach((child) => {
|
||||
const dx = node.x - tree.result.x;
|
||||
const dy = node.y - tree.result.y;
|
||||
eachNode(child, (childNode) => {
|
||||
const orgNode = db.getNodeById(childNode.id);
|
||||
if (orgNode) {
|
||||
orgNode.x = childNode.x + dx;
|
||||
orgNode.y = childNode.y + dy;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return node;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @param isRoot
|
||||
* @param parent
|
||||
* @param conf
|
||||
*/
|
||||
function layoutMindmap(node, isRoot) {}
|
||||
function layoutMindmap(node, conf) {
|
||||
// BoundingBox(gap, bottomPadding)
|
||||
// const bb = new BoundingBox(10, 10);
|
||||
// const layout = new Layout(bb);
|
||||
// // const layout = new HorizontalLayout(bb);
|
||||
|
||||
const trees = [];
|
||||
// node.children.forEach((child, index) => {
|
||||
// const tree = clone(node);
|
||||
// tree.children = [tree.children[index]];
|
||||
// trees.push(layout(tree, dirFromIndex(index), conf));
|
||||
// });
|
||||
|
||||
let cnt = 0;
|
||||
// For each direction, create a new tree with the same root, and add a ubset of the children to it.
|
||||
for (let i = 0; i < 4; i++) {
|
||||
// Calculate the number of the children of the root node that will be used in this direction
|
||||
const numChildren =
|
||||
Math.floor(node.children.length / 4) + (node.children.length % 4 > i ? 1 : 0);
|
||||
// Copy the original root node
|
||||
const tree = clone(node);
|
||||
// Setup the new copy with the children to be rendered in this direction
|
||||
tree.children = [];
|
||||
for (let j = 0; j < numChildren; j++) {
|
||||
tree.children.push(node.children[cnt]);
|
||||
cnt++;
|
||||
}
|
||||
if (tree.children.length > 0) {
|
||||
trees.push(layout(tree, dirFromIndex(i), conf));
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the trees into a single tree
|
||||
const result = mergeTrees(node, trees);
|
||||
|
||||
// return layout(node, 'BT', conf);
|
||||
// const res = layout(node, 'BT', conf);
|
||||
// res.result.children = [];
|
||||
// trees.forEach((tree) => {
|
||||
// res.result.children.push(tree.result);
|
||||
// });
|
||||
console.log('Trees', trees);
|
||||
return node;
|
||||
}
|
||||
/**
|
||||
* @param node
|
||||
* @param isRoot
|
||||
* @param conf
|
||||
*/
|
||||
function positionNodes(node, isRoot) {}
|
||||
function positionNodes(node, conf) {
|
||||
svgDraw.positionNode(node, conf);
|
||||
if (node.children) {
|
||||
node.children.forEach((child) => {
|
||||
positionNodes(child, conf);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a an info picture in the tag with id: id based on the graph definition in text.
|
||||
|
@ -63,16 +229,6 @@ export const draw = (text, id, version, diagObj) => {
|
|||
const g = svg.append('g');
|
||||
const mm = diagObj.db.getMindmap();
|
||||
|
||||
// mm.x = 0;
|
||||
// mm.y = 0;
|
||||
// svgDraw.drawNode(g, mm, getConfig());
|
||||
// mm.children.forEach((child) => {
|
||||
// child.x = 200;
|
||||
// child.y = 200;
|
||||
// child.width = 200;
|
||||
// svgDraw.drawNode(g, child, getConfig());
|
||||
// });
|
||||
|
||||
// Draw the graph and start with drawing the nodes without proper position
|
||||
// this gives us the size of the nodes and we can set the positions later
|
||||
|
||||
|
@ -82,12 +238,14 @@ export const draw = (text, id, version, diagObj) => {
|
|||
|
||||
// Next step is to layout the mindmap, giving each node a position
|
||||
|
||||
// layoutMindmap(mm, conf);
|
||||
console.log('Before', mm);
|
||||
const positionedMindmap = layoutMindmap(mm, conf);
|
||||
console.log(positionedMindmap);
|
||||
|
||||
// After this we can draw, first the edges and the then nodes with the correct position
|
||||
// drawEdges(svg, mm, conf);
|
||||
|
||||
// positionNodes(svg, mm, conf);
|
||||
positionNodes(positionedMindmap, conf);
|
||||
|
||||
// Setup the view box and size of the svg element
|
||||
setupGraphViewbox(undefined, svg, conf.mindmap.diagramPadding, conf.mindmap.useMaxWidth);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const lineBreakRegex = /<br\s*\/?>/gi;
|
||||
import { select } from 'd3';
|
||||
import db from './mindmapDb';
|
||||
|
||||
/**
|
||||
* @param {string} text The text to be wrapped
|
||||
* @param {number} width The max width of the text
|
||||
|
@ -88,13 +90,21 @@ export const drawNode = function (elem, node, conf) {
|
|||
.call(wrap, node.width);
|
||||
const bbox = txt.node().getBBox();
|
||||
node.height = bbox.height + conf.fontSize * 1.1 * 0.5;
|
||||
r.attr('height', node.height).attr('y', (-1 * node.height) / 2);
|
||||
r.attr('height', node.height); // .attr('y', (-1 * node.height) / 2);
|
||||
|
||||
txt.attr('transform', 'translate( 0,' + (-1 * node.height) / 2 + ')');
|
||||
// Position the node to its coordinate
|
||||
if (node.x || node.y) {
|
||||
nodeElem.attr('transform', 'translate(' + node.x + ',' + node.y + ')');
|
||||
}
|
||||
db.setElementForId(node.id, nodeElem);
|
||||
return node.height;
|
||||
};
|
||||
export default { drawNode };
|
||||
export const positionNode = function (node, conf) {
|
||||
const nodeElem = db.getElementById(node.id);
|
||||
|
||||
const x = node.x || 0;
|
||||
const y = node.y || 0;
|
||||
// Position the node to its coordinate
|
||||
nodeElem.attr('transform', 'translate(' + x + ',' + y + ')');
|
||||
};
|
||||
export default { drawNode, positionNode };
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -5574,6 +5574,11 @@ extsprintf@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
|
||||
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
|
||||
|
||||
fast-clone@^1.5.13:
|
||||
version "1.5.13"
|
||||
resolved "https://registry.yarnpkg.com/fast-clone/-/fast-clone-1.5.13.tgz#7fe17542ae1c872e71bf80d177d00c11f51c2ea7"
|
||||
integrity sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
|
@ -8663,6 +8668,11 @@ nomnom@1.5.2:
|
|||
chalk "~0.4.0"
|
||||
underscore "~1.6.0"
|
||||
|
||||
non-layered-tidy-tree-layout@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804"
|
||||
integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
|
|
Loading…
Reference in New Issue