diff --git a/demo/src/assets/resources.js b/demo/src/assets/resources.js
index 4aabb66b..257d711b 100644
--- a/demo/src/assets/resources.js
+++ b/demo/src/assets/resources.js
@@ -56,7 +56,7 @@ export default {
{% if hasError %}
-
+
`,
},
diff --git a/src/draw/DefaultDrawer.js b/src/draw/DefaultDrawer.js
index 6b467986..cc0dea08 100644
--- a/src/draw/DefaultDrawer.js
+++ b/src/draw/DefaultDrawer.js
@@ -1,5 +1,5 @@
import * as d3 from 'd3';
-import ElkLayout from './ElkLayout';
+import ElkLayout from './layout/ElkLayout';
import ComponentRenderer from './render/ComponentRenderer';
/**
@@ -11,20 +11,41 @@ class DefaultDrawer {
* @param {DefaultData} pluginData - Plugin data storage.
* @param {object} [resources] - Object that contains resources.
* @param {string} [viewPortId] - Id of HTML element where we want to draw.
+ * @param option
*/
- constructor(pluginData, resources = null, viewPortId = 'view-port') {
+ constructor(pluginData, resources = null, viewPortId = 'view-port', option = {
+ padding: 10,
+ gap: 50,
+ }) {
/**
* Plugin data storage.
* @type {DefaultData}
*/
this.pluginData = pluginData;
+ /**
+ * Component renderer.
+ */
+ this.componentRenderer = new ComponentRenderer({ padding: option.padding });
+
/**
* Plugin layout system.
* @type {DefaultLayout}
* @default new ElkLayout()
*/
- this.layout = new ElkLayout(this.pluginData);
+ this.layout = new ElkLayout(
+ this.pluginData,
+ { componentRenderer: this.componentRenderer },
+ {
+ 'elk.padding': `[
+ left=${option.padding},
+ top=${option.padding},
+ right=${option.padding},
+ bottom=${option.padding}
+ ]`,
+ 'elk.layered.spacing.baseValue': option.gap,
+ },
+ );
/**
* Object that contains resources.
@@ -51,11 +72,6 @@ class DefaultDrawer {
* @type {Selection}
*/
this.root = null;
-
- /**
- * Component renderer.
- */
- this.componentRenderer = new ComponentRenderer();
}
/**
@@ -80,28 +96,6 @@ class DefaultDrawer {
this.componentRenderer.resources = this.resources;
}
- automaticLayout() {
- // TODO: implement automatic layout
- // first step: sort components by depth (decrescent)
- // like this [[depth: 3, depth: 3], [depth: 2, depth: 2], [depth: 1, depth: 1]]
- // second step: automatic layout for the deepest components
- // third step: filter the components of the previous depth - 1
- // to keep the container with children
- // four step: set the width and height of these container components
-
- const containerGroups = this.groupNodesByDepth().map((group) => (
- group.filter((d) => d.data.definition.isContainer && !!d.children)
- ));
-
- containerGroups.forEach((group) => {
- group.each((d) => {
- // TODO: autolayout its children
-
- this.componentRenderer.setAutomaticlyContainerSize(d.data.id);
- });
- });
- }
-
groupNodesByDepth() {
const nodes = d3.selectAll('.component');
const maxDepth = d3.max(nodes.data(), (d) => d.depth);
@@ -121,7 +115,6 @@ class DefaultDrawer {
draw() {
this.__drawingComponents();
this.registerComponentsDrawOption();
- this.automaticLayout();
}
/**
@@ -215,8 +208,6 @@ class DefaultDrawer {
const position = this.getNodePosition(component.id);
const size = this.getNodeSize(component.id);
- console.log(position, size);
-
component.drawOption.x = position.x;
component.drawOption.y = position.y;
component.drawOption.width = size.width;
diff --git a/src/draw/DefaultLayout.js b/src/draw/layout/DefaultLayout.js
similarity index 100%
rename from src/draw/DefaultLayout.js
rename to src/draw/layout/DefaultLayout.js
diff --git a/src/draw/ElkLayout.js b/src/draw/layout/ElkLayout.js
similarity index 94%
rename from src/draw/ElkLayout.js
rename to src/draw/layout/ElkLayout.js
index 5a298b43..9d0a46a3 100644
--- a/src/draw/ElkLayout.js
+++ b/src/draw/layout/ElkLayout.js
@@ -101,10 +101,11 @@ class ElkLayout extends DefaultLayout {
/**
* Initializes ELK parameters and inherited fields.
* @param {DefaultData} pluginData - A graph to be arranged.
+ * @param {object} [renderer] - Renderer for the components. (use defaults if unsure)
* @param {object} [elkParams] - Parameters for the layout algorithm. (use defaults if unsure)
* @see Parameters for ELK: {@link https://eclipse.dev/elk/reference/options.html}
*/
- constructor(pluginData, elkParams = {}) {
+ constructor(pluginData, renderer = {}, elkParams = {}) {
super(pluginData);
/**
@@ -114,7 +115,6 @@ class ElkLayout extends DefaultLayout {
this.elkParams = {
// default parameters
'elk.algorithm': 'elk.layered',
- 'spacing.baseValue': '50',
separateConnectedComponents: 'true',
'elk.layered.cycleBreaking.strategy': 'INTERACTIVE',
'elk.layered.layering.strategy': 'INTERACTIVE',
@@ -126,6 +126,11 @@ class ElkLayout extends DefaultLayout {
...elkParams,
};
+
+ this.renderer = {
+ componentRenderer: null,
+ ...renderer,
+ };
}
/**
@@ -158,10 +163,7 @@ class ElkLayout extends DefaultLayout {
// For each parent, from the deepest nodes up to the root, get a layout for its children.
return Promise.all(
- this.getParentsByDepth(nodes)
- .map(
- (node) => this.generateELKLayout(node, nodes, links),
- ),
+ this.getParentsByDepth(nodes).map((node) => this.generateELKLayout(node, nodes, links)),
);
}
@@ -171,7 +173,9 @@ class ElkLayout extends DefaultLayout {
* @private
*/
writeLayout(layout) {
- layout.forEach((elkNode) => this.writeSingleDepthLayout(elkNode));
+ layout.forEach((elkNode) => {
+ this.writeSingleDepthLayout(elkNode);
+ });
}
/**
@@ -273,7 +277,15 @@ class ElkLayout extends DefaultLayout {
}));
// Finally calling ELK.
- return ElkLayout.elk.layout(graph);
+ const layout = await ElkLayout.elk.layout(graph);
+
+ this.writeSingleDepthLayout(layout);
+ this.renderer.componentRenderer.render(layout.id);
+ if (layout.id !== 'root') {
+ this.renderer.componentRenderer.setAutomaticlyContainerSize(layout.id);
+ }
+
+ return layout;
}
/**
@@ -282,7 +294,6 @@ class ElkLayout extends DefaultLayout {
* @private
*/
writeSingleDepthLayout(elkNode) {
- console.log('elkNode: ', elkNode);
const nodes = new Map(elkNode.children
.map((node) => [node.id, {
x: node.x,
@@ -297,8 +308,6 @@ class ElkLayout extends DefaultLayout {
component.drawOption.x = x;
component.drawOption.y = y;
});
-
-
}
/**
diff --git a/src/draw/render/ComponentRenderer.js b/src/draw/render/ComponentRenderer.js
index 686cc041..00b4ddce 100644
--- a/src/draw/render/ComponentRenderer.js
+++ b/src/draw/render/ComponentRenderer.js
@@ -74,16 +74,18 @@ class ComponentRenderer {
/**
* Create nodes.
* @param {string} contextId - Id of current context.
+ * @param {number} [depth] - Depth of current context.
* @private
*/
render(contextId = this.drawingContextId) {
const context = d3.select(`#${contextId}`);
- context.select('.components').selectAll('.component')
+ context.select('.components').selectAll(`.component[depth="${context.datum().depth + 1}"]`)
.data(({ children }) => children)
.join('g')
.attr('id', ({ data }) => data.id)
.attr('class', 'component')
+ .attr('depth', (data) => data.depth)
.html(({ data }) => this.renderModel(data))
.filter(({ data, children }) => data.definition.isContainer && !(!children))
.each(({ data }) => this.render(data.id));
@@ -91,7 +93,6 @@ class ComponentRenderer {
setAutomaticlyContainerSize(nodeId) {
const node = d3.select(`#${nodeId}`);
-
const { width, height } = node.select('.components').node().getBoundingClientRect();
node.datum().data.drawOption.innerWidth = width;