From 4586b5b19ca865700181961ac90ab4e89c12021f Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Mon, 23 Dec 2024 00:04:11 +0800 Subject: [PATCH] update --- design/netlist.drawio | 13 ++++++ src/App.vue | 3 +- src/components/render/index.vue | 3 ++ src/hook/jsdoc.js | 7 +++- src/hook/render/index.js | 71 +++++++++++++++++++++++---------- src/hook/render/layout.js | 15 ++++++- 6 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 design/netlist.drawio diff --git a/design/netlist.drawio b/design/netlist.drawio new file mode 100644 index 0000000..788a161 --- /dev/null +++ b/design/netlist.drawio @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 6b5ad66..5906aeb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,6 @@ diff --git a/src/components/render/index.vue b/src/components/render/index.vue index 6dbf925..410222d 100644 --- a/src/components/render/index.vue +++ b/src/components/render/index.vue @@ -17,5 +17,8 @@ defineComponent({ name: 'netlist-render' }); height: 100vh; width: calc(100vw - var(--right-nav-width)); overflow: hidden; + display: flex; + justify-content: center; + align-items: center; } \ No newline at end of file diff --git a/src/hook/jsdoc.js b/src/hook/jsdoc.js index d637569..8aee47f 100644 --- a/src/hook/jsdoc.js +++ b/src/hook/jsdoc.js @@ -148,6 +148,8 @@ /** * @typedef ElkNode * @property {string} id 节点的唯一标识符。 + * @property {string} [renderName] node 展示的名字,布局算法前生成 + * @property {'port' | 'cell' | 'cellPort'} [renderType] 渲染的类型 * @property {ElkNode[]} children 当前节点的内部 * @property {ElkPort[]} ports 当前节点的端口 * @property {ElkEdge[]} edges 当前节点的连线 @@ -188,8 +190,9 @@ /** * @typedef ElkSection - * @property {ElkPoint} startPoint - * @property {ElkPoint} endPoint + * @property {ElkPoint} startPoint 起点 + * @property {ElkPoint} endPoint 终点 + * @property {ElkPoint[]} bendPoints 中间经过的点 * @property {string} id edge 的 id * @property {string} incomingShape source 实体的 id * @property {string} outgoingShape target 实体的 id diff --git a/src/hook/render/index.js b/src/hook/render/index.js index 460d567..74e65d9 100644 --- a/src/hook/render/index.js +++ b/src/hook/render/index.js @@ -25,6 +25,10 @@ export class NetlistRender { */ this.elkGraph = { id: 'root', + layoutOptions: { + 'elk.algorithm': 'layered', + 'layered.nodePlacement.strategy': 'SIDE_BASED' + }, children: [], edges: [] }; @@ -67,10 +71,7 @@ export class NetlistRender { * @returns {Promise} */ async createLayout() { - const elk = new ELK({ - // 分层算法,使得生成的边和坐标轴平行 - algorithm: 'layered' - }); + const elk = new ELK(); const graph = this.elkGraph; const layoutGraph = await elk.layout(graph); console.log(layoutGraph); @@ -93,8 +94,8 @@ export class NetlistRender { // 遍历计算布局进行创建 const svg = d3.select(container).append('svg') - .attr('width', this.renderWidth) - .attr('height', this.renderHeight); + .attr('width', virtualWidth) + .attr('height', virtualHeight); await this.renderEntity(svg, computedLayout, ratio); await this.renderLine(svg, computedLayout, ratio); @@ -116,13 +117,16 @@ export class NetlistRender { // 生成用于绘制的 d3 数据结构 const squares = []; - for (const node of computedLayout.children) { + for (const node of computedLayout.children) { squares.push({ x: node.x, y: node.y, width: node.width, height: node.height, - fill: 'green' + fill: '#2D323B', + text: node.renderName, + rx: 3, + ry: 3 }); // 如果存在 port,绘制 port @@ -132,7 +136,10 @@ export class NetlistRender { y: cellPort.y + node.y, width: cellPort.width, height: cellPort.height, - fill: 'blue' + fill: '#CB81DA', + text: '', + rx: 0, + ry: 0 }); } } @@ -146,8 +153,23 @@ export class NetlistRender { .attr('width', data => data.width) .attr('height', data => data.height) .attr('fill', d => d.fill) - .attr('stroke', 'white') - .attr('stroke-width', 2); + .attr('stroke', '#CB81DA') + .attr('stroke-width', 2) + .attr('rx', d => d.rx) + .attr('ry', d => d.ry); + + + svg.selectAll('text') + .data(squares) + .enter() + .append('text') + .attr('x', data => data.x + data.width / 2) // 文本的 x 坐标(居中) + .attr('y', data => data.y + data.height / 2) // 文本的 y 坐标(居中) + .attr('dominant-baseline', 'middle') // 文本垂直居中 + .attr('text-anchor', 'middle') // 文本水平居中 + .attr('fill', 'white') // 文本颜色 + .attr('font-size', '12px') + .text(data => data.text); // 设置文本内容 } /** @@ -160,14 +182,23 @@ export class NetlistRender { const lines = []; for (const edge of computedLayout.edges) { for (const section of edge.sections || []) { - lines.push({ - x1: section.startPoint.x, - y1: section.startPoint.y, - x2: section.endPoint.x, - y2: section.endPoint.y, - strokeWidth: 2, - color: 'white' - }); + const points = []; + points.push(section.startPoint); + for (const point of section.bendPoints || []) { + points.push(point); + } + points.push(section.endPoint); + + for (let i = 0; i < points.length - 1; ++ i) { + lines.push({ + x1: points[i].x, + y1: points[i].y, + x2: points[i + 1].x, + y2: points[i + 1].y, + strokeWidth: 2, + color: 'var(--foreground)' + }); + } } } @@ -180,6 +211,6 @@ export class NetlistRender { .attr('x2', data => data.x2) .attr('y2', data => data.y2) .attr('stroke-width', data => data.strokeWidth) - .attr('stroke', data => data.color) + .attr('stroke', data => data.color); } } \ No newline at end of file diff --git a/src/hook/render/layout.js b/src/hook/render/layout.js index 9d246fe..a4133fb 100644 --- a/src/hook/render/layout.js +++ b/src/hook/render/layout.js @@ -6,7 +6,7 @@ import { CELL_LIBS, ModuleTree } from "./yosys"; export const LAYOUT_CONSTANT = { PORT_WIDTH: 50, - PORT_HEIGHT: 50, + PORT_HEIGHT: 20, INSTANTIATION_WIDTH: 50, INSTANTIATION_HEIGHT: 50, CONSTANT_WIDTH: 50, @@ -67,11 +67,19 @@ export class Module { // 绘制 ports for (const name of this.moduleTree.nameToPort.keys()) { const port = this.moduleTree.nameToPort.get(name); + + const direction = port.direction === 'input' ? 'LEFT': 'RIGHT'; const node = { id: port.id, + renderName: name, + renderType: 'port', + type: port.direction, width: LAYOUT_CONSTANT.PORT_WIDTH, height: LAYOUT_CONSTANT.PORT_HEIGHT, + properties: { + 'elk.layered.nodePlacement.side': direction + } }; nodes.push(node); @@ -103,6 +111,8 @@ export class Module { const portSide = connection.direction === 'input' ? ELK_DIRECTION.LEFT: ELK_DIRECTION.RIGHT; ports.push({ id: connection.id, + renderName: connectionName, + renderType: 'cellPort', width: LAYOUT_CONSTANT.CELL_PORT_WIDTH, height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT, properties: { @@ -113,6 +123,8 @@ export class Module { const node = { id: cell.id, + renderName: cell.type, + renderType: 'cell', width, height, ports, @@ -156,6 +168,7 @@ export class Module { // 如果是常数,需要先创建代表常数的节点,常数一定是器件的输入,而非输出 const node = { id, + name: wireId, width: LAYOUT_CONSTANT.CONSTANT_WIDTH, height: LAYOUT_CONSTANT.CONSTANT_HEIGHT, layoutOptions: {